【问题标题】:EntityFrameworkCore is there a way to create EnumToStringConverter without passing the enum type as generic?EntityFrameworkCore 有没有一种方法可以创建 EnumToStringConverter 而无需将枚举类型作为泛型传递?
【发布时间】:2018-06-15 17:26:18
【问题描述】:

我正在尝试使用EntityFrameworkCore ORM 与我的数据库进行交互。默认情况下,EntityFrameworkCore 似乎将枚举存储为 int 而不是字符串。

但是,我想将该值作为字符串存储在数据库中。我可以看到 EntityFrameworkCore 附带一个名为 EnumToStringConverter 的转换器。

我正在尝试使用反射来设置模型构建器,因此我不必手动构建每个模型。

我遇到的问题是EnumToStringConverter 接受必须是enum 的泛型类型。但是由于我在这里尝试使用反射,所以在创建转换器时无法传递枚举类型

这是我的代码到目前为止的样子

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // Get all DbSet<> properties that are defined in the DbContext
    var modelTypes = typeof(DataContext).GetProperties()
                                        .Where(x => x.PropertyType.IsGenericType && x.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
                                        .Select(x => x.PropertyType.GetGenericArguments().First())
                                        .ToList();

    foreach (Type modelType in modelTypes)
    {
        var properties = modelType.GetProperties();

        foreach (var property in properties)
        {
            if (IsPrimaryKey(property))
            {
                // At this point we know that the property is a primary key
                modelBuilder.Entity(modelType)
                            .Property(property.Name)
                            .UseSqlServerIdentityColumn()
                            .Metadata.BeforeSaveBehavior = PropertySaveBehavior.Ignore;

                continue;
            }

            if (property.PropertyType.IsEnum)
            {
                // At this point we know that the property is an enum.
                // Add the EnumToStringConverter converter to the property so that
                // the value is stored in the database as a string instead of number 
                var converter = new EnumToStringConverter(); // if somehow I can change this code to something like var `new EnumToStringConverter(property.PropertyType);` the code would work

                modelBuilder.Entity(modelType)
                            .Property(property.Name)
                            .HasConversion(converter);

                continue;
            }

        }
    }
}

上述代码的唯一问题是EnumToStringConverter 是如何构造的。如果我能以某种方式向EnumToStringConverter 的构造函数提供Type,而不是将其作为通用参数传递来解决问题。

【问题讨论】:

    标签: c# reflection entity entity-framework-core valueconverter


    【解决方案1】:

    Pre-defined conversions 文档部分所述:

    对于存在内置转换器的常见转换,无需明确指定转换器。相反,只需配置应使用的提供程序类型,EF 将自动使用适当的内置转换器。上面以枚举到字符串的转换为例,但如果配置了提供程序类型,EF 实际上会自动执行此操作:

    接下来是一个例子。

    接下来,您可以简单地使用:

    if (property.PropertyType.IsEnum)
    {
        // At this point we know that the property is an enum.
        // Add the EnumToStringConverter converter to the property so that
        // the value is stored in the database as a string instead of number 
        modelBuilder.Entity(modelType)
            .Property(property.Name)
            .HasConversion<string>(); // <--
    
        continue;
    }
    

    【讨论】:

    • 做到了。我错过了
    • 默认怎么做这样就不用写200次了?
    • @JeremyHolovacs 您可以这样做:stackoverflow.com/questions/50727860/… 只需使用此处的答案更改代码的内部部分。但是,如果您在单独的 SO 问题中提出这个问题,我很乐意为您提供准确的答案!
    • 或作为属性将 [Column(TypeName = "nvarchar(32)")] 放置到枚举属性中。这将自动将其保存为字符串。
    【解决方案2】:

    正在搜索相同的内容,但不想使用流利的方法。

    将以下内容添加到您的枚举属性中。

     [Column(TypeName = "nvarchar(32)")] 
    

    这将自动将其保存为字符串。如果放置在基类中,则适用于所有派生实体。

    你也可以注册一个类型配置

    public class BaseEntityTypeConfiguration : IEntityTypeConfiguration<BaseEntity>
    {
        public void Configure(EntityTypeBuilder<BaseEntity> builder)
        {
            builder.Property(p => p.YourEnumProp).HasConversion<string>();
        }
    }
    

    然后你在模型构建器上注册它

    mb.ApplyConfiguration(new BaseEntityTypeConfiguration());
    

    【讨论】:

      【解决方案3】:

      从 EF 核心 v6.0.0-preview6 开始,有一个更优雅的解决方案来全局注册 ValueConverter。由于 EFcore 已经附带了 EnumToStringConverter,只需将这些行添加到您的 DbContext 类中:

      protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
      {
          // Instead of numeric conversion that EFcore uses by default
          configurationBuilder.Properties<Enum>().HaveConversion<string>();
      }
      

      所有Enum 类型的属性都将被序列化为字符串,而不是数字。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多