从DbContext获取所有跟踪的实体?

时间:2012-04-12 11:16:23

标签: c# entity-framework

我数据库中的许多表都需要有一个“DateCreated”和“DateModified”列。我想在调用SaveChanges()时更新这些列。

我的所有模型对象都继承自类AbstractModel以允许这种行为。该课程如下:

public abstract class AbstractModel {
    public virtual void UpdateDates() { }
}

然后我计划在任何需要维护UpdateDates()DateCreated字段的子类中覆盖DateModified

要使用此功能,我需要能够获取DbContext正在跟踪的所有实体的列表,如果对象标记为{{1},则需要在其上调用UpdateDates() }或Added

我似乎无法访问Modified存储此信息的位置。我可以DbContext获取单个实体的dbContext.Entry(object).State,但我无法弄清楚如何获取所有跟踪实体的列表。

我该怎么做?

3 个答案:

答案 0 :(得分:21)

我认为您可以使用ChangeTracker

public class MyContext : DbContext
{
    //...

    public override int SaveChanges()
    {
        foreach (var dbEntityEntry in ChangeTracker.Entries<AbstractModel>())
        {
            dbEntityEntry.Entity.UpdateDates();
        }
        return base.SaveChanges();

    }
}

答案 1 :(得分:5)

对于上面的EF4,接受的解决方案here比ObjectContext建议更好 - 我们遇到了问题,例如我们在测试上下文中使用的内存db与上述解决方案不兼容(获得Detached状态为继承方案中的一些修改条目)。此解决方案使用DbContext本机方式检索跟踪的实体:

private IEnumerable<IValidationResult> Validate(IDeliveryObject deliveryObject)
{
    var validationErrors = new List<IValidationResult>();
    int maxNumberOfErrors = 10;
    foreach (IDeliveryValidator deliveryValidator in _validators)
    {
       // Here I want results to contain MAX 10 regular validation results, but unlimited soft validation results
        IEnumerable<IValidationResult> results = deliveryValidator.Validate(deliveryObject).Take(maxNumberOfErrors);
        validationErrors.AddRange(results);
        if (validationErrors.Count(x => !x.IsSoftError) >= maxNumberOfErrors)
        {
            return validationErrors.Take(maxNumberOfErrors).ToList();
        }
    }
    return validationErrors;
}

答案 2 :(得分:2)

这在我们的项目中运作良好,因此每次添加具有标准LastUpdatedDateTime属性的新实体时,我们都不必记住覆盖某些内容。 使用EF4;对于EF5 DbContext我认为((IObjectContextAdapter)_dbContext).ObjectContext.ObjectStateManager会得到对象状态管理器:

// In our SaveChanges wrapper:
        var entries = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted);

        private static void PopulateDate(IEnumerable<ObjectStateEntry> entries)
                {
                    foreach (var entry in entries)
                    {
                        if (entry.State != EntityState.Deleted)
                        {
                            if ((entry.Entity != null) && (entry.Entity.GetType().GetProperty("LastUpdatedDateTime") != null))
                            {
                                ((dynamic)entry.Entity).LastUpdatedDateTime = DateTime.UtcNow;
                            }
                        }
                    }
                }

反射调用不是问题:对于具有25个属性(很多)的对象,一百万次反射查询需要平均〜210 ms。