簡體   English   中英

實體框架6:檢測關系變化

[英]Entity Framework 6: detect relationship changes

在我的DbContext子類中,我重寫了SaveChanges()方法,因此我可以實現一種類似觸發器的功能(在實際保存更改之前)。 現在,在某些觸發器中,有必要檢測某些關系是否已經改變,無論多對多,一對一/零等。

我已經閱讀了互聯網上的一些帖子,包括本網站上的一些帖子,提到DbContext API沒有公開任何獲取關系信息的方法。 但是,ObjectContext應該能夠。

我的SaveChanges方法:

public override int SaveChanges()
{
    IEntity entity;
    ChangeTracker.DetectChanges();

    var stateManager = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager;
    var added = stateManager.GetObjectStateEntries(EntityState.Added).ToList();
    var updated = stateManager.GetObjectStateEntries(EntityState.Modified).ToList();
    var deleted = stateManager.GetObjectStateEntries(EntityState.Deleted).ToList();
    var unchanged = stateManager.GetObjectStateEntries(EntityState.Unchanged).ToList();

    while ((entity = _entitiesRequiringTriggering.FirstOrDefault(x => x.Value).Key) != null)
    {
        _entitiesRequiringTriggering[entity] = false;
        var entry = ChangeTracker.Entries<IEntity>().SingleOrDefault(x => x.State != EntityState.Unchanged && x.Entity == entity);
        if (entry == null) continue;
        var trigger = Triggers.Triggers.GetTriggerForEntity(entry.Entity, this);
        if (trigger == null) continue;
        trigger.BeforeSave(entry.Entity);
        switch (entry.State)
        {
            case EntityState.Added:
                trigger.BeforeAdd(entry.Entity);
                break;
            case EntityState.Modified:
                trigger.BeforeUpdate(entry.Entity);
                break;
            case EntityState.Deleted:
                trigger.BeforeDelete(entry.Entity);
                break;
        }
    }
    return base.SaveChanges();
}

請注意添加更新刪除更改的四個變量。 根據我到目前為止所發現的,GetObjectStateEntries應該返回ObjectStateEntry的集合,該集合具有IsRelationship屬性。

我在測試應用程序中運行以下代碼:

using (var db = container.Resolve<IDatabaseContext>())
{
    var cus = db.Query<Customer>().Single(x => x.Id == 1);
    var newAddress = db.Query<Address>().Single(x => x.Id == 5);

    cus.Address = newAddress; //also sets the foreign key property Customer.AddressId to its new corresponding value
    db.SaveChanges();
}

當我在調用之后檢查SaveChanges中的代碼時,我得到了預期的結果: 更新列表中的一個結果,Customer對象。 但在任何時候,我都沒有獲得關系(一對一)Customer_Address的ObjectStateEntry。

我需要能夠在關系發生變化時如前所述進行檢測。 對於正常的標量屬性,您可以這樣做:

var changed = DbEntry.Property(x => x.Name).OriginalValue == DbEntry.Property(x => x.Name).CurrentValue;

但對於不明顯起作用的參考屬性。 有任何想法嗎?

您可以使用此ExtensionMethod獲取已更改的關系列表

public static class DbContextExtensions
{
    public static IEnumerable<Tuple<object, object>> GetRelationships(
        this DbContext context)
    {
        return GetAddedRelationships(context)
                .Union(GetDeletedRelationships(context));
    }

    public static IEnumerable<Tuple<object, object>> GetAddedRelationships(
        this DbContext context)
    {
        return GetRelationships(context, EntityState.Added, (e, i) => e.CurrentValues[i]);
    }

    public static IEnumerable<Tuple<object, object>> GetDeletedRelationships(
        this DbContext context)
    {
        return GetRelationships(context, EntityState.Deleted, (e, i) => e.OriginalValues[i]);
    }

    private static IEnumerable<Tuple<object, object>> GetRelationships(
        this DbContext context,
        EntityState relationshipState,
        Func<ObjectStateEntry, int, object> getValue)
    {
        context.ChangeTracker.DetectChanges();
        var objectContext = ((IObjectContextAdapter)context).ObjectContext;

        return objectContext.ObjectStateManager
                            .GetObjectStateEntries(relationshipState)
                            .Where(e => e.IsRelationship)
                            .Select(
                                    e => Tuple.Create(
                                            objectContext.GetObjectByKey((EntityKey)getValue(e, 0)),
                                            objectContext.GetObjectByKey((EntityKey)getValue(e, 1))));
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM