Подтвердить что ты не робот

Entity Framework как репозиторий и UnitOfWork?

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

Ответ 3

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

EF gotcha

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

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

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

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

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

Примеры,

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

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