C# 在DDD中将创建日期和创建人放在何处?

C# 在DDD中将创建日期和创建人放在何处?,c#,entity-framework,design-patterns,ef-code-first,domain-driven-design,C#,Entity Framework,Design Patterns,Ef Code First,Domain Driven Design,我使用实体框架,希望使用DDD原则。但是,有一些关于实体的信息,这些实体处于什么是日志/持久性信息和什么是关于域对象的信息之间的边界 在我的情况下,这些被放在一个抽象基类中,所有实体都从该基类继承: public abstract class BaseEntity: IBaseEntity { /// <summary> /// The unique identifier /// </summary> public int Id { g

我使用实体框架,希望使用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;
    }

}
公共抽象类BaseEntity:IBaseEntity
{
/// 
///唯一标识符
/// 
公共int Id{get;set;}
/// 
///创建此实例的用户
/// 
公共用户CreatedBy{get;set;}
/// 
///创建对象的日期和时间
/// 
公共日期时间CreatedDate{get;set;}
/// 
///哪个用户是最后一个更改此对象的用户
/// 
公共用户LastChangedBy{get;set;}
/// 
///上次更改对象是什么时候
/// 
公共日期时间LastChangedDate{get;set;}
/// 
///这是实体的状态。有关详细信息,请参阅EntityStatus文档。
/// 
公共EntityStatus EntityStatus{get;set;}
/// 
///设置新对象的默认值
/// 
受保护的BaseEntity()
{
CreatedDate=DateTime.Now;
EntityStatus=EntityStatus.Active;
LastChangedDate=DateTime.Now;
}
}
现在,如果不提供日期和时间,就无法实例化域对象。然而,我觉得这是一个错误的地方把它。我真的可以为两者辩护。也许它根本不应该与域混合在一起

因为我首先使用EF代码,所以将其放在那里是有意义的,否则我还需要创建从DAL中的基类继承的新类,复制代码并需要映射到域对象和MVC模型,这看起来比上述方法更混乱

问题:

在域模型中使用DateTime.Now可以吗?您首先使用DDD和EF代码将此类信息放在哪里?应该在域对象中设置用户,还是在业务层中需要用户

更新

我认为jgauffin在这里是正确的答案——但这确实是一个相当根本的变化。然而,在我寻找另一个解决方案时,我几乎用这个解决了它。我使用ChangeTracker.Entries查找是否添加或修改了实体,并相应地设置字段。这是在我的UnitOfWork Save()方法中完成的

问题在于加载导航属性,如用户(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();
    }
public void SaveChanges(用户已更改)
{
foreach(在_context.ChangeTracker.Entries()中的var条目)
{
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.Now可以吗

这并不可怕,但问题是,您最终将不得不复制代码,而且实现一致性将更加困难

您首先使用DDD和EF代码将此类信息放在哪里

您断言此类信息不属于您的域是正确的。它通常被称为审核日志或跟踪。有几种方法可以使用EF实现审核。例如,请看一看,或者只是四处搜索EF审核实现。其思想是,在EF持续更改实体之前,它会引发一个事件您可以侦听并分配所需的审核值

应该在域对象中设置用户,还是在 业务层

最好在基础设施/存储库级别通过上述审计实现来处理此问题。这是数据持久化之前的最后一站,因此是处理此问题的最佳场所

在域模型中使用DateTime.Now可以吗

您首先使用DDD和EF代码将此类信息放在何处?用户应该在域对象中设置还是在业务层中要求设置

首先,DDD模型总是处于有效状态。这对于公共setter是不可能的。在DDD中,您使用方法处理模型,因为这些方法可以确保所有必需的信息都已指定且有效

例如,如果您可以将一个项目标记为已完成,则很可能更新日期也应该更改。如果您让调用代码确保该日期,则很可能会将其遗忘在某个地方。相反,您应该具有以下内容:

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;
    }
}
阅读我关于这种方法的博客帖子:

更新

如何让舒尔在以后更改“CreatedBy”和“CreatedDate”

对于模型,我通常有两个构造函数,它们也适合DB。一个受保护的构造函数可供我的持久性层使用,另一个需要必填字段。将createdby放在该构造函数中,并在其中设置createdate:

public class YourModel
{
    public YourModel(User createdBy)
    {
        CreatedDate = DateTime.Now;
        CreatedBy = createdby;
    }

    // for persistance
    protected YourModel()
    {}
}
然后为这些字段设置私有setter

我收到很多关于“构造函数中的虚拟成员调用”的警告,我以前读过这方面的内容,但这并不是一个好的实践


这通常不是问题。请阅读此处:

我以前没有听说过,但它看起来是一个非常好的解决方案。我必须更仔细地研究它。您知道这是否会导致实体框架的新版本出现问题吗