好的,这里发生了很多事情,我不想让你们知道一个很长的代码样本,所以这里有一个摘录......
在我的EF上下文中调用SaveChangesAsync()时,我让它调用此方法来审核每个条目......
async Task Audit(DbEntityEntry<IAmAuditable> entry)
{
try
{
var newAuditEntry = new AuditEntry
{
EntityType = entry.Entity.GetType().Name,
Event = entry.State.ToString(),
SSOUserId = kernel.Get<User>().Id,
EntityId = entry.GetId().ToString(),
EventId = eventId
};
如果有问题的条目是实体创建,将导致db i上的插入,那么也会这样做...
var properties = entry.CurrentValues.PropertyNames.Select(p => entry.Property(p)).ToList();
var addedValues = new List<AuditDataItem>();
foreach (var p in properties)
{
addedValues.Add(new AuditDataItem
{
PropertyName = p.Name,
PreviousValue = null,
NewValue = p.CurrentValue.ToString()
});
}
newAuditEntry.Changes = addedValues;
break;
......这就是它落空的地方......在那个时候,对SaveChanges的基本调用还没有被执行,所以有问题的实体还没有主键值......最终结果是我记录了没有主要实体的创建。
有没有人有一个很好的干净方法来处理这个问题,所以我可以把新的主键值放到AuditDataItem中?
编辑:
以下是我作为json记录的一个示例,这是一个AuditEntry对象和一些子AuditDataItem行的一部分......
{
"Id": 4,
"SSOUserId": 1,
"EventId": "6d862aad-0898-4794-aea0-00af6f2994ff",
"EntityType": "AC_Programme",
"Event": "Added",
"TimeOfEvent": "2016-02-04T12:04:31.5501508+01:00",
"Changes": [
{
"Id": 34,
"PropertyName": "Id",
"PreviousValue": null,
"NewValue": "0"
},
{
"Id": 35,
"PropertyName": "Name",
"PreviousValue": null,
"NewValue": "Test"
},
...
]
}
答案 0 :(得分:1)
据我所知,在创建对象后没有事件可以截取对象创建。有以下活动:
第一个发生在保存更改之前(您遇到同样的问题)。第二个是在查询结果或.Load
从数据库中读取实体时发生的,因此它不适合您的情况。
我能想到的唯一解决方案是覆盖原始的SaveChanges,并在重写的方法中执行此操作:
List<Object>
Logging and Intercepting Database Operations (EF6 Onwards)不符合您的需求
答案 1 :(得分:1)
您需要在AuditEntry中保留ObjectStateEntry,然后重新访问主键为&#34; Temporary&#34;的每个AuditEntry。在PostSaveChanges事件中。
以下是一个例子:
显然,我建议您使用EF + Audit而不是创建自己的库,但如果您仍想编写代码,那么该库是开源的,因此您可以找到很多信息来帮助您。
免责声明:我是该项目的所有者EF+ (EntityFramework Plus)
答案 2 :(得分:0)
好的,这就是我想出来的......好奇地想知道你们的想法......
public override async Task<int> SaveChangesAsync()
{
try
{
await AuditChanges(new[] { EntityState.Modified, EntityState.Deleted });
var result = await base.SaveChangesAsync();
await AuditChanges(new[] { EntityState.Added });
return result;
}
catch (DbEntityValidationException ex) { throw ConstructDetailsFor(ex); }
}
async Task AuditChanges(EntityState[] states)
{
var auditableEntities = ChangeTracker.Entries<IAmAuditable>()
.Where(e => states.Contains(e.State));
foreach (var entry in auditableEntities)
await Audit(entry);
}
async Task Audit(DbEntityEntry<IAmAuditable> entry)
{
...
这很简单:)
我的审计方法然后基本上进入switch语句,并根据来自更改跟踪器的传入的可审计实体条目决定运行什么逻辑。
我认为审计不会比这简单得多。
我把它放到我所有EF上下文的通用基类中,然后运行迁移将其应用到所有数据库和bang ...各处获得动态,自动审核所有标有“IAmAuditable”的实体(空标记界面。
我考虑过使用属性,但这需要反思而不是。