在DDD中放置创建日期和创建日期的位置?

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)

jga*_*fin 3

在域模型中使用 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# 警告“构造函数中的虚拟成员调用”,我之前读过它,这不应该是一个好的做法。

这通常不是问题。阅读此处:构造函数中的虚拟成员调用