尝试使用实体上下文中的SavingChanges事件在entityframework 4.0中实现一些通用日志记录。
我想记录有关任何创建/更新和已删除记录的详细信息,包括要更改的记录的ID(始终为int标识字段)。在更新和删除过程中,我可以使用
获取记录的ID Dim AddedItems = Statemanager.GetObjectStateEntries(EntityState.Added)
For Each entry As ObjectStateEntry In DirectCast(sender, ObjectContext).ObjectStateManager.GetObjectStateEntries(EntityState.Added)
NewLogItem.RecordId = CInt(entry.EntityKey.EntityKeyValues(0).Value.ToString())
Next
但是我显然无法在插入期间获取即将插入记录的id,因为它尚未写入数据库,是否有一个简单的方法呢?
答案 0 :(得分:3)
您可以执行的一个选项是覆盖SaveChanges方法并将SaveChanges调用到基础而不接受对objectcontext的更改。这样您就可以审核ObjectStateManager上的更改。
override void SaveChanges(SaveOptions)
{
context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
//query the object statemanager
}
关键是使用正确的saveoptions将savechanges调用到base。默认值将接受对ObjectStateManager的所有更改,因此所有条目将处于未处理状态,您将无法知道添加,删除或修改的内容。在循环遍历statemanager之后,您可以显式调用AcceptChanges。 我也在书中介绍了这个概念。
12-1调用SaveChanges()时执行代码
答案 1 :(得分:0)
我认为无法在SavingChanges
事件中获取新插入记录的ID,因为在完全触摸数据库并创建ID之前只调用该事件。不幸的是,在保存数据后没有SavedChanges
事件被调用。
一个可能的选择可能是利用ObjectContext的SaveChanges
方法的一个重载是virtual
(或VB中的overridable
)这一事实,即:
public virtual int SaveChanges(SaveOptions options)
(注意:它只在EF 4中是虚拟的,而不是在早期版本中!只有这个重载是虚拟的,SaveChanges的其他两个重载都不是!)
因此,您可以在模型的ObjectContext中覆盖此方法。在这个重写的方法中,您调用基类的SaveChanges,之后您的新实体应该具有您可以记录的数据库中创建的ID。
(这只是一个粗略的想法,我从未测试或使用过这个虚拟过载。我在SavingChanges中构建了一个类似的日志记录机制,因为你刚刚实现并遇到了同样的问题。但这是在EF 3.5中这个虚拟的方法还不存在。最后我在调用SaveChanges之后只在重要的位置记录了Inserts,但当然不是那么“通用”。也许新的虚拟方法现在很有可能改进它。)
修改强>
我的意思更加精确(在C#语法中):
public partial class MyEntitiesContext : ObjectContext
{
// ...
public override int SaveChanges(SaveOptions options)
{
// Log something BEFORE entities are stored in DB
int result = base.SaveChanges(options);
// Log something AFTER entities are stored in DB, especially new entities
// with auto-incrementing identity key which have been inserted in the DB
// should have the final primary key value now
return result;
}
// ...
}
重要的是致电base.SaveChanges(options)
。 (当然,只调用SaveChanges(options)
而base.
不会以StackOverflow结束。)
答案 2 :(得分:0)
这是我最终得到的,不理想的事实是我最终得到了两个saveChanges调用,因此有两个交易,但是无法看到任何其他方式,如果我们在保存之前不记录已删除的项目那么我们就不能在savechanges()之后正确访问它们(实体将不再存在,并且这反映在已删除项目的State Entry中)
Public Function SaveAndLogChanges()As Integer
Dim Statemanager As ObjectStateManager = Me.ObjectStateManager
Dim AddedItems As IEnumerable(Of ObjectStateEntry) = Statemanager.GetObjectStateEntries(EntityState.Added)
Dim UpdatedItems As IEnumerable(Of ObjectStateEntry) = Statemanager.GetObjectStateEntries(EntityState.Modified)
Dim DeletedItems As IEnumerable(Of ObjectStateEntry) = Statemanager.GetObjectStateEntries(EntityState.Deleted)
For Each entry As ObjectStateEntry In UpdatedItems
' dont do anything for any of the log file entries or we will end up in an infinate loop
If (Not entry.EntitySet.Name = "LogItem" And Not entry.EntitySet.Name = "LogTransaction") Then
createLogEntry(LogItemType.ItemType.Modify, entry)
End If
Next
' deleted entities
For Each entry As ObjectStateEntry In DeletedItems
' dont do anything for any of the log file entries or we will end up in an infinate loop
If (Not entry.EntitySet.Name = "LogItem" And Not entry.EntitySet.Name = "LogTransaction") Then
createLogEntry(LogItemType.ItemType.Delete, entry)
End If
Next
' need to save changes here to ensure we have ids for the inserted records
Me.SaveChanges()
' inserted enties
For Each entry As ObjectStateEntry In AddedItems
' dont do anything for any of the log file entries or we will end up in an infinate loop
If (Not entry.EntitySet.Name = "LogItem" And Not entry.EntitySet.Name = "LogTransaction") Then
createLogEntry(LogItemType.ItemType.Insert, entry)
End If
Next
Me.SaveChanges()
Return iRet
End Function