我正在使用Josh Close优秀的CsvHelper库来读取csv文件并使用实体框架将它们加载到数据库中。这一切都很好,除了一件事; CsvReader在csv文件中将空字符串存储为数据库中的空字符串,我希望这是一个NULL值。所以我所做的就是创建一个自定义转换器来处理这个问题:
public class NullStringConverter : StringConverter
{
public override object ConvertFromString(TypeConverterOptions options, string text)
{
if (string.IsNullOrEmpty(text))
return null;
else
return base.ConvertFromString(options, text);
}
}
我可以使用流畅的地图语法或通过属性将其应用于字符串属性,现在它将插入NULL而不是空字符串。
由于我有很多包含许多字符串属性的类,所以我希望避免为每个人和每个人创建Map语句。我创建了一个通用的Map类,它枚举所有属性并将自定义转换器应用于所有字符串属性。这就是我所熟悉的
public class DefaultStringMap<TEntity> : CsvClassMap<TEntity> where TEntity : AbstractAmtSourceEntity
{
public DefaultStringMap()
{
typeof(TEntity).GetProperties()
.Where(p => p.PropertyType == typeof(string))
.ToList()
.ForEach(p => Map(m => p.Name).TypeConverter<NullStringConverter>());
}
}
这里AbstractAmtSourceEntity
是我所有实体类的基类。这是我的读者类实际获取数据:
public static void Read<TEntity>(TextReader reader, AmtSourceModel context) where TEntity : AbstractAmtSourceEntity
{
using (var csvReader = new CsvReader(reader))
{
csvReader.Configuration.WillThrowOnMissingField = false;
csvReader.Configuration.Delimiter = "|";
csvReader.Configuration.SkipEmptyRecords = true;
csvReader.Configuration.RegisterClassMap<DefaultStringMap<Entity1>>();
csvReader.Configuration.RegisterClassMap<DefaultStringMap<Entity2>>();
etc...
csvReader.Configuration.IgnoreReadingExceptions = true;
csvReader.Configuration.ReadingExceptionCallback = (ex, row) =>
{
_log.Warn($"Exception caught reading row {row}", ex);
_log.Debug($"Exception detail: {ex.Data["CsvHelper"]}");
};
var records = csvReader.GetRecords<TEntity>();
context.Set<TEntity>().AddRange(records);
context.SaveChanges();
}
}
但这不起作用,映射没有应用,所以很明显我错过了一些东西。谁能告诉我这里缺少什么?
答案 0 :(得分:3)
您可以全局设置转换器。
TypeConverterFactory.AddConverter( typeof( string ), new NullStringConverter() );
// or
TypeConverterFactory.AddConverter<string>( new NullStringConverter() );