对于审计日志记录的目的,我需要获取所有列的值,包括已修改为数据库中某个表的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;
}