循环/反映所有EF模型中的所有属性以设置列类型

Chr*_*ris 17 entity-framework entity-framework-core asp.net-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)");
Run Code Online (Sandbox Code Playgroud)

如果有一个功能,我可以直接告诉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)");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

反射似乎是一个很好的方法,因为那时我可以实现一些其他约定,如果一个对象有一个名称和描述,名称是必需的,并限制为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)";
}
Run Code Online (Sandbox Code Playgroud)

不久之后,他提供了一个完整的答案,我稍微改了一下,使用十进制和可以为零的小数:

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)");
}
Run Code Online (Sandbox Code Playgroud)

两种方法都有效!

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

Iva*_*oev 29

在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)");
}
Run Code Online (Sandbox Code Playgroud)

更新:从EF Core 2.0开始,模型是为每个数据库提供程序单独构建的,因此HasAbcXyz方法将替换为common 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)";
}
Run Code Online (Sandbox Code Playgroud)

  • 这已经发生了一些变化,至少对于ef core 2.0而言.您需要使用nuget Microsoft.EntityFrameworkCore.SqlServer而不是ForSqlServer.该扩展名为HasColumnType. (4认同)

Mar*_*ese 8

EF 核心 6.0

现在可以很简单地为每个decimal属性(或string等)配置默认值:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder
        .Properties<decimal>()
        .HavePrecision(19, 4);
}
Run Code Online (Sandbox Code Playgroud)

更多信息:会议前模型配置