Я использую отличную библиотеку CsvHelper Джоша Клоуз для чтения файлов csv и загрузки их в базу данных с помощью entity framework. Все это работает хорошо, за исключением одного; 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();
}
}
Однако это не работает, сопоставление не применяется, поэтому, очевидно, я чего-то упускаю. Кто-нибудь может сказать мне, чего здесь не хватает?