【发布时间】:2017-05-19 00:48:10
【问题描述】:
我的客户端有一个存储 SQL Server 小数的标准,其规格为 decimal(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 才能使上述内容起作用。当我逐行设置属性时,这似乎不是必需的。
【问题讨论】:
-
查看 change all string property max length 以了解 v1.1.0 中的类似内容(无法在 v.1.0 中测试)
-
关于更新 2:发现所有实体类型后,代码应位于
OnModelCreating的末尾,因此包括非DbSet类型,例如通过modelBuilder.Entity<..>调用引入。跨度> -
@IvanStoev 说得有道理,但我有一些
modelBuilder.Entity<..>语句仅用于指定小数列类型,所以这些语句现在已经不存在了。 -
您需要有一些东西才能让 EF Core 将您的类视为实体(它不像 EF6 那样反映您的程序集)。 AFAIK 它应该是
DbSet,导航属性引用实体类(简单或集合)或modelBuilder.Entity<..>。如果这些都不存在,我看不到该类将如何映射到表。当然,该方法看起来更像是解决方法,而不是像 EF6modelBuilder.Type<...>配置这样的解决方案,但是您是说如果您在OnModelCreating末尾移动该过程,它会遗漏一些实体吗?我真的很感兴趣。
标签: entity-framework asp.net-core entity-framework-core