实体框架 – 域实体跟踪数据的最佳实践?基类还是作文?

大多数大型项目的一个常见方面是需要对许多域实体进行通用跟踪数据.例如,大多数大型项目会跟踪许多域实体的以下属性:

DateTime DateCreated
User CreatedBy
DateTime LastModified
User LastModifiedBy

这些数据非常自我解释,数据用于跟踪谁对Domain对象做了什么.

问题是在为大型应用程序设计域模型时,处理此跟踪数据的最佳方法是什么.

经典的方法是使用基类,然后让相关的域类继承自该基类.但这引起了我的favor composition over inheritance警钟.我工作的项目越大,我就越拒绝继承,但这并不是说有些情况下它是最好的选择,例如在这种情况下.另一种继承解决方案是使用接口,但是虽然此解决方案耦合较少,但我没有看到很多在域实体上使用此方法的示例.

第二种方法是使用组合将各种跟踪对象添加到每个域实体.唯一的问题是必须特别指示数据层不将它们表示为单独的表.一项小任务,但如果没有回报则难以证明这一点.

处理跟踪数据的最后一种方法是配置数据层以透明地执行此操作.我认为可能有可能使用Entity-Framework执行此操作,但过去没有实现此解决方案,这将是最前期的时间密集型解决方案.很难预见这种解决方案是否值得这么麻烦.

虽然这个问题看似客观,但这实际上是大多数大型项目必须以某种方式处理的常见任务.

设计用于跟踪元数据的域模型和/或大型项目的最佳方法是什么?

最佳答案 最佳实践通常是主观的,并且可以解决尽可能多的问题.你什么时候应该继承?你什么时候撰写?学者花了数年时间争论抛出一个问题的细枝末节.具有简单界面的基本继承是务实和有效的.如果它是所有实体的标准功能,那么继承可能是更好的选择.

我有一个带有审计属性的基类,并为这些属性实现了一个接口.我使用以下代码拦截对context.SaveChanges()的调用.这很简单,也很有效.如果任何被跟踪的实体未实现IAudit接口,则可以将其扩展为失败.

    public override int SaveChanges()
    {
        var entities = this.GetChangedAuditDataEntities();

        foreach (var entity in entities)
        {
            this.SetModificationInfo(entity);
        }

        return base.SaveChanges();
    }

    private IEnumerable<IAuditData> GetChangedAuditDataEntities()
    {
        return (
            from entry in _context.ChangeTracker.Entries()
            where entry.State != EntityState.Unchanged
            select entry.Entity)
            .OfType<IAuditData>();
    }

    private void SetModificationInfo(IAuditData entity)
    {
        entity.lastModifiedBy = _currentUser.Name;
        entity.lastModified = System.DateTime.Now;
    }

这是其中一个不会自动获得“正确”答案的问题.如果Jon Skeet要回答它,那么它将被视为最佳实践.唯一正确的答案必须确认您的特定偏见,或者至少打出正确的知识分子.

多年前,继承很普遍,其中一个很大的推动就是“继承的价值构成”口头禅.很好,但继承有它的位置.

我建议任何具有许多相同类型对象的架构层,例如域对象(“域对象”一词意味着公共层)可以通过具有公共基类来大大增强. System.Object就是一个很好的例子.我再举一个例子.当我们为解决方案定义异常装饰器时,我们决定扩展ToString()方法以创建唯一标识对象的值.

public override string ToString()
{
    if (this is IAuditData)
    {
        IAuditDataidentifiable = this as IAuditData;
        return string.Format(@"{0} {{ id: {1}, ETag: {2} }}",
            identifiable.GetType().Name,
            identifiable.id,
            identifiable.ETag);
    }
    else return base.ToString();
}

7行代码 – 务实,简单,有效.从你的问题来看,你完全反对继承,这必须由许多烧焦的手指承担.我也是;-)但我仍然声称它是这个例子中更好的选择.

点赞