entity-framework - 循环/遍历所有EF模型中的所有属性以设置列类型

标签 entity-framework asp.net-core entity-framework-core

我的客户有一个存储SQL Server小数的标准,该小数具有十进制(13,4)规范。结果,在非常庞大且仍在增长的模式中,我有将近一百条这样的语句:

builder.Entity<MyObject>()
    .Property(x => x.MyField1)
    .ForSqlServerHasColumnType("decimal(13,4)");
builder.Entity<MyObject>()
    .Property(x => x.MyField2)
    .ForSqlServerHasColumnType("decimal(13,4)");
builder.Entity<MyObject2>()
    .Property(x => x.MyField1)
    .ForSqlServerHasColumnType("decimal(13,4)");

如果有一个功能可以直接告诉EF默认情况下所有小数应为十进制(13,4),我想使用它。如果没有,我可以使用反射来遍历模型中的每个对象/属性,以便在几个语句中做到这一点吗?

就像是:
foreach(var efObj in EntityFrameWorkObjects)
{
    foreach (var objProperty in efObj)
    {
        if (objProperty is decimal || objProperty is decimal?)
        {
            builder.Entity<efObj>()
                .Property(x => x.efObj)
                .ForSqlServerHasColumnType("decimal(13,4)");
        }
    }
}

反射似乎是一种很好的方法,因为这样我就可以实现一些其他约定,如果对象具有名称和描述,则该名称是必需的,并且限制为256个字符。

更新:
我按照Ivan的评论中的链接进行了修改,使其适合我:
foreach (var p in builder.Model
    .GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => 
        p.ClrType == typeof(decimal) ||
        p.ClrType == typeof(decimal?)))
{
    p.SqlServer().ColumnType = "decimal(13,4)";
}

不久之后,他提供了一个完整的答案,我对它作了些微改动,使其可以同时使用十进制和可为空的十进制:
foreach (var pb in builder.Model
    .GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => 
        p.ClrType == typeof(decimal) ||
        p.ClrType == typeof(decimal?))
    .Select(p => 
        builder.Entity(p.DeclaringEntityType.ClrType)
            .Property(p.Name)))
{
    pb.ForSqlServerHasColumnType("decimal(13,4)");
}

两种方法都行!

更新2:我必须在上下文中将我的对象声明为DbSet <>才能使上述工作正常。当我逐行设置属性时,这似乎不是必需的。

最佳答案

在EF Core v1.1.0中,您可以使用以下代码:

foreach (var pb in modelBuilder.Model
    .GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?))
    .Select(p => modelBuilder.Entity(p.DeclaringEntityType.ClrType).Property(p.Name)))
{
    pb.ForSqlServerHasColumnType("decimal(13,4)");
}

更新(EF Core 2.x):从EF Core 2.0开始,该模型是为每个数据库提供程序单独构建的,因此HasAbcXyz方法将替换为通用的HasXyz。更新后的代码(还将跳过显式配置的属性)如下所示:
foreach (var property in modelBuilder.Model.GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
{
    if (property.Relational().ColumnType == null)
        property.Relational().ColumnType = "decimal(13,4)";
}

更新(EF Core 3.x):更改了EF Core 3.0元数据API(删除了Relational()扩展名,将属性替换为Get/Set方法对),代码如下:
foreach (var property in modelBuilder.Model.GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
{
    if (property.GetColumnType() == null)
        property.SetColumnType("decimal(13,4)");
}

关于entity-framework - 循环/遍历所有EF模型中的所有属性以设置列类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45463349/

相关文章:

c# - 将 ASPNET MVC RC1 迁移到 RC2 后出现 Entity Framework Core 错误

asp.net-core - .Net-Core 从 httpContext 获取 HttpBrowserCapabilities

visual-studio-2015 - 如何在 MVC6 中使用标准类库?

c# - 为什么不能使用 = 运算符设置 DbContextOptions?

.net-core - .NET Core 和 Entity Framework Core 之间的区别

c# - 在不将整个表加载到内存的情况下检查哪些消息已经存在

entity-framework - 如何在使用 Entity Framework 时序列化 ICollection<T> 类型的属性

c# - 我如何在 Entity Framework 中执行此操作(多个 where's 或 Join)?

c# - 显示原始值 Entity Framework 7

c# - 在 web api 中删除项目单元测试