爲了實現審覈日誌,我在我的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]);
}
}
}
}
我希望這有助於更好地說明我正在努力實現的目標。任何輸入是受歡迎的。
謝謝!
審計只是Id變更有什麼問題?如果你直接在數據庫中進行審計,你也會改變Id。順便說一句。如果你不喜歡它,你爲什麼使用FK協會而不是獨立的協會? – 2011-05-18 21:14:52
我試圖爲最終用戶提供一些比PublisherID更改描述的內容,從b087929b-3221-4c43-916b-ad49066969c8更改爲6372b8b6-1848-4f7a-ada0-d778a5682d67。可能是指向實體的超鏈接。因此,無論是在收集審計日誌數據還是顯示審計日誌時,我都需要弄清楚某個屬性是否是外鍵,以及它指向的是哪種類型的實體。 – LeffeBrune 2011-05-18 21:35:58
我讀過你關於獨立社團的文章,並留下了一種感覺,如果我選擇走這條路線,我可能會在稍後遇到一些問題。最重要的是,如果我決定序列化具有合適外鍵值的POCO實體,可能會派上用場。有了獨立的關聯關係,我需要序列化某些實體圖形以便有用。 – LeffeBrune 2011-05-18 21:38:56