Недавно я прочитал, что не рекомендуется использовать шаблон хранилища в сочетании с ORM. Насколько я понимаю, это потому, что абстракция, которую они предоставляют для базы данных SQL, слишком неплотна, чтобы сдерживать шаблон.
У меня есть пара вопросов по этому поводу:
Что вы делаете, если хотите отключить ORM? У вас будет специальный код ORM в вашем приложении, если вы не содержите его в репозитории.
Является ли шаблон хранилища действительным, если не используется ORM, и вы используете ADO.NET для доступа к данным и самостоятельно заполняете данные объекта?
Если вы используете ORM, но не шаблон репозитория, где вы храните часто используемые запросы? Было бы разумно представлять каждый запрос как класс и иметь какую-то фабрику запросов для создания экземпляров?
источник
Ответы:
1) Верно, но как часто вы выключаете ORM?
2) Я бы сказал так, потому что контекст ORM является своего рода хранилищем и скрывает много работы, включая создание запросов, получение данных, отображение и т. Д. Если вы не используете ORM, эта логика все еще должна где-то находиться. Я не знаю, будет ли это квалифицироваться как шаблон репозитория в самом строгом смысле этого слова ...
3) Я часто вижу инкапсуляцию запросов, но обычно это больше для целей тестирования / заглушки. Кроме этого, я был бы осторожен при повторном использовании запроса в разных частях приложения, потому что тогда вы рискуете создать зависимость от чего-то, что может измениться n раз (n - количество мест, где вы используете запрос).
источник
Я еще не был в положении, когда компания вдруг решила переключить технологию доступа к данным. Если это произойдет, потребуется некоторая работа. Я склонен абстрагировать операции доступа к данным через интерфейсы. Репозиторий является одним из способов решения этой проблемы.
Тогда у меня была бы другая сборка для конкретной реализации моего уровня доступа к данным. Например, я мог бы иметь:
Company.Product.Data
иCompany.Product.Data.EntityFramework
сборки. Первая сборка будет использоваться исключительно для интерфейсов, тогда как другая будет конкретной реализацией логики доступа к данным Entity Framework.Я думаю, что вам решать, какой шаблон действителен или нет. Я использовал шаблон репозитория на уровне представления. Нужно иметь в виду, что людям нравится бросать обязанности в репозитории. Прежде чем вы это узнаете, ваш репозиторий будет танцевать, петь и делать разные вещи. Вы хотите избежать этого.
Я видел класс репозитория, который начинался с обязанностей GetAll, GetById, Update и Delete, что хорошо. К тому времени, когда проект был завершен, у того же класса были десятки методов (обязанностей), которых никогда не должно было быть. Например, GetByForename, GetBySurname, UpdateWithExclusion и всякие сумасшедшие вещи.
Это где запросы и команды вступают в игру.
Я думаю, что это хорошая идея - использовать запросы и команды вместо репозиториев. Я делаю следующее:
Определить интерфейс для запроса. В этом вам поможет юнит тест. Например
public interface IGetProductsByCategoryQuery { ... }
Определите конкретную реализацию для запроса. Вы сможете внедрить их через IoC-фреймворк по вашему выбору. Например
public class GetProductsByCategoryQuery : IGetProductsByCategoryQuery
Теперь вместо того, чтобы загрязнять хранилище десятками обязанностей, я просто группирую свои запросы в пространства имен. Например, интерфейс для вышеупомянутого запроса может жить в:
Company.SolutionName.Products.Queries
и реализация может жить вCompany.SolutionName.Products.Queries.Implementation
Когда дело доходит до обновления или удаления данных, я использую шаблон команд таким же образом.
Некоторые могут не согласиться и сказать, что до завершения проекта у вас будут десятки классов и пространств имен. Да, вы будете. На мой взгляд, это хорошая вещь, так как вы можете просмотреть решение в IDE по вашему выбору и сразу увидеть, какие обязанности выполняет определенный компонент. Если вы решили вместо этого использовать шаблон репозитория, вам придется заглянуть внутрь каждого класса репозитория, пытаясь выяснить его обязанности.
источник
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: то, что следует, основано на моем понимании и кратком опыте упомянутой модели (репозитория). Я мог бы делать это неправильно ... на самом деле, я довольно уверен, что я делаю это неправильно :). Итак, хотя это попытка ответа, это также скрытый вопрос.
Я использую шаблон Repository для абстрагирования от слоя доступа к данным, который в большинстве случаев является ORM. Это универсальный интерфейс с методами для классов Create, Read, Update, Delete и реализации для LINQ to SQL и EF. Я мог бы сделать реализацию, которая записывает в XML-файлы на диске (просто дикий пример того, что я мог с этим сделать). Я не внедряю Unit of Work, поскольку он поддерживается ORM. В случае необходимости, я мог бы реализовать это. Мне так нравится, потому что пока это дало мне хорошее разделение. Я не говорю, что нет лучших альтернатив.
Чтобы ответить на ваши вопросы:
В качестве другого примера, ребята из Umbraco абстрагировали контейнер DI, на тот случай, если они захотят переключиться на что-то другое.
источник
Если ORM предлагает гибкость LINQ, нетерпеливую загрузку и т. Д., Я бы не стал скрывать это за дополнительным слоем.
Если он включает в себя необработанный sql (микро ORM), то в любом случае следует использовать «метод на запрос» для достижения возможности повторного использования, что делает шаблон репозитория подходящим.
Зачем вам нужно переключаться?
Тот, который имеет большинство функций, которые вам нужны, следует использовать. Возможно, что новая версия ormX принесет новые функции и окажется лучше, чем текущая, но ...
Если вы решите скрыть orm, вы можете использовать только те функции, которые имеют все кандидаты.
Например, вы не можете использовать
Dictionary<string, Entity>
свойства в своих объектах, потому что ormY не может их обработать.Предполагая, что используется LINQ, большинство переключателей orm просто переключают ссылки на библиотеки и заменяют их
session.Query<Foo>()
наcontext.Foos
аналогичные, пока они не скомпилируются. Скучная задача, но занимает меньше времени, чем кодирование уровня абстракции.Да. Код должен быть многоразовым, и это означает, что здание SQL, материализация объекта и т. Д. Должны быть размещены в одном месте (отдельный класс). Вы также можете вызвать класс «XRepository» и извлечь из него интерфейс.
Предполагая, что LINQ используется, обертка класса будет излишним ИМХО. Более хорошим способом были бы методы расширения
Любой код, который используется в нескольких местах (или имеет потенциал) и достаточно сложен (подвержен ошибкам), должен быть извлечен в централизованное место.
источник