C# 设置实体';使用EF Core和DDD时的s UpdatedAt属性
我的实体有:C# 设置实体';使用EF Core和DDD时的s UpdatedAt属性,c#,entity-framework-core,domain-driven-design,entity-framework-core-2.2,C#,Entity Framework Core,Domain Driven Design,Entity Framework Core 2.2,我的实体有: public DateTime UpdatedAt { get; private set; } 我希望在每次更新实体时都更新该属性,因此我有: private void updateTimeStamp() => UpdatedAt = DateTime.UtcNow; 但是,我需要记住在每一个改变实体的方法中调用它,例如: public void addOrder(Order order) { //blah blah updateTimeStamp();
public DateTime UpdatedAt { get; private set; }
我希望在每次更新实体时都更新该属性,因此我有:
private void updateTimeStamp() => UpdatedAt = DateTime.UtcNow;
但是,我需要记住在每一个改变实体的方法中调用它,例如:
public void addOrder(Order order) {
//blah blah
updateTimeStamp(); // <----- musn't forget this!
}
问题:即使我不想更新实体,每次都会设置
选项2:属性
[UpdateTimestamp]
public void addOrder(Order order) {
//blah blah
}
问题:这并不能改善情况,基本上与原始问题相同
选项3:context.SaveChanges()中的自动更新
ChangeTracker.Entries()
.Where(e => e.Entity is MyEntity)
.Where(e => e.State == EntityState.Modified)
.Where(e => e.Entity as MyEntity)
.ToList()
.ForEach(e => { e.UpdatedAt = DateTime.UtcNow; });
builder.Property(e => e.UpdatedAt).ValueGeneratedOnUpdate();
// or
builder.Property(e => e.UpdatedAt).HasComputedColumnSql("GETDATE()");
问题:UpdatedAt
现在需要一个公共setter。这违反了DDD原则。这是最简单的选择,但意味着我必须放弃DDD的“始终有效”
选项3:与3相同,但使用反射
与选项3类似,我可以使用反射来更改属性,即使它有一个私有setter。这很容易做到,而且它的反射和“慢”并不是什么大问题,因为与数据库写入相比,时间可以忽略不计
问题:在基础设施而不是域中进行更改感觉是错误的
否则这是个不错的选择。它不是纯DDD,但它至少允许我保护实体的不变量
选项4:卸载到数据库提供商或数据库本身
ChangeTracker.Entries()
.Where(e => e.Entity is MyEntity)
.Where(e => e.State == EntityState.Modified)
.Where(e => e.Entity as MyEntity)
.ToList()
.ForEach(e => { e.UpdatedAt = DateTime.UtcNow; });
builder.Property(e => e.UpdatedAt).ValueGeneratedOnUpdate();
// or
builder.Property(e => e.UpdatedAt).HasComputedColumnSql("GETDATE()");
问题:不适用于所有提供程序(不适用于我,因为我使用的是不支持计算列的Npgsql)。同时,这也将问题转移到了基础设施和领域之外。所以我觉得我又犯了DDD
所以。。。有什么我忘了的吗?如果您正在进行DDD,您如何处理此问题?正如您已经指出的,选项1不适用,因为您可以在不更新任何内容的情况下获得订单,并且日期无论如何都会更改 选项2可能也会违反DDD原则,因为您可能已经修改了订单,并且在使用该特定方法之前不会更改更新日期 你只剩下选项3了,考虑到DDD的原则,我想它不那么糟糕,而且使用起来也最舒适。 你应该走这边。只需使用UpdatedAt属性和updateTimeStamp方法创建一个接口,并在实体上实现它。您可能应该创建一个基类并实现该方法。然后按照建议在SaveChanges方法中获取修改后的条目,并使用该方法而不是属性来避免将setter设置为private
还有第四个选项,您可以使用反射和代理类,但这将是一个很长的路要走,只有你问…为什么你需要一个公共setter?你试过@Matthiee我知道关于阴影属性。。。但是我不确定它们在这种情况下会有什么帮助?但是你可以做
e.SetUpdatedAt()
例如,让属性设置程序保持私有。@DavidG我不确定我是否同意你的想法。。。然而,这不仅仅是关于属性设置器是否是公共的,或者我是否将其隐藏在公共方法后面——这里的DDD问题是1)除了实体本身之外,任何代码都不可能更改它,2)只有在某些*实际更改时才可以。谢谢您的帮助。我从选项4开始。。。你认为现在最“好”的是什么?同意您关于要从上下文调用的updateTimeStamp()
方法的想法,我最初就是这样做的,但它感觉非常错误(而且它与仅将属性设置为public没有太大区别)。我也考虑过反射的想法,但似乎是一种迂回的方式来完成它(我现在要把它添加到列表中)。我认为这是DDD变得不切实际的情况之一!:(如果你真的需要坚持DDD原则,我想你必须为每个属性创建一个私有属性,将公共属性绑定到私有属性,并在setter中调用update方法……你应该看看mvvm模式如何绑定属性,也许你可以在那里找到适合你的东西。最后,我认为你应该不要拘泥于一种单一的方法。有些设计对于某个特定的问题没有简单的解决方案,你需要做大量的工作来遵循它。有时为了简单易懂而做出让步是可以的。同意实用。