Entity Framework как репозиторий и UnitOfWork? - PullRequest
18 голосов
/ 06 февраля 2009

Я начинаю новый проект и решил попробовать включить шаблоны DDD, а также включить Linq to Entities. Когда я смотрю на ObjectContext EF, кажется, что он выполняет функции шаблонов Repository и Unit of Work:

Репозиторий в том смысле, что базовый интерфейс уровня данных абстрагирован от представления сущности, и я могу запрашивать и сохранять данные через ObjectContext.

Единица работы в том смысле, что я могу записать все свои вставки / обновления в objectContext и выполнить их все за один раз, когда я выполняю SaveChanges ().

Кажется излишним помещать другой слой этих шаблонов поверх EF ObjectContext? Также кажется, что классы Model могут быть включены непосредственно поверх сгенерированных EF сущностей, используя «частичный класс».

Я новичок в DDD, поэтому, пожалуйста, дайте мне знать, если я что-то упустил здесь.

Ответы [ 3 ]

17 голосов
/ 06 февраля 2009

Я не думаю, что Entity Framework является хорошей реализацией Repository, потому что:

  • Контекст объекта недостаточно абстрактен, чтобы проводить хорошее модульное тестирование вещей, которые на него ссылаются, поскольку он связан с доступом к БД. Вместо этого ссылка на IRepository работает намного лучше для создания модульных тестов.
  • Когда у клиента есть доступ к ObjectContext, он может делать практически все, что ему нужно. Единственный реальный контроль над этим - сделать определенные типы или свойства приватными. Сложно реализовать хорошую защиту данных таким образом.
  • В нетривиальной модели ObjectContext недостаточно абстрактен. Например, у вас могут быть таблицы и хранимые процедуры, сопоставленные с одним и тем же типом сущности. Вы на самом деле не хотите, чтобы клиент различал эти два отображения.
  • В соответствующей заметке сложно написать всеобъемлющие и надежные бизнес-правила и код сущностей. Действительно, независимо от того или нет, это даже хорошая идея спорна.

С другой стороны, , если у вас есть ObjectContext, реализация шаблона репозитория тривиальна. Действительно, для случаев, которые не являются особенно сложными, репозиторий представляет собой оболочку вокруг типов ObjectContext и Entity.

7 голосов
/ 06 февраля 2009

Я бы сказал, что вы должны смотреть на ObjectContext как на свой UnitOfWork, а не на репозиторий.

ObjectContext не может быть репозиторием -imho-, поскольку он является «универсальным». Вы должны создать свои собственные репозитории, которые имеют специализированные методы (например, GetCustomersWithGoldStatus) рядом с обычными методами CRUD.

Итак, что я бы сделал, это создаю репозитории (по одному для каждого агрегатного корня), и пусть эти репозитории используют ObjectContext.

0 голосов
/ 13 декабря 2012

Мне нравится иметь слой хранилища по следующим причинам:

EF Готча

Когда вы смотрите на некоторые текущие учебные пособия по EF (версия Code First), становится очевидным, что нужно обработать ряд ошибок, особенно в отношении графов объектов (объектов, содержащих объекты) и отключенных сценариев. Я думаю, что слой репозитория отлично подходит для упаковки их в одном месте.

Четкая картина механизмов доступа к данным

Репозиторий дает конкретную картину того, как BL получает доступ и обновляет хранилище данных. Он раскрывает методы, которые имеют четкое единственное назначение и могут быть протестированы независимо от BL. Стандартный пример из учебников, Find () , чтобы найти одну сущность. Более конкретный пример приложения Clear () для очистки таблицы базы данных.

Место для оптимизации

При использовании vanilla EF вы неизбежно сталкиваетесь с падениями производительности. Я использую хранилище, чтобы скрыть механизмы оптимизации от BL.

Примеры,

GetKeys () для проецирования кэшированных ключей из таблиц (для решений о вставке / обновлении). Чтение только ключа происходит быстрее и использует меньше памяти, чем чтение полной сущности.

Массовая загрузка через SqlBulkCopy. EF будет вставлять по отдельным операторам SQL. Если вы хотите, чтобы один оператор вставлял несколько строк, SqlBulkCopy - хороший механизм. Хранилище инкапсулирует это и предоставляет метаданные для SqlBulkCopy. Как и метод Insert, вам нужен метод StartBatch () и EndBatch (), который также является аргументом для слоя UnitOfWork.

...