EF5 типы поддерживаемых сущностей

В результате копания во внутренностях EntityFramework я наткнулся на change-tracking proxies, которые с одной стороны натолкнули меня на мысль создания self-tracking objects для обычных объектов с помощью PostSharp. Однако перед началом рассказа о прокси-объектах изменения состояния, стоит рассказать о других классах объектов поддерживаемых  EF. Далее идет их описание в хронологическом порядке, как они был реализованы/введены во фреймворк.

Сущности, наследуемые от EntityObject

Единственный тип сущностей, поддерживаемый в самой первой предварительно реализации EF, были классы наследуемые от класса EntityObject, входящего в пространство имен EF. Наследование от EntityObject предоставляло ряд сервисов, таких как:

  • отслеживание изменений состояния свойств класса,
  • управление связями между сущностями,
  • работа с первичными и вторичными ключами.

Существование такого базового класса позволяло весьма эффективно EF управлять сущностями.

Минусом такого подхода, и очень БОЛЬШИМ минусом , было то, что бизнес-объекты и слой доступа данных (EF) были связаны более чем тесно, к тому же это нарушает принцип persistence-ignorance, т.е. объект не должен знать и завязываться на то как именно он сохраняется. Это была одна из причин, по которой я долгое время игнорировал и не стремился использовать в работе Entity Framework. К тому же, на практике, наследование от EntityObject делало работу с бизнес-объектами сложнее и полной специфичного для EF кода.

Сущности, наследуемые от EntityObject поддерживаются EF1 и EF4, но не DbContext и CodeFirst, которые были введены в версиях EF4.x.

IPOCO сущности

Класс EntityObject прошел некоторый рефакторинг перед тем, как EF1 вошел в релиз .Net 3.5 SP1. В результате рефакторинга были выделены три интерфейса:

  • IEntityWithRelationships
  • IEntityWithChangeTracker
  • IEntityWithKey

Все вместе они стали известны как IPOCO интерфейсы. Основным желанием было предоставить некоторый уровень абстракции для разделения бизнес-сущностей и EF. Реальность оказалась суровее и связь объектов все еще оставалась, ко всему прочему интерфейсы было достаточно тяжело реализовать правильно, что в итоге приводило людей либо к созданию своих собственных EntityObject, либо возвращало к оригинальному базовому классу.

IPOCO сущности в теории должны поддерживаться всеми версиями EF.

POCO сущности

Акроним POCO расшифровывается как «Plain Old CLR Object» и обозначают объекты которые ни с чем не связаны. Они не обязаны наследоваться от каких-либо классов, реализовывать какие-либо интерфейсы или ссылаться на что-либо особенное, кроме стандартных CLR классов.

Поддержка POCO объектов критично важна для осуществления принципа persistence-ignorance – отчуждения бизнес-сущностей от слоя доступа данных. Работа с POCO была введена как главная фича в EF4 и продолжает поддерживаться в последующих версиях.

Прокси ленивой загрузки

Отчуждение бизнес-сущностей от слоя данных (EF), которое стало возможно с введением поддержки POCO –  отличная вещь! Но всему есть цена – бизнес-сущности не имеют больше доступа к инфраструктуре EF для выполнения некоторых полезных действий. Одной из таких полезных вещей является ленивая загрузка связанных сущностей при первом обращении к ним. Но класс не может попросить загрузить связанную с ним коллекцию, если у него нет доступа к EF.

Прокси класс для ленивой загрузки позволяет решить указанную проблему связи путем генерирования специальных классов, наследуемых от POCO объектов, во время исполнения кода. Эти, динамически сгенерированные классы, связаны с EF и перегружают виртуальные свойства навигации (свойства с коллекциями связанных объектов или свойства связи с другими сущностями отображаемыми на БД) так, чтобы была возможность перехватить обращение к ним и запустить механизм загрузки данных. Конкретный экземпляр такого сгенерированного класса будет возвращен вызывающему коду вместо первоначального POCO объекта.

Работа с прокси была введена совместно с POCO в EF4 и продолжает поддерживаться в последующих версиях. Шаблоны Т4 для DbContext могут генерировать сущности, которые действуют как прокси для ленивой загрузки.

Прокси отслеживания изменений

Одной из ключевых особенностей EF является отслеживание изменений в сущностях и их взаимосвязей так, чтобы при вызове метода SaveChanges() обновления, которые пойдут на запись в базу данных были корректны. Для большинства POCO сущностей, включая прокси ленивой загрузки, механизмом отслеживания изменений является создание и работа с первоначальным «снимком» объекта (snapshot). «Снимок» состояния объекта создается в момент его материализации в контексте и затем «снимок» сравнивается с текущим графом состояний объектов для определения  что именно и как изменилось.

Отслеживание изменений с помощью «снимков» работает замечательно, однако есть такие ситуации когда необходимо получать данные об изменениях сразу, как только они произошли. Для этого и существуют прокси отслеживания изменений. Они создаются и выглядят почти так же как и прокси ленивой загрузки за исключением того, что каждое свойство (get и set) должны быть виртуальными – только в этом случае сработает прокси. С помощью такой реализации каждое изменение будет обнаружено в тот же самый момент.

Интересен способ, как прокси отслеживают изменения. Для реализации они используют два интерфейса упомянутых выше, это:  IEntityWithChangeTracker для отслеживания изменений в скалярных свойствах и IEntityWithRelationships для отслеживания изменений в связях между объектами. Именно по этой причине вы можете встретить код, который проверяет наличие данных интерфейсов у класса, чтобы определить будет ли целевой класс действовать как прокси отслеживания изменений.

Итого

EF1 (в .Net 3.5 SP1) поддерживал только классы наследованные от EntityObject и IPOCO. Ни один из этих способов работы больше не используется при работе с DbContext в версиях EF4.x. Начиная с EF4 и выше появилась поддержка POCO, включая поддержку ленивой загрузки и прокси отслеживания изменений.

Конечно, сейчас вас может начать мучать вопрос, что же лучше всего использовать, но на это нет четкого ответа.  Хотя выбор и сузился до 2х опций: POCO и прокси отслеживания изменений. Про POCO все ясно и так, стоит наверно поподробнее рассказать про прокси отслеживания изменений. Но отложим это до следующего поста.

По мотивам статей Артура Викерса.

 

 

Hard’n’Heavy

 

Violet Tape

 

 

Оставить комментарий