這是一個更概念性的問題。這是我目前的困境;我正在編寫一個vb.net WPF應用程序並使用MVVM模式(愛它!可維護性只是非常棒)。目前所有代碼都是手工編寫的,並且沒有使用NHibernate或實體框架,因爲後端是一個訪問數據庫(由於策略我不能使用NH並且EF不支持JET數據庫,我們可能會在某些時候切換到MSSQL但從現在開始可能會有一段時間)。以最大效率更新MVVM模式記錄的正確方法
應用程序運行良好,想知道將更新發送回數據庫的最佳方式是什麼。
目前該方法是添加布爾到模型的設置部分的記錄「髒」,然後當更新被按下時,我們遍歷所有「髒」的記錄並使用oledbcommand(使用參數執行)要更新的sql語句。
這創建了一個很好的問題分離,但如果這是錯誤的方式,我想知道替代方法(請注意數據庫類型和相關的缺點,例如它不適用於EF)。
謝謝!
最終代碼在VB.NET評論等後:
Public Class Car
Implements ICloneable
Public Property Make() As String
Get
Return m_Make
End Get
Set(ByVal value As String)
m_Make = value
End Set
End Property
Private m_Make As String
Public Property Model() As String
Get
Return m_Model
End Get
Set(ByVal value As String)
m_Model = value
End Set
End Property
Private m_Model As String
Public Function Clone() As Object Implements System.ICloneable.Clone
Return New Car() With { _
.Make = Me.Make, _
.Model = Me.Model _
}
End Function
End Class
Public Class CarEqualityComparer
Implements IEqualityComparer(Of Car)
Public Overloads Function Equals(ByVal x As Car, ByVal y As Car) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Car).Equals
Return x.Make = y.Make AndAlso x.Model = y.Model
End Function
Public Overloads Function GetHashCode(ByVal obj As Car) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Car).GetHashCode
Return 1 'http://blogs.msdn.com/b/jaredpar/archive/2008/06/03/making-equality-easier.aspx
End Function
End Class
Public Class CarRepository
Private _carComparator As New CarEqualityComparer
Private _cars As New ChangeTracker(Of Car)(_carComparator)
Public Function GetCars() As IEnumerable(Of Car)
'TODO: JET/ADO code here, you would obviously do in a for/while loop
Dim dbId1 As Integer = 1
Dim make1 As String = "Ford"
Dim model1 As String = "Focus"
Dim dbId2 As Integer = 2
Dim make2 As String = "Hyundai"
Dim model2 As String = "Elantra"
'TODO: create or update car objects
Dim car1 As Car
If Not _cars.IsTracking(dbId1) Then
car1 = New Car()
Else
car1 = _cars.GetItem(dbId1)
End If
car1.Make = make1
car1.Model = model1
If Not _cars.IsTracking(dbId1) Then
_cars.StartTracking(dbId1, car1)
End If
Dim car2 As Car
If Not _cars.IsTracking(dbId2) Then
car2 = New Car()
Else
car2 = _cars.GetItem(dbId2)
End If
car2.Make = make2
car2.Model = model2
If Not _cars.IsTracking(dbId2) Then
_cars.StartTracking(dbId2, car2)
End If
Return _cars.GetTrackedItems()
End Function
Public Sub SaveCars(ByVal cars As IEnumerable(Of Car))
'TODO: JET/ADO code here to update the item
Console.WriteLine("Distinct " & cars.Distinct.Count.ToString)
For Each changedItem As Car In _cars.GetChangedItems().Intersect(cars)
Console.Write("Saving: ")
Console.WriteLine(changedItem.Make)
Next
For Each newItem As Car In cars.Except(_cars.GetTrackedItems())
Console.Write("Adding: ")
Console.WriteLine(newItem.Make)
Dim newId As Integer = CInt(Math.Ceiling(Rnd() * 5000)) 'Random right now but JET/ADO to get the id later....
_cars.StartTracking(newId, newItem)
Next
Dim removalArray As New ArrayList
For Each deletedItem As Car In _cars.GetTrackedItems().Except(cars)
Console.Write("Removing: ")
Console.WriteLine(deletedItem.Make)
removalArray.Add(_cars.GetId(deletedItem)) 'Cannot remove right as iterating through array - clearly that would be problematic....
Next
For Each dbId As Integer In removalArray
_cars.StopTracking(dbId)
Next
_cars.SetNewCheckpoint()
End Sub
End Class
Public Class ChangeTracker(Of T As {ICloneable})
'item "checkpoints" that are internal to this list
Private _originals As New Dictionary(Of Integer, T)()
Private _originalIndex As New Dictionary(Of T, Integer)()
'the current, live-edited objects
Private _copies As New Dictionary(Of Integer, T)()
Private _copyIndex As New Dictionary(Of T, Integer)()
Private _comparator As System.Collections.Generic.IEqualityComparer(Of T)
Public Sub New(ByVal comparator As System.Collections.Generic.IEqualityComparer(Of T))
_comparator = comparator
End Sub
Public Function IsChanged(ByVal copy As T) As Boolean
Dim original = _originals(_copyIndex(copy))
Return Not _comparator.Equals(copy, original)
End Function
Public Function GetChangedItems() As IEnumerable(Of T)
Dim items As IEnumerable(Of T)
items = _copies.Values.Where(Function(c) IsChanged(c))
Return items
End Function
Public Function GetTrackedItems() As IEnumerable(Of T)
Return _copies.Values
End Function
Public Sub SetNewCheckpoint()
For Each copy In Me.GetChangedItems().ToList()
Dim dbId As Integer = _copyIndex(copy)
Dim oldOriginal = _originals(dbId)
Dim newOriginal = DirectCast(copy.Clone(), T)
_originals(dbId) = newOriginal
_originalIndex.Remove(oldOriginal)
_originalIndex.Add(newOriginal, dbId)
Next
End Sub
Public Sub StartTracking(ByVal dbId As Integer, ByVal item As T)
Dim newOriginal = DirectCast(item.Clone(), T)
_originals(dbId) = newOriginal
_originalIndex(newOriginal) = dbId
_copies(dbId) = item
_copyIndex(item) = dbId
End Sub
Public Sub StopTracking(ByVal dbId As Integer)
Dim original = _originals(dbId)
Dim copy = _copies(dbId)
_copies.Remove(dbId)
_originals.Remove(dbId)
_copyIndex.Remove(copy)
_originalIndex.Remove(original)
End Sub
Public Function IsTracking(ByVal dbId As Integer) As Boolean
Return _originals.ContainsKey(dbId)
End Function
Public Function IsTracking(ByVal item As T) As Boolean
Return _copyIndex.ContainsKey(item)
End Function
Public Function GetItem(ByVal dbId As Integer) As T
Return _copies(dbId)
End Function
Public Function GetId(ByVal item As T) As Integer
Dim dbId As Integer = (_copyIndex(item))
Return dbId
End Function
End Class
嗨凱文,我只有一半瞭解這一點 - 你能解釋在代碼中實際發生了什麼嗎?有點像敘事? – 2012-03-14 19:50:37
嗨,奧馬爾,我做了一些編輯,我希望這很有幫助。非常短的版本是我們仍然在進行髒跟蹤,除了我們只是在用戶單擊Save時計算哪些對象是髒的,而不是在用戶進行更改時管理髒標誌。 – 2012-03-14 20:09:39
嘿凱文,怎麼樣ovveriding GetHashCode? – 2012-03-19 01:19:13