将EF Core列/字段指定为只读

时间:2019-01-03 21:01:05

标签: c# sql-server entity-framework entity-framework-core

我有一个SQL Server表,其中包含由数据库通过默认值设置的某些字段,这些默认值一旦保存,就应该从不再次进行修改(例如DateCreated)。

在Entity Framework Core 2.1模型构建器或类中,如何将字段“标记”为本质上是只读的?换句话说,我不希望任何代码能够设置或覆盖这些字段。

根据搜索结果,我可以在.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)的末尾添加.Property()吗?

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Doohicky>(entity =>
    {
        ... // other fields

        entity.Property(e => e.DateCreated).HasDefaultValueSql("(getdate())");

        ... // other fields
    });
}

还是在[DatabaseGenerated(DatabaseGeneratedOption.Identity)]字段中添加DateCreated注释?

public class Doohicky
{
    public DateTime DateCreated {get; set;}
}

还是完全有另一种方法?

我想要这样,以便将来如果有人决定写这样的东西,就会引发错误。

model.DateCreated = new DateTime();
dbContext.SaveChanges() // errors out

任何见识将不胜感激。

3 个答案:

答案 0 :(得分:4)

EF核心预期的方式是将AfterSaveBehavior属性设置为默认Save以外的值:

  

获取一个值,该值指示在将实体保存到数据库之后是否可以修改此属性。

     

如果为Throw,则在数据库中存在该实体之后,如果将新值分配给该属性,则将引发异常。

     

如果为Ignore,则将忽略数据库中已存在的实体的属性值的任何修改。

还没有专用的流畅的API,因此您需要通过可变属性元数据直接设置它,如下所示:

entity.Property(e => e.DateCreated)
    .HasDefaultValueSql("(getdate())")
    .Metadata.AfterSaveBehavior = PropertySaveBehavior.Throw; // <-- 

答案 1 :(得分:1)

[Required, DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime DateCreated {get; set;}

答案 2 :(得分:0)

我过去使用可审计的属性(例如DateCreated,DateModified等)来完成此操作。此解决方案可能不适合排除各种对象中的特定属性(尽管您可以使用自定义属性进行某些操作,等等。) )。

我重写SaveChanges / Async(),然后遍历上下文正在跟踪的所有已更改对象。我所有的对象都使用相同的基类,因此可以通过以下方法实现此目的:

var changes = ChangeTracker.Entries<BaseEntity>().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);

使用这些对象,我遍历它们并设置一些可审核的属性,如果对象不是新对象,则忽略某些属性。首先,我有一个字符串集合,这些字符串表示要排除的属性名称。然后,我遍历集合,并忽略属性名称与排除的集合匹配的属性。见下文:

// A collection of property names which should not be updated
var excludedProperties = new[] { "CreatedBy", "CreatedDateUtc" };

foreach (var change in changes)
{
   // If new, do as you'd like

   // If used, ignore date created
   Array.ForEach(excludedProperties, prop =>
   {
      change.Property(prop).IsModified = false;
   });
}