cfs*_*cfs 7 c# design-patterns domain-driven-design entity-framework ef-code-first
我使用Entity Framework并希望使用DDD原则.但是,有一些信息涉及在记录/持久性信息和域对象信息之间的边界线上的实体.
我的情况这些被放在一个抽象的基类中,所有实体都继承自:
public abstract class BaseEntity: IBaseEntity
{
/// <summary>
/// The unique identifier
/// </summary>
public int Id { get; set; }
/// <summary>
/// The user that created this instance
/// </summary>
public User CreatedBy { get; set; }
/// <summary>
/// The date and time the object was created
/// </summary>
public DateTime CreatedDate { get; set; }
/// <summary>
/// Which user was the last one to change this object
/// </summary>
public User LastChangedBy { get; set; }
/// <summary>
/// When was the object last changed
/// </summary>
public DateTime LastChangedDate { get; set; }
/// <summary>
/// This is the status of the entity. See EntityStatus documentation for more information.
/// </summary>
public EntityStatus EntityStatus { get; set; }
/// <summary>
/// Sets the default value for a new object
/// </summary>
protected BaseEntity()
{
CreatedDate = DateTime.Now;
EntityStatus = EntityStatus.Active;
LastChangedDate = DateTime.Now;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,如果不提供日期和时间,则无法对域对象进行实例化..不过我认为这是错误的地方.我可以说两者都是真的.也许它根本不应该与域名混合?
因为我正在使用EF Code First,所以将它放在那里是有意义的,否则我需要创建从DAL中的基类继承的新类,复制代码并需要映射到域对象和MVC模型看起来比上面的方法更麻烦.
问题:
是否可以在Domain模型中使用DateTime.Now?你在哪里使用DDD和EF Code First来提供这类信息?用户是应该在域对象中设置还是在业务层中需要它?
更新
我认为jgauffin在这里得到正确答案 - 但这确实是一个根本性的变化.但是,在我寻找替代解决方案时,我几乎已经解决了这个问题.如果添加或修改实体,我使用ChangeTracker.Entries查找ut并相应地设置字段.这是在我的UnitOfWork Save()方法中完成的.
问题是加载导航属性,如User(正确设置DateTime).可能是因为用户是实体继承的抽象基类的属性.我也不喜欢在那里放置字符串,但它可能会为某些人解决一些简单的场景,所以我在这里发布解决方案:
public void SaveChanges(User changedBy)
{
foreach (var entry in _context.ChangeTracker.Entries<BaseEntity>())
{
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedDate = DateTime.Now;
entry.Entity.LastChangedDate = DateTime.Now;
entry.Entity.CreatedBy = changedBy;
entry.Entity.LastChangedBy = changedBy;
}
if (entry.State == EntityState.Modified)
{
entry.Entity.CreatedDate = entry.OriginalValues.GetValue<DateTime("CreatedDate");
entry.Entity.CreatedBy = entry.OriginalValues.GetValue<User>("CreatedBy");
entry.Entity.LastChangedDate = DateTime.Now;
entry.Entity.LastChangedBy = changedBy;
}
}
_context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
在域模型中使用 DateTime.Now 可以吗?
是的。
使用 DDD 和 EF Code First 将此类信息放在哪里?用户应该在域对象中设置还是在业务层中要求它?
出色地。首先:DDD模型始终处于有效状态。对于公共设置者来说这是不可能的。在 DDD 中,您可以使用方法来处理模型,因为方法可以确保所有必需的信息均已指定且有效。
例如,如果您可以将一个项目标记为已完成,那么日期很可能UpdatedAt也应该更改。如果您让调用代码确保它很可能会被遗忘在某个地方。相反,你应该有类似的东西:
public class MyDomainModel
{
public void MarkAsCompleted(User completedBy)
{
if (completedBy == null) throw new ArgumentNullException("completedBy");
State = MyState.Completed;
UpdatedAt = DateTime.Now;
CompletedAt = DateTime.Now;
CompletedBy = completedBy;
}
}
Run Code Online (Sandbox Code Playgroud)
阅读我关于该方法的博客文章:http://blog.gauffin.org/2012/06/protect-your-data/
更新
如何确保以后没有人更改“CreatedBy”和“CreatedDate”
我通常有两个也适合数据库的模型构造函数。一种是受保护的,一种可以由我的持久层使用,另一种需要强制字段。将createdby放入该构造函数中并在其中设置createdate:
public class YourModel
{
public YourModel(User createdBy)
{
CreatedDate = DateTime.Now;
CreatedBy = createdby;
}
// for persistance
protected YourModel()
{}
}
Run Code Online (Sandbox Code Playgroud)
然后为这些字段设置私有设置器。
我收到很多 R# 警告“构造函数中的虚拟成员调用”,我之前读过它,这不应该是一个好的做法。
这通常不是问题。阅读此处:构造函数中的虚拟成员调用
| 归档时间: |
|
| 查看次数: |
2355 次 |
| 最近记录: |