2013-09-05 73 views
2

我正在爲使用實體框架5作爲後端數據源的新應用程序構建存儲庫。我有簡單模型的基本CRUD操作,但我正在努力瞭解如何更新升級到升級對象的相關對象。使用實體框架的存儲庫模式5.更新相關對象

型號

enter image description here

進口系統 進口System.Collections.Generic

Partial Public Class tblUser 
    Public Property idUser As Integer 
    Public Property username As String 
    Public Property pwd As String 

    Public Overridable Property tblUsermmRoles As ICollection(Of tblUsermmRole) = New HashSet(Of tblUsermmRole) 
End Class 

Imports System 
Imports System.Collections.Generic 

Partial Public Class tblUsermmRole 
    Public Property idUser As Integer 
    Public Property idRole As Integer 

    Public Overridable Property tblUser As tblUser 
    Public Overridable Property tblUserRole As tblUserRole 

End Class 

我試圖記錄添加到tblUsermmRole對象反對相關的tblUser記錄,但我無法使更新工作。

POCO

Public Class User 

    Public Property ID As Int32 
    Public Property Username As String 
    Public Property Password As String 
    Public Property AccessRoles As IEnumerable(Of Int32) 

    Public Sub New() 
    End Sub 

    Public Sub New(id As Int32, userName As String, password As String, roles As List(Of Int32)) 
     Me.ID = id 
     Me.Username = userName 
     Me.Password = password 
     Me.AccessRoles = roles 
    End Sub 

End Class 

Public Class UserRoles 

    Public Property RoleID As Int32 

    Public Sub New(roleID As Int32) 
     Me.RoleID = roleID 
    End Sub 

End Class 

Imports System.Data.Entity 

Namespace DataAccess.Repository 

    Public MustInherit Class EntityFramworkContextBase 
     Inherits DbContext 
     Implements IUnitOfWork 

     Public Sub New(entityConnectionStringOrName As String) 
      MyBase.New(entityConnectionStringOrName) 
     End Sub 

     Public Sub Add(Of T As Class)(obj As T) Implements IUnitOfWork.Add 
      [Set](Of T).Add(obj) 
     End Sub 

     Public Sub Attach(Of T As Class)(obj As T) Implements IUnitOfWork.Attach 

      Dim entity As T 

      If ExistsInContext(obj) Then 
       entity = ObjectInContext(obj) 
       Entry(entity).CurrentValues.SetValues(obj) 

      Else 
       entity = [Set](Of T).Attach(obj) 
      End If 

      Entry(entity).State = EntityState.Modified 

     End Sub 

     Public Sub Commit() Implements IUnitOfWork.Commit 
      MyBase.SaveChanges() 
     End Sub 

     Public Function [Get](Of T As Class)() As IQueryable(Of T) Implements IUnitOfWork.Get 
      Return [Set](Of T)() 
     End Function 

     Public Function Remove(Of T As Class)(obj As T) As Boolean Implements IUnitOfWork.Remove 

      Dim entity As T 

      If ExistsInContext(obj) Then 
       entity = ObjectInContext(obj) 
      Else 
       entity = [Set](Of T).Attach(obj) 
      End If 

      [Set](Of T).Remove(entity) 

      Return True 

     End Function 

     Private Function ExistsInContext(Of T As Class)(obj As T) As Boolean 
      Return [Set](Of T).Local.Any(Function(o) o.Equals(obj)) 
     End Function 

     Private Function ObjectInContext(Of T As Class)(obj As T) As T 
      Return [Set](Of T).Local.FirstOrDefault(Function(o) o.Equals(obj)) 
     End Function 

    End Class 

End Namespace 

問題

Attach方法中調用Entry(entity).CurrentValues.SetValues(obj)行時,將複製基本屬性,但tblUsermmRole對象的新元素不是。

與更新

enter image description here

實體新建對象setValues方法

enter image description here

從它看起來像在this post

討論的 SetValues方法不會對相關導航屬性複製最初的研究後,

問題

鑑於我正在使用的存儲庫模式(加上UnitOfWork模式),您如何維護對象圖關係並更新數據庫?

附加說明

此方法效果如預期的向tblUsers的新實例對象附有tblUsermmRoles。兩個表的記錄都添加了外鍵。

回答

1

我覺得很奇怪,實體框架已經不支持這一點,但像往常一樣在社區已經與RefactorThis' GraphDiff救援可以通過their GitHub repository

看起來像實體框架團隊下載會看看這個功能後EF6作爲其目前數量2 on there issue list和羅恩·米勒似乎認爲它是個好主意

RoMiller在11:15寫道:2月14日下午

EF團隊分流:我們同意日在這將是一個很好的情況下啓用。 考慮到我們在EF6版本中的位置以及 的尺寸以及此功能的影響,我們的團隊不打算在的EF6中實施它。因此,我們將其轉移到未來版本 以在下一版本中重新考慮。

與此同時RefactorThis' GraphDiff解決了大多數的使用案例。由於布倫特

更新的方法出現如下

Public Sub AttachObjectGraph(Of T As Class)(obj As T, mapping As Expression(Of Func(Of IUpdateConfiguration(Of T), Object))) Implements IUnitOfWork.AttachObjectGraph 
     Me.UpdateGraph(obj, mapping) 
End Sub 

與調用方法出現這樣的,指定父 - >子實體映射

_usersRepository.AttachObjectGraph(dbUser, Function(map) map.OwnedCollection(Function(u) u.tblUsermmRoles)) 
_unitOfWork.Commit() 
0

基本上,實體框架缺乏這樣做的能力。或者說更好,它缺乏適當的優化方式來做到這一點。

假設您有一個擁有4個角色的用戶,並且您想刪除1,並添加2個新角色。

您需要在選擇用戶時加載足夠的導航屬性,以便填充角色集合。然後,您使用經典的從集合中刪除來刪除角色,並使用添加添加新角色。

一旦您點擊SaveChanges,已刪除的角色將從數據庫中刪除(如果是1到多個)或者至少有許多2個關係會被刪除。新的角色將被保存 - m2m關係將被更新。

對於一小組實體,這通常是相當不錯的。

但是,假設用戶有100.000個朋友,並且您想從集合中刪除一個。明確加載100.000只是爲了刪除1是完全奇怪的,這是實體框架不是很好的解決方案(或者至少我不熟悉它)。

在上述場景中,我更傾向於通過用戶ID和朋友ID查詢直接關係,而不是拉取所有朋友的列表並對該集合進行操作。

通過使用DbContext.Database.ExecuteSqlCommand執行ESQL命令,還可以更快地發送批量更新和刪除命令。請記住,雖然該實體框架沒有跟蹤這些變化,所以你的DbContext不會意識到你已經更新了東西。

希望這個說明至少可以幫助你一點。