循环/反映所有 EF 模型中的所有属性以设置列类型 [英] Loop/reflect through all properties in all EF Models to set Column Type

查看:33
本文介绍了循环/反映所有 EF 模型中的所有属性以设置列类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的客户有一个存储 SQL Server 小数的标准,其中包含小数 (13,4) 规范.结果,在一个非常大且仍在增长的模式中,我有近一百个这样的语句:

My client has a standard of storing SQL Server decimals with a decimal(13,4) specification. As a result, in a very large and still-growing schema, I have nearly a hundred statements like these:

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),我想使用它.如果没有,我是否可以使用反射来遍历模型中的每个对象/属性,以便我可以在几个语句中执行此操作?

If there is a feature where I can tell EF directly that all decimals should be decimal(13,4) by default, I would like to use that. If not, can I use reflection to loop through every object/property in the model so I can do this in a couple statements?

类似于:

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 个字符.

Reflection seems like a great way to go, because then I can implement some of our other conventions where, if an object has a Name and Description, the Name is required and limited to 256 chars.

更新:我按照伊万评论中的链接进行了修改,这对我有用:

Update: I followed the link in Ivan's comment and adapted it to this, which works for me:

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)";
}

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

Soon after, he provided a full answer, which I changed slightly to work with both decimal and nullable decimal:

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<> 才能使上述内容正常工作.当我逐行设置属性时,这似乎不是必需的.

Update 2: I had to have my objects declared as DbSet<> in the context for the above to work. This didn't seem to be required when I was setting properties line by line.

推荐答案

在 EF Core v1.1.0 中,您可以使用以下内容:

In EF Core v1.1.0 you can use something like this:

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.更新后的代码(也跳过了显式配置的属性)如下所示:

Update (EF Core 2.x): Starting from EF Core 2.0, the model is built separately for each database provider, so HasAbcXyz methods are replaced with common HasXyz. The updated code (which also skips the explicitly configured properties) looks like this:

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 方法对),代码如下:

Update (EF Core 3.x): With EF Core 3.0 metadata API changes (Relational() extensions removed, properties replaced with Get / Set method pair), the code is as follows:

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)");
}

这篇关于循环/反映所有 EF 模型中的所有属性以设置列类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆