我有一个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
任何见识将不胜感激。
答案 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;
});
}