Я бы строго отличался между EF и NH в этом случае и не включал бы обе технологии в один и тот же вопрос. Simple NH более развит и имеет архитектуру, ведущую к коду, который легче тестировать. Также в случае NH вы можете просто переключить базу данных на другую (например, SQLite), и она будет работать все так же, что не должно быть верно в случае EF, где переключение базы данных может привести к тестированию совершенно другого приложения - особенно если Вы переключаетесь между базой данных MS и не MS.
Что такое хранилище? Давайте посмотрим определение Мартина Фаулера :
Репозиторий является посредником между доменом и слоями отображения данных,
действуя как коллекция объектов домена в памяти. Клиентские объекты
создать спецификации запросов декларативно и представить их
Репозиторий для удовлетворения. Объекты могут быть добавлены и удалены из
Репозиторий, как они могут из простой коллекции объектов, и
код отображения, инкапсулированный репозиторием, будет выполнять
соответствующие операции за кадром. Концептуально, хранилище
инкапсулирует набор объектов, сохраненных в хранилище данных и
операции, выполняемые над ними, обеспечивая более объектно-ориентированное представление
персистентного слоя. Хранилище также поддерживает цель
достижение чистого разделения и односторонней зависимости между доменом
и слои отображения данных.
Хорошее определение. Теперь подумайте о цели DbSet
:
- Действует ли это как при сборе памяти? Да, вы можете использовать его для получения сущностей из базы данных или использовать свойство
Local
для получения уже загруженных сущностей.
- Может ли клиент запрашивать спецификации декларативно? Да, это называется linq-to-entity.
- Можно ли добавлять или удалять объекты как из коллекции? Да, это может.
- Является ли отображение инкапсулированным? Да, это так.
- Есть ли чистое разделение? С точки зрения логики да. С точки зрения API нет, потому что использование
IDbSet
модели домена сделает модель домена зависимой от технологии - EF. Это проблема? Теоретически да, для пуристов да, но на 99% это действительно не проблема, потому что ситуация, когда вам нужно изменить API, встречается редко и всегда включает большие изменения, даже если вы правильно разделяли API.
DbSet
- хранилище. Единственная разница между непосредственным использованием DbSet
и переносом его в какой-либо общий репозиторий - это разделение. Это приводит к моему предыдущему ответу на аналогичный вопрос - Общий репозиторий с EF 4.1 в чем смысл
Теперь, какова цель хранилища в вашем приложении? Я видел ваши предыдущие вопросы, включая , этот , где у вас есть BaseRepository
, построенный поверх платформы Entity. Если вы серьезно подразумеваете это как базовый репозиторий, который будет родительским для ваших специализированных репозиториев, работающих на совокупных корнях для вашей доменной модели и предоставляющих специализированные методы, относящиеся только к конкретному раскрытому типу сущности, тогда да - вы используете шаблон репозитория, и он вам нужен. Но если вы просто переносите контекст и одиночный набор и вызываете этот репозиторий, вы, скорее всего, создали только избыточный слой с сомнительной добавленной стоимостью, потому что это просто оболочка поверх DbSet
.
Существует только один сценарий, в котором ваш репозиторий (DbSet
обертка) будет иметь смысл в таком случае:
- Оболочка никогда не будет выставлена
IQueryable
(linq-to-entity)
- Оболочка никогда не примет
Expression<>
и не передаст ее внутренне IQueryalbe
(linq-to-entity)
Это единственный сценарий, который предложит вам полностью смоделированные репозитории => ваш верхний уровень может быть легко протестирован модулем. Вы не собираетесь использовать репозитории модульного тестирования и не будете имитировать контекст, используемый в репозиториях. Репозитории оборачивают логику доступа к данным и сопоставления - единственными разумными тестами в случае репозиториев являются интеграционные тесты. В чем проблема этого сценария? Вы потеряете всю мощь LINQ, и вам придется обернуть / повторно реализовать некоторые методы и типы, реализованные в EF. Этот тип репозиториев аналогичен используемому при упаковке доступа к данным с использованием хранимых процедур.
Если вы не последуете этому сценарию, ваша жизнь будет намного проще. У вас будут запросы, определенные LINQ, но вы не сможете выполнить модульное тестирование кода, потому что не существует макета / фейка, который все равно будет оценивать запросы как linq-to-entity. После того, как вы имитируете DbSet
или IQueryable
, вы будете использовать linq-to-object, который является надмножеством linq-to-entity. Вы можете легко написать запрос, который пройдет тест на ложном DbSet
, но потерпит неудачу во время выполнения с настоящим DbSet
. Здесь - больше об этой проблеме, а здесь - пример запроса, который пройдет тест, но не выполнится во время выполнения. В этом случае вы должны использовать интеграционные тесты (с реальной базой данных) для всех методов, использующих запросы linq-to-entity поверх ваших репозиториев.