В настоящее время я тестирую Entity Framework Core 2.1 с целью его использования в компании, в которой я работаю, для бизнес-приложений.У меня большая часть возможностей по внедрению преобразователей значений в моем тестовом проекте, но моя существующая база знаний подвела меня к последнему препятствию!
Что я пытаюсь сделать
Мойпонимание состоит в том, что для значений перечисления встроенные преобразователи типов могут преобразовывать из значения перечисления в строковый эквивалент (EnumToStringConverter) или из значения перечисления в его числовое представление (EnumToNumberConverter).Однако мы используем пользовательское строковое значение для представления перечисления в нашей базе данных, поэтому я написал собственный EnumToDbStringEquivalentConvertor для этого преобразования, и строковое значение базы данных указано в качестве атрибута для каждого из значений перечисления в моей модели.
Код выглядит следующим образом:
Модель
public class User
{
[Key] public int ID { get; set; }
public EmployeeType EmployeeType { get; set; }
}
public enum EmployeeType
{
[EnumDbStringValue("D")]
Director,
[EnumDbStringValue("W")]
Weekly,
[EnumDbStringValue("S")]
Salaried
}
DataContext
public class MyDataContext : DbContext
{
public DbSet<User> Users { get; set; }
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType.IsEnum)
{
property.SetValueConverter(new EnumToDbStringEquivalentConvertor<EmployeeType>());
}
}
}
}
}
ЗначениеКонвертер
public class EnumToDbStringEquivalentConvertor<T> : ValueConverter<T, string>
{
public EnumToDbStringEquivalentConvertor(ConverterMappingHints mappingHints = null) : base(convertToProviderExpression, convertFromProviderExpression, mappingHints)
{ }
private static Expression<Func<T, string>> convertToProviderExpression = x => ToDbString(x);
private static Expression<Func<string, T>> convertFromProviderExpression = x => ToEnum<T>(x);
public static string ToDbString<TEnum>(TEnum tEnum)
{
var enumType = tEnum.GetType();
var enumTypeMemberInfo = enumType.GetMember(tEnum.ToString());
EnumDbStringValueAttribute enumDbStringValueAttribute = (EnumDbStringValueAttribute)enumTypeMemberInfo[0]
.GetCustomAttributes(typeof(EnumDbStringValueAttribute), false)
.FirstOrDefault();
return enumDbStringValueAttribute.StringValue;
}
public static TEnum ToEnum<TEnum>(string stringValue)
{
// Code not included for brevity
}
}
Этот код (я рад сообщить), кажется, работает без проблем.
Моя проблема
Документация по преобразователям значенийкажется, предлагает способ, которым мы назначаем их в методе OnModelCreating, чтобы физически назначить каждый отдельный преобразователь типа каждому отдельному свойству в модели.Я не хочу этого делать - я хочу, чтобы моя модель была водителем.Я реализую это позже, но пока, в текущей версии кода, я перебираю типы сущностей в моей модели, проверяя значение свойства IsEnum и затем назначая преобразователь значения в этой точке.
Моя проблема в том, что метод расширения SetValueConverter, который я использую, требует от меня передать ему новый экземпляр EnumToDbStringEquivalentConvertor, который в моем примере жестко запрограммирован как EnumToDbStringEquivalentConvertor, который работает.Однако я не хочу, чтобы это было жестко закодировано - я хочу передать тип сущности ClrType.
Ранее я использовал отражение для создания универсальных типов и универсальных методов, но не могу найти правильный код длязаставить это работать.
Это:
public class MyDataContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType.IsEnum)
{
var converterType = typeof(EnumToDbStringEquivalentConvertor<>);
var genericConverterType = converterType.MakeGenericType(property.ClrType);
MethodInfo setValueConverterMethodInfo = typeof(MutablePropertyExtensions).GetMethod("SetValueConverter");
setValueConverterMethodInfo.Invoke(property,
new object[] { property, Activator.CreateInstance(genericConverterType) });
}
}
}
}
}
выдает мне сообщение об ошибке « System.MissingMethodException :« Не определен конструктор без параметров для этого объекта. »наМетод GetModel в Microsoft.EntityFrameworkCore.Infrastructure
Так что мой вопрос: может ли кто-нибудь посоветовать мне, как я могу передать свой преобразователь значений в общем случае в метод SetValueConveter EF Core?
Заранее спасибо заваша помощь.