2013-09-05 5 views
2

Я создаю репозиторий для нового приложения, которое использует Entity Framework 5 в качестве исходного источника данных. У меня есть основная операция CRUD, работающая для простых моделей, но я изо всех сил пытаюсь понять, как обновлять связанные объекты при обновлении до объекта exising.Шаблон хранилища с Entity Framework 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, но я не могу заставить обновление работать.

ПОКО

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 

Repository

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 

Проблема

При вызове линии Entry(entity).CurrentValues.SetValues(obj) в методе Attach основные свойства копируются, но новые элементы для объекта tblUsermmRole отсутствуют.

Новый объект с обновленной

enter image description here

Entity после SetValues ​​

enter image description here

Из первоначальных исследований он выглядит как метод SetValues не копировать связанных с навигационными свойствами, как описано в this post

Вопрос

Учитывая шаблон репозитория (плюс шаблон UnitOfWork), который я использую, как вы поддерживаете отношения между объектным графом и обновляете базу данных?

Дополнительное примечание

Этот метод работает, как ожидалось для новых экземпляров tblUsers объекта с прикрепленными tblUsermmRoles. Записи для обеих таблиц добавляются с сохранением внешних ключей.

ответ

1

Я нахожу это довольно удивительно, что Entity Framework уже не поддерживает это, но, как обычно, сообщество пришло на помощь с RefactorThis' GraphDiff, которые могут быть загружены через their GitHub repository

Похоже, команда Entity Framework будет смотреть на эту функциональность после EF6 как его в настоящее время номер 2 on there issue list и Роуэн Миллер, кажется, думают его хорошую идею

RoMiller написал 14 фев в 11:15 PM

EF Team Сортировка: Мы согласны с й при этом было бы хорошим сценарием. Принимая во внимание, что мы находимся в выпуске EF6 вместе с размером и влиянием этой функции, наша команда не планирует реализовать ее в EF6. Поэтому мы переходим к выпуску Future , чтобы пересмотреть его в следующей версии.

В настоящее время RefactorThis' GraphDiff решает большинство случаев использования. Благодаря Brent

Обновленный метод выглядит как ниже

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

В принципе, в инфраструктуре Entity отсутствует возможность сделать это. Или сказать лучше, ему не хватает надлежащего оптимизированного способа сделать это.

Скажите, что у вас есть Пользователь, который имеет 4 роли, и вы хотите удалить 1 и добавить 2 новых.

При выборе пользователя вам необходимо загрузить соответствующее навигационное свойство, чтобы ваша коллекция ролей была заполнена. Затем вы удаляете роли с классическим удалением из коллекции и добавляете новые роли с помощью Add.

После того, как вы нажмете SaveChanges, роли, которые были удалены, будут удалены из базы данных (если от 1 до многих) или по крайней мере многие из двух отношений будут удалены. Новые роли будут сохранены - отношения m2m будут обновлены.

Обычно это нормально для небольшого набора сущностей.

Однако предположим, что пользователь имеет 100 000 друзей и вы хотите удалить его из коллекции. Ясно, что загрузка 100 000 только для удаления 1 является совершенно странной, и именно здесь Entity Framework не является хорошим решением (или, по крайней мере, я не знаком с ней).

В таких сценариях, как выше, я скорее нацеливаю прямые отношения, запрашивая его как с идентификатором пользователя, так и с идентификатором друга, вместо того, чтобы вытаскивать список всех друзей и работать с этой коллекцией.

Существует также более быстрый способ выполнения команды ESQL с DbContext.Database.ExecuteSqlCommand для отправки команд обновления и удаления партии. Имейте в виду, что Entity Framework не отслеживает эти изменения, поэтому ваш DbContext не будет знать, что вы обновили enything.

Надеюсь, это разъяснение поможет вам хотя бы немного.

Смежные вопросы