【发布时间】:2019-03-28 19:46:26
【问题描述】:
我目前正在试用 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
}
数据上下文
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)
{
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) });
}
}
}
}
}
在 Microsoft.EntityFrameworkCore.Infrastructure 中的 GetModel 方法上给我一个错误“System.MissingMethodException: 'No parameterless constructor defined for this object.'”
所以我的问题是谁能告诉我如何将我的值转换器一般地传递给 EF Core 的“SetValueConveter”方法?
提前感谢您的帮助。
【问题讨论】:
-
Aww,我本可以使用您省略的“public static TEnum ToEnum
(string stringValue) {}”类的实现。当我对反射没有多少经验时,事实证明,根据字符串找到正确的枚举值很棘手。
标签: c# entity-framework-core ef-core-2.1