c# - EF Core 3.1 Fluent API 未检测到实体上的更改
问题描述
我正在使用带有流畅 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 中检查我的表时,我看到 Coupon 表值列实际上使用默认值 (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,但它们都没有奏效。有什么建议还是我在这里遗漏了什么?
解决方案
问题是,那些映射对象配置函数根本没有被调用。
解决方案很简单:
protected override void OnModelCreating(ModelBuilder builder)
{
// configuring mappings one by one like below..
// builder.ApplyConfiguration(new CouponMap());
// builder.ApplyConfiguration(new WebOrderMap());
// or configuring all the mappings by using assembly..
builder.ApplyConfigurationsFromAssembly(typeof(CouponMap).Assembly);
base.OnModelCreating(builder);
}
感谢@Ivan Stoev,他指出我在这些映射对象中抛出异常以查看它们是否会触发......它愚弄了我,因为我所有的关系都非常好,所以我认为这是因为我的映射对象工作正常。但这实际上只是因为 EF 约定,我的对象映射从未运行过。
推荐阅读
- c# - 在 C# 中使用 ContinueWith 链接异步任务
- java - 为什么在持有多个锁时不应调用“等待”?
- javascript - 使用javascript php laravel在经度和纬度数据库中的条目重复
- scala - Different byte code generated issue
- php - 使用 codeigniter 使用 REST API 时如何在表单操作中调用方法名称?
- javascript - 如何在 Angularjs 中使用 gojs 禁用 DragSelectingTool
- javascript - Calling function of service. Angular6
- javascript - How to remove focus from text field when user presses ESC angular 5
- javascript - Async/Await 函数,fs.readfile 并将其存储到变量中
- python - pip 命令问题 - 命令“python setup.py egg_info”失败,错误代码 1 在 /private/tmp/pip-build-7n_jim1n/mysql-python/