【发布时间】:2020-04-20 15:26:38
【问题描述】:
我正在使用带有流畅 API 的 EF Core 3.1,并在特定的 Map 对象中配置实体,如下所示:
public class CouponMap: IEntityTypeConfiguration < Coupon > {
public void Configure(EntityTypeBuilder < Coupon > builder) {
builder.HasKey(t = >t.Id);
builder.Property(t = >t.Id).ValueGeneratedOnAdd();
builder.Property(e = >e.Name).HasMaxLength(120).IsRequired();
builder.Property(e = >e.Code).HasMaxLength(120).IsRequired();
builder.Property(e = >e.Value).HasColumnType("decimal(19,4)").IsRequired();
// Relations...
builder.HasOne < AppUser > (e = >e.CreatedByUser).WithMany().HasForeignKey(e = >e.DeletedBy).IsRequired();
builder.HasOne < AppUser > (e = >e.DeletedByUser).WithMany().HasForeignKey(e = >e.CreatedBy).IsRequired();
builder.HasOne < AppUser > (e = >e.UpdatedByUser).WithMany().HasForeignKey(e = >e.UpdatedBy);
// Set table name
builder.ToTable("Coupon", "dbo");
}
}
然后我在调试控制台上注意到,我的十进制字段有警告,例如:
Microsoft.EntityFrameworkCore.Model.Validation[30000] No type was specified for the decimal column 'Value' on entity type 'Coupon'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'.
但我实际上已经在我的地图对象中定义了HasColumnType,如您在上面看到的。首先我认为这可能只是一个警告,因为它无法“以某种方式”检测到更改,但是当我在 db 中检查我的表时,我看到优惠券表值列实际上使用默认值 (18,2) 作为十进制精度刻度而不是 ( 19,4)。
优惠券对象值字段定义如下:
public class Coupon : IHasIdColumn<int>
{
public int Id { get; set; }
public string Name { get; set; }
.
.
.
public decimal Value { get; set; } // <== the problem guy!
.
.
}
此外,如果您注意到,代码和名称字段甚至被创建为 NVARCHAR(MAX),尽管它们在地图对象中已设置为 HasMaxLength(120)。
之后我检查我的模型快照以确保我的实体脚本是如何生成的,只是为了确认它忽略了我的小数(19,4)并确认它实际上在模型快照中创建了表脚本:
modelBuilder.Entity("MyProject.Core.DomainModels.Coupon", b = >{
b.Property < int > ("Id").ValueGeneratedOnAdd().HasColumnType("int").HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
.
.
b.Property < decimal > ("Value").HasColumnType("decimal(18,2)");
.
.
. goes with other properties
}
然后这让我明白了,所以我尝试更新我的 CouponMap 对象中的其他属性,但没有检测到这些更改。例如,我尝试将我的列最大长度从 120 更改为 500,如下所示并添加新的迁移,但我的 up 和 down 函数为空。
public class CouponMap: IEntityTypeConfiguration < Coupon > {
public void Configure(EntityTypeBuilder < Coupon > builder) {
builder.HasKey(t = >t.Id);
builder.Property(t = >t.Id).ValueGeneratedOnAdd();
builder.Property(e = >e.Name).HasMaxLength(500).IsRequired(); // changed this but not detected in migration...
builder.Property(e = >e.Code).HasMaxLength(500).IsRequired(); // also changed this but not detectedin migration...
builder.Property(e = >e.Value).HasColumnType("decimal(19,4)").IsRequired(); // this somehow was not being detected anyways so I tried other 2 columns above
// Relations...
builder.HasOne < AppUser > (e = >e.CreatedByUser).WithMany().HasForeignKey(e = >e.DeletedBy).IsRequired();
builder.HasOne < AppUser > (e = >e.DeletedByUser).WithMany().HasForeignKey(e = >e.CreatedBy).IsRequired();
builder.HasOne < AppUser > (e = >e.UpdatedByUser).WithMany().HasForeignKey(e = >e.UpdatedBy);
// Set table name
builder.ToTable("Coupon", "dbo");
}
}
我知道我可以使用System.ComponentModel.DataAnnotations.Schema 来装饰我的财产,如下所示:
[Column(TypeName = "decimal(19,4)")]
public decimal Value { get; set; }
如果我这样做并创建新的迁移,我会看到它立即检测到更改,并且我的 up 和 down 函数如下所示:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<decimal>(
name: "Value",
table: "Coupon",
type: "decimal(19,4)",
nullable: false,
oldClrType: typeof(decimal),
oldType: "decimal(18,2)");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<decimal>(
name: "Value",
table: "Coupon",
type: "decimal(18,2)",
nullable: false,
oldClrType: typeof(decimal),
oldType: "decimal(19,4)");
}
但我想保持我的域对象尽可能干净,并且只使用EntityMap 类来定义与数据库相关的任何实体类型配置(否则使用 FluentAPI 有什么意义?)
我在想我的实体映射对象可能没用,但是我在实体映射对象中创建的关系工作得很好。
我尝试清理解决方案、重建、重新启动 VS,但都没有奏效。有什么建议还是我在这里遗漏了什么?
【问题讨论】:
-
CouponMap.Configure中的代码很可能没有被执行。 -
@IvanStoev - 我实际上是这么想的,但我所有的关系都工作正常(也在 CouponMap.Configure 中定义)。
-
好吧,
Key、ValueGeneratedOnAdd、关系 - 所有这些都可以在没有流畅配置的情况下工作,因为它们符合 EF Core 约定。为了测试,把Configure方法的内容注释掉。或者在里面添加类似throw new Exception("Blah");的东西。 -
@IvanStoev - 你是对的。非常感谢。它根本没有抛出那个异常,因为我没有在 DbContext 的 OnModelCreating 函数中调用 builder.ApplyConfiguration ......呃......
标签: c# .net-core entity-framework-core code-first ef-fluent-api