【发布时间】:2015-01-09 16:22:04
【问题描述】:
我正在尝试在我的 dbContext 中的各种表中实现各种审计跟踪。
我希望将现有记录标记为“旧”,并将生成的新记录标记为“当前”(与进行更改的用户一起记录),而不是任何更改被 SaveChanges 覆盖。因此,这给了我各种各样的审计线索。
我目前的方法是覆盖/重载 SaveChanges,然后使用 ChangeTracker 条目:
Public Overrides Function SaveChanges() As Integer
Throw New InvalidOperationException("User ID must be provided")
End Function
Public Overloads Function SaveChanges(userID As String) As Integer
Dim recordsUpdated as integer=0
For Each entry As dbentityentry In Me.ChangeTracker.Entries().Where(Function(e) e.State <> EntityState.Unchanged)
Dim Original As DbPropertyValues = entry.OriginalValues
Dim Current As DbPropertyValues = entry.CurrentValues
Dim t As Type = entry.Entity.GetType
Dim x = Activator.CreateInstance(t) 'create new entity of same type as original
x=.....
' Am stuck here... I'm trying to create a new record of the same entity type as the original
'which I will then append to the dbContext/entity, set a field as 'current' and save.
'Meanwhile I'll change the old field's status to 'old' and MyBase.SaveChanges that.
Next 'loop through the changes
'record how many fields were different/had changed
For Each PropertyName In Original.PropertyNames
Dim OriginalValue As Object = Original.GetValue(Of Object)(PropertyName)
Dim CurrentValue As Object = Current.GetValue(Of Object)(PropertyName)
If Not Object.Equals(OriginalValue, CurrentValue) Then
recordsUpdated+=1
End If
Next
Next
MyBase.SaveChanges()
'Save journal entries
Return recordsUpdated
End Function
从概念上讲,当我不一定知道实体是什么类型(即我将更改保存到哪个表)时,我正在努力解决如何在实体中创建新记录。
Activator.CreateInstance 是正确的方法吗?还是我必须对每个实体进行测试并对新记录的创建进行硬编码?
更新 1
感谢 hjb 和 Gert,我认为我的思路是正确的 - 我只是没有完全看到我所期望的行为。重载的 SaveChanges 现在是:
Public Overloads Function SaveChanges(userID As Integer) As Integer
Dim recordsUpdated As Integer = 0
For Each entry As dbentityentry In Me.ChangeTracker.Entries().Where(Function(e) e.State <> EntityState.Unchanged)
Dim Original As DbPropertyValues = entry.OriginalValues
Dim Current As DbPropertyValues = entry.CurrentValues
Dim NewValues As DbPropertyValues = Current 'NewValue will go into the brand new record (with status='current')
Dim t As Type = entry.Entity.GetType
Dim EntityDBSet = Me.Set(t)
entry.CurrentValues.SetValues(entry.OriginalValues) '<--we don't actually want to change the old record other than set status to 'old'
Dim NewRow = EntityDBSet.Create 'here's our new row created
NewValues("Creator") = Convert.ToInt64(userID)
NewValues("Status")="Current" '<-- indicates the new current data item
Current("Status")="Old" '<-- indicates it's a previous version
NewRow = NewValues.ToObject '<--- put the NewValues into a row object to add to table
'Now append the newly created row
EntityDBSet.Add(NewRow)
Next
MyBase.SaveChanges() 'save the old row (now with status 'old') together with the newly created row (with status 'current')
Return recordsUpdated
End Function
为了更简洁,我删除了记录计数。
我看到添加了一个新行,但它只是旧行的副本 - 没有对旧的“当前”行进行任何更改,并且新行没有反映对旧行所做的任何更改调用原始 SaveChanges 之前的数据。
这可能与“Dim NewValues As DbPropertyValues = Current”有关吗?我应该以某种方式实例化一个新的 NewValues 吗?如果是的话怎么办?
更新 2 - 已解决!
我曾怀疑我需要为 NewValues 提供一个全新的对象,当然实例化它的方法是使用 .ToObject。所以我有:
Public Overloads Function SaveChanges(userID As Integer) As Integer
Dim recordsUpdated As Integer = 0
For Each entry As dbentityentry In Me.ChangeTracker.Entries().Where(Function(e) e.State <> EntityState.Unchanged)
Dim Original As DbPropertyValues = entry.OriginalValues
Dim Current As DbPropertyValues = entry.CurrentValues
Dim NewValues = Current.ToObject 'NewValue will go into the brand new record (with status='current')
Dim t As Type = entry.Entity.GetType
Dim EntityDBSet = Me.Set(t)
entry.CurrentValues.SetValues(entry.OriginalValues) '<--we don't actually want to change the old record other than set status to 'old'
Current("Status")="Old" '<-- indicates it's a previous version
Dim NewRow = EntityDBSet.Create 'here's our new row created
NewValues("Creator") = Convert.ToInt64(userID)
NewValues("Status")="Current" '<-- indicates the new current data item
NewRow = NewValues.ToObject '<--- put the NewValues into a row object to add to table
'Now append the newly created row
EntityDBSet.Add(NewRow)
Next
MyBase.SaveChanges() 'save the old row (now with status 'old') together with the newly created row (with status 'current')
Return recordsUpdated
End Function
宾果! - 这行得通。
【问题讨论】:
-
所以历史记录总是只有一个?如果是这样,那作为审计跟踪几乎没有用。
-
否 - 永远不会删除记录 - 将记录表所处的每个状态,但只有一个的“状态”为“当前”。进行更新时,“当前”记录设置为“旧”(连同所有先前版本)并创建一个新记录。
-
好的。或许
CurrentValues.ToObject()可以帮到你。 -
好的,非常感谢!我认为这是我需要将值从旧的“更新”行转移到全新的“当前”行。我已经为我的问题添加了更新,因为我仍然没有完全了解我所追求的行为