對於審計日誌記錄的目的,我需要獲取所有列的值,包括已修改爲數據庫中某個表的FK實體和關係實體。數據庫基本上是一個用戶可以上傳資源(文件,在線文檔,圖片等)的網站,我有一個名爲Material
的表格,它具有多個many-2-many和one-2-one關係,如Material - Audience
,Material - Category
,''材料上傳器「,」材料權限Material -Tags
等。我想記錄發生在Material
的所有變化。例如,如果有人去除材料的標籤,然後我需要登錄:在SaveChanges上使用ObjectContext進行實體框架審計
- [USER12 - 12年12月12日] -
Happy
標籤得到了Crappy
材料中去除。
到目前爲止,我得到這個:我可以得到所有這些修改ObjectStateEntries
,添加,使用刪除:
context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified)
現在,我可以檢查這個ObjectStateEntry
是關係或者不使用:
if (e.IsRelationship) {
HandleRelationshipEntry(e);
}
else {
HandleEntry(e);
}
在HandleEntry
方法(項不是關係條目),我可以檢查的Entry
類型,在我的情況下,它是Material
,所以我上來G:
// We care about only Material which are modifed
if (e.State != EntityState.Modified || !(e.Entity is Material))
return;
有一次,我知道Entry
是Material Entry
型的,我可以用得到的所有已更改爲Material
表中的列:
e.CurrentValues[ARCHIVE_COLUMN].ToString() != e.OriginalValues[ARCHIVE_COLUMN].ToString()
在這一點上,我可以記錄所有非FK更改Material
表。但是,如果列是FK
某些其他entity
,我不能將該值FK
值解析爲相應的Entity
。我只能知道CategoryID
已從42
更改爲76
,但我無法解析Category
本身的名稱。我試着像鑄造DBDataRecord
和CurrentValueRecord
到EntityKey
,但它只是NULL
。有沒有什麼辦法可以使用ObjectStateManager
解決這些FKs
到Entities
?
我的針對參考全碼:
私有類SingleMaterialLogger { MaterialAuditData auditData =新MaterialAuditData(); public void HandleEntity(ObjectStateEntry e,ObjectContext context){ HandlePrimaryTypeChanges(e); HandleComplexTypeChanges(e,context); }
private void HandleComplexTypeChanges(ObjectStateEntry e, ObjectContext c) {
// Owner, Category, Contact
ChangeValueHelper(e, CONTACT_COLUMN, (k1, k2) => {
// get old value
User old = c.GetObjectByKey(k1) as User;
User current = c.GetObjectByKey(k2) as User;
});
}
public void HandlePrimaryTypeChanges(ObjectStateEntry e) {
// Name, Description, ArchiveDate, Status
// Again no reflection is used - So change them if column name changes
ChangeValueHelper<string>(e, NAME_COLUMN, (change) => auditData.Name = change);
ChangeValueHelper<string>(e, NAME_COLUMN, (change) => auditData.Description = change);
// TODO - Fix change value helper
if (e.CurrentValues[ARCHIVE_COLUMN].ToString() != e.OriginalValues[ARCHIVE_COLUMN].ToString()) {
auditData.ArchiveDate = new Change<DateTime?>(e.OriginalValues[ARCHIVE_COLUMN] as DateTime?, e.CurrentValues[ARCHIVE_COLUMN] as DateTime?);
}
}
private void ChangeValueHelper(ObjectStateEntry e, string columnName, Action<EntityKey, EntityKey> func) {
if (e.CurrentValues[columnName].ToString() != e.OriginalValues[columnName].ToString()) {
func(e.OriginalValues[columnName] as EntityKey, e.CurrentValues[columnName] as EntityKey);
}
}
private void ChangeValueHelper<T>(ObjectStateEntry e, string columnName, Action<Change<T>> func) where T : class {
if(e.CurrentValues[columnName].ToString() != e.OriginalValues[columnName].ToString()) {
func(new Change<T>(e.OriginalValues[columnName] as T, e.OriginalValues[columnName] as T));
}
}
}
Dictionary<EntityKey, SingleMaterialLogger> singleMaterialLoggerMap = new Dictionary<EntityKey, SingleMaterialLogger>();
private ObjectContext context;
public MaterialAuditLogger(ObjectContext context) {
this.context = context;
}
public void AuditMaterialChanges() {
// Grab everything thats being added/deleted/modified
foreach(var e in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified)) {
if (e.IsRelationship) {
HandleRelationshipEntity(e);
}
else {
HandleEntity(e);
}
}
}
private void HandleEntity(ObjectStateEntry e) {
// We care about only Material which are modifed
if (e.State != EntityState.Modified || !(e.Entity is Material))
return;
var logger = SingleLogger(e.EntityKey);
logger.HandleEntity(e, context);
}
private void HandleRelationshipEntity(ObjectStateEntry e) {
// relations whose entity keys contains
}
private SingleMaterialLogger SingleLogger(EntityKey key) {
if(singleMaterialLoggerMap.ContainsKey(key))
return singleMaterialLoggerMap[key];
SingleMaterialLogger logger = new SingleMaterialLogger();
singleMaterialLoggerMap[key] = logger;
return logger;
}