7

爲了實現審覈日誌,我在我的DbContext上重寫了SaveChanges。使用多對多關係或獨立關聯相對容易,因爲EF爲這些類型關係的任何更改創建了ObjectStateEntries。實體框架:跟蹤對FK關聯的更改

我正在使用外鍵關聯,當實體之間的關係發生變化時,您得到的是一個ObjectStateEnty,例如實體「Title」具有「PublisherID」屬性。對於人來說,這顯然是Title實體中的一個外鍵,但是我如何在運行時確定它呢?有沒有辦法將這個改變轉換爲「PublisherID」屬性來讓EntityKey爲外鍵所代表的實體?

我認爲我處理看起來像這樣的實體:

public sealed class Publisher 
{ 
    public Guid ID { get; set; } 
    public string Name { get; set; } 
    public ICollection<Title> Titles { get; set; } 
} 

public class Title 
{ 
    public Guid ID { get; set; } 
    public string Name { get; set; } 
    public Guid? PublisherID { get; set; } 
    public Publisher Publisher { get; set; } 
} 

還有EF EntityConfiguration代碼定義的關係和外鍵:

public TitleConfiguration() 
{ 
    HasOptional<Publisher>(t => t.Publisher).WithMany(
      p => p.Titles).HasForeignKey(t => t.PublisherID); 
} 

我在做什麼現在看起來有點太複雜了。我希望有更優雅的方式來實現我的目標。對於來自ObjectStateEntry的每個修改後的屬性,我將查看當前實體的所有ReferentialConstraints,並查看是否有任何人使用它作爲外鍵。下面的代碼被稱爲SaveChanges():

private void HandleProperties(ObjectStateEntry entry, 
     ObjectContext ctx) 
{ 
    string[] changedProperties = entry.GetModifiedProperties().ToArray(); 
    foreach (string propertyName in changedProperties) 
    { 
     HandleForeignKey(entry, ctx, propertyName); 
    } 
} 

private void HandleForeignKey(ObjectStateEntry entry, 
     ObjectContext ctx, string propertyName) 
{ 
    IEnumerable<IRelatedEnd> relatedEnds = 
      entry.RelationshipManager.GetAllRelatedEnds(); 

    foreach (IRelatedEnd end in relatedEnds) 
    { 
     // find foreign key relationships 
     AssociationType elementType = end.RelationshipSet.ElementType as 
       AssociationType; 
     if (elementType == null || !elementType.IsForeignKey) continue; 

     foreach (ReferentialConstraint constraint in 
       elementType.ReferentialConstraints) 
     { 
      // Multiplicity many means we are looking at a foreign key in a 
      // dependent entity 
      // I assume that ToRole will point to a dependent entity, don't 
      // know if it can be FromRole 
      Debug.Assert(constraint.ToRole.RelationshipMultiplicity == 
        RelationshipMultiplicity.Many); 
      // If not 1 then it is a composite key I guess. 
      // Becomes a lot more difficult to handle. 
      Debug.Assert(constraint.ToProperties.Count == 1); 
      EdmProperty prop = constraint.ToProperties[0]; 

      // entity types of current entity and foreign key entity 
      // must be the same 
      if (prop.DeclaringType == entry.EntitySet.ElementType 
        && propertyName == prop.Name) 
      { 
       EntityReference principalEntity = end as EntityReference; 
       if (principalEntity == null) continue; 

       EntityKey newEntity = principalEntity.EntityKey; 
       // if there is more than one, the foreign key is composite 
       Debug.Assert(newEntity.EntityKeyValues.Length == 1); 

       // create an EntityKey for the old foreign key value 
       EntityKey oldEntity = null; 

       if (entry.OriginalValues[prop.Name] is DBNull) 
       { 
        oldEntity = new EntityKey(); 
        oldEntity.EntityKeyValues = new[] { 
         new EntityKeyMember("ID", "NULL") 
        }; 
        oldEntity.EntitySetName = newEntity.EntitySetName; 
       } 
       else 
       { 
        Guid oldGuid = Guid.Parse(
          entry.OriginalValues[prop.Name].ToString()); 
        oldEntity = ctx.CreateEntityKey(newEntity.EntitySetName, 
          new Publisher() 
          { 
           ID = oldGuid 
          }); 
       } 

       Debug.WriteLine(
         "Foreign key {0} changed from [{1}: {2}] to [{3}: {4}]", 
         prop.Name, 
         oldEntity.EntitySetName, oldEntity.EntityKeyValues[0], 
         newEntity.EntitySetName, newEntity.EntityKeyValues[0]); 
      } 
     } 
    } 
} 

我希望這有助於更好地說明我正在努力實現的目標。任何輸入是受歡迎的。

謝謝!

+0

審計只是Id變更有什麼問題?如果你直接在數據庫中進行審計,你也會改變Id。順便說一句。如果你不喜歡它,你爲什麼使用FK協會而不是獨立的協會? – 2011-05-18 21:14:52

+0

我試圖爲最終用戶提供一些比PublisherID更改描述的內容,從b087929b-3221-4c43-916b-ad49066969c8更改爲6372b8b6-1848-4f7a-ada0-d778a5682d67。可能是指向實體的超鏈接。因此,無論是在收集審計日誌數據還是顯示審計日誌時,我都需要弄清楚某個屬性是否是外鍵,以及它指向的是哪種類型的實體。 – LeffeBrune 2011-05-18 21:35:58

+0

我讀過你關於獨立社團的文章,並留下了一種感覺,如果我選擇走這條路線,我可能會在稍後遇到一些問題。最重要的是,如果我決定序列化具有合適外鍵值的POCO實體,可能會派上用場。有了獨立的關聯關係,我需要序列化某些實體圖形以便有用。 – LeffeBrune 2011-05-18 21:38:56

回答

1

看起來像我的代碼是正確的解決了這個問題:/

我沒有最終使用獨立的協會,以完全避免這個問題。