DbContext vs ObjectContext — изменение поведения свойства навигации

Я переношу большой проект из ObjectContext в DbContext, EF6.1.3. Просто столкнулся с проблемой, которую будет трудно надежно отследить в исходном коде, и мне интересно, может ли быть подход, с помощью которого я могу имитировать поведение ObjectContext.

Рассмотрим два класса, Parent и Child. Родитель имеет ноль или более дочерних объектов. На уровне таблицы у Child есть столбец ParentID, который находится в отношении FK со столбцом ID в родительском объекте. Вот два класса POCO, которые я создал, чтобы проиллюстрировать проблему:

Partial Public Class Parent
    Public Property ID As Integer

    Public Overridable Property Children As ICollection(Of Child) = New HashSet(Of Child)

End Class

Partial Public Class Child
    Public Property ID As Integer
    Public Property ParentID As Integer

    Public Overridable Property Parent As Parent

End Class

и вот небольшая программа для иллюстрации проблемы:

  Sub Main()
    Using session As New testEntities
      Dim parent = session.Parents.Add(session.Parents.Create)
      Dim child = session.Children.Create
      parent.Children.Add(child)
      Console.WriteLine(child.Parent Is Nothing)
      session.SaveChanges()
      Console.WriteLine(child.Parent Is Nothing)
    End Using

В реализации ObjectContext добавление дочернего элемента к родительскому также задает свойство родительского элемента дочернего элемента. С DbContext этого не происходит до тех пор, пока сеанс не будет зафиксирован.

В коде, который я переношу, есть несколько мест (которые мы нашли до сих пор), где коду будет передан эквивалент объекта Child, который был добавлен к Parent, а затем попытка сослаться на объект Parent через свойство Parent ребенка . Они компилируются правильно, но поведение во время выполнения «сломано» с DbContext. Поиск всех таких случаев, когда используется этот шаблон, будет дорогостоящим, и будет очень легко пропустить случаи, которые затем вызовут проблемы во время выполнения. Может ли кто-нибудь предложить обходной путь, который позволит коду работать как есть? Я предполагаю, что мы могли бы изменить файл TT, чтобы сгенерировать наш собственный класс вместо HashSet для свойства Children, реализовать конструктор, который принимает ссылку на зависимое свойство, и метод Add, который обновляет зависимое свойство. Прежде чем мы пойдем по этому пути, есть ли что-то более простое, что мы могли упустить?


person Kevin O'Donovan    schedule 12.04.2017    source источник
comment
Я не думаю, что это связано с ObjectContext или DbContext, но с классом сущностей (POCO против специального). Вы хотите сказать, что использовали одни и те же классы сущностей с ObjectContext?   -  person Ivan Stoev    schedule 12.04.2017
comment
В какой-то степени это верно — с ObjectContext свойства навигации поддерживаются типом EntityCollection, но с DbContext сама сущность обернута прокси-сервером, что дало бы еще одну возможность сделать что-то подобное.   -  person Kevin O'Donovan    schedule 13.04.2017
comment
Да, и нет, классы не совпадают в обоих случаях, но они оба создаются с помощью связанных файлов TT.   -  person Kevin O'Donovan    schedule 13.04.2017
comment
Таким образом, в основном разница заключается в специальном классе EntityCollection, используемом в старом сценарии, и в обычном типе коллекции CLR, используемом во втором. В то время как прокси может перехватывать доступ к виртуальному свойству, он не может перехватывать коллекцию Add / Remove и т. д. Таким образом, исправление свойства навигации DbContext происходит в некоторых контекстных операциях — SaveChanges, DbSet.Add и т. д. Проблема в том, что код сначала добавляет родителя в базу данных set, затем добавляет детей. Вероятно, вам нужно пойти по пути, который вы указали.   -  person Ivan Stoev    schedule 13.04.2017
comment
Да, это то, что я сделал. Вроде нормально работает. В долгосрочной перспективе мне нужно придумать способ определить весь код, который использует этот шаблон, и заменить его.   -  person Kevin O'Donovan    schedule 13.04.2017


Ответы (1)


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

ChangeTracker.DetectChanges()

Если это приведет к тому, что вы хотите, вы можете создать свой собственный DbSet, который будет вызывать его автоматически всякий раз, когда вызывается Add... Даже если вам нужно затенить метод Add. (Надеюсь, это просто событие, с которым вы можете справиться.)

person Daniel Lorenz    schedule 13.04.2017
comment
DetectChanges работает. Я еще не пытался интегрировать его в решение, так как я уже написал подход, который создает подклассы HashSet. - person Kevin O'Donovan; 17.04.2017