繁体   English   中英

EF 核心计算属性标记为只读

[英]EF core computed properties marked as readonly

背景:每当添加或更新“Item”实体时,我都会覆盖 SaveChanges() 方法以自动生成 LastUpdatedDate。

项目.cs

  [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
  public DateTime? LastUpdated { get; set; }

数据库上下文

  protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
      ...
      // generated value
      modelBuilder.Entity<Item>()
                  .Property(b => b.LastUpdated)
                  .ValueGeneratedOnAddOrUpdate();

     }

    public override int SaveChanges()
    {
        var now = DateTime.UtcNow;

        foreach (var item in ChangeTracker.Entries<Item>()
            .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified))
        {
            item.Property("LastUpdated").CurrentValue = now;             
        }           

        return base.SaveChanges();
    } 

我遇到的问题是每当调用 SaveChanges() 时,我都会收到此异常:

EntityFramework.Core.dll 中发生了“System.InvalidOperationException”类型的异常,但未在用户代码中处理。
附加信息:实体类型“Item”上的属性“LastUpdated”在保存后被定义为只读,但其值已被修改或标记为已修改。

要解决此问题,我必须将 IsReadOnlyBeforeSave 和 IsReadOnlyAfterSave 设置为 false,如下所示:

        modelBuilder.Entity<Tray>()
            .Property(b => b.LastUpdated)
            .ValueGeneratedOnAddOrUpdate()
            .Metadata.IsReadOnlyBeforeSave = false; 
        modelBuilder.Entity<Tray>()
            .Property(b => b.LastUpdated)
            .Metadata.IsReadOnlyAfterSave = false;

问题:

这是在 EF Core 中设置计算属性的正确方法吗?

此外,我可以首先防止将 LastUpdated 定义为“只读”吗?

这是在 EF Core 中设置计算属性的正确方法吗?

文档对此非常清楚:

添加或更新时生成的值意味着每次保存(插入或更新)记录时都会生成一个新值。

注意

如何为添加和更新的实体生成值将取决于所使用的数据库提供程序。 (...) 如果您指定在添加或更新时生成 DateTime 属性,则必须设置生成值的方法(例如数据库触发器)。

注释的名称 --"DatabaseGeneratedOption"-- 可能揭示了这些方面的内容。

所以如果你想使用这种模式,你应该在数据库中设置一个触发器,在插入和每次更新时设置字段值。 通过使用注释[DatabaseGenerated]流畅的 API .ValueGeneratedOnAddOrUpdate() (无需同时执行这两项操作),EF 会收到信号,表示它应该在保存更改后从数据库读取值。

至于IsReadOnlyBeforeSave属性。 到目前为止,唯一的文档是 EF 源代码中有关该属性的 XML 文档:

获取或设置一个值,该值指示在将实体保存到数据库之前是否可以修改此属性。 如果为 true,则在此属性处于已Added状态时为其分配值将引发异常。

据我所知,您可能希望将此值设置为true以消除对设置此属性有用的任何期望(因为它不是)。 同样,您可以将IsReadOnlyAfterSave设置为在现有(未Added )实体中设置该属性时引发异常。

如果您不想要数据库生成的值,您可以删除注释并像现在一样分配值。

IsReadOnlyAfterSave标志已被废弃并由AfterSaveBehavior取代。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Device>()
        .Property<string>("TenantId")
        .HasField("_tenantId")
        //.Metadata.IsReadOnlyAfterSave = true;
        .Metadata.AfterSaveBehavior = Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Ignore;
}

EF 核心 3.x 和 5

这是在 EF Core 5 中设置 AfterSaveBehavior 的方式

    protected override void OnModelCreating(ModelBuilder modelBuilder) 
    { 
       modelBuilder.Entity<MyEntity>
         .Property(x => x.DateCreated)
         .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save); 
    }

投掷

如果设置了显式值或更改了值,则会引发异常。 这是默认设置,也是您收到异常的原因 - 根据您的情况将其设置为保存或忽略。

保存

设置或更改的值将以正常方式发送到数据库。

忽略

任何设置或更改的值都将被忽略。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM