Реализация шаблона репозитория и сервиса с помощью RavenDB

У меня есть некоторые трудности с реализацией репозитория и шаблона обслуживания в моем проекте RavenDB. Основная проблема заключается в том, как должен выглядеть мой интерфейс репозитория, потому что в RavenDB я использую несколько индексов для своих запросов.

Скажем, мне нужно получить все элементы, где родитель равен 1. Один из способов - использовать IQueryable List() и получить все документы, а затем добавить предложение where, чтобы выбрать элементы, где parentid равен 1. Это похоже на плохая идея, потому что я не могу использовать какие-либо функции индекса в RavenDB. Таким образом, другой подход заключается в том, чтобы иметь что-то вроде этого: IEnumerable Find (строковый индекс, предикат Func) в репозитории, но это также кажется плохой идеей, потому что оно недостаточно общее и требует, чтобы я реализовал этот метод, если бы я изменил его с RavenDB на общий сервер sql.

Итак, как я могу реализовать общий репозиторий, но все же получаю преимущества индексов в RavenDB?

Ответ 2

Во-первых, спросите, почему вы хотите использовать шаблон репозитория?

Если вы хотите использовать шаблон, потому что вы делаете проект, ориентированный на домен, то, как указывает другой из этих ответов, вам нужно заново подумать о намерении вашего запроса и поговорить об этом с точки зрения вашего domain - и вы можете начать моделировать вещи вокруг этого.

В этом случае спецификации, вероятно, являются вашим другом, и вы должны изучить их.


ОДНАКО, давайте взглянем на одну часть вашего вопроса на мгновение, прежде чем продолжить свой ответ:

кажется плохой идеей, потому что он недостаточно общий и требует, чтобы я реализовал этот метод, если бы я изменил его с RavenDB на общий сервер sql.

Вы идете по этому пути неправильно - пытаясь сделать вашу систему полностью стойкой - агностик на этом уровне требует неприятностей - если вы попытаетесь скрыть уникальные функции вашего хранилища данных от самих запросов, то зачем вам использовать RavenDB?

Метод, который я обычно использую в простой документ-ориентированной (IE, я говорю с точки зрения данных, что вы, кажется, делаете), состоит в том, чтобы разделить мои запросы с моими командами.

Спросите себя, почему вы хотите запросить свои документы по идентификатору родителя? Отображать ли список на странице? Почему вы пытаетесь моделировать это с точки зрения документов? Почему бы не моделировать это с точки зрения модели представления и использовать наиболее эффективный метод извлечения этих данных из RavenDB? (Запрос по индексу (динамический или иначе)), придерживайтесь этого в factory, который принимает "некоторые входы" и генерирует "выход", и если вы решите изменить свой хранилище персистентности, вы можете изменить эти заводы. (Я делаю еще один шаг в своих приложениях ASP.NET MVC и имею одиночные контроллеры действий, и я не называю их контроллерами, делая запрос от них в большинстве случаев).

Если вы хотите на самом деле вытащить ваши документы с помощью родительского идентификатора, чтобы обновить их или запустить некоторую бизнес-логику через них, возможно, вы их неправильно имитировали - операция записи обычно включает только изменение одного документа или другими словами, вы должны моделировать свои документы вокруг границ транзакций.

TL; DR

Подумайте о том, чего вы на самом деле хотите достичь - почему вы хотите использовать "шаблон репозитория" или "шаблон службы" - эти слова существуют как способы описания сценария, который может возникнуть, если вы моделируете свой приложения в соответствии с вашими потребностями, как общий способ выражения роли определенного объекта, а не как то, что вам нужно, чтобы обучать все ваши функциональные возможности.

Ответ 3

Скажем, мне нужно взять все предметы где parentid равен 1.

Во-первых, перестаньте думать, что ваш доступ к данным так нужен.

Вы НЕ должны "получать все элементы, где parentid равно 1". Это поможет попытаться прекратить думать таким образом, ориентированным на данные.

Вам нужно получить все элементы с определенным родителем. Это концепция, которая существует в вашем проблемном пространстве (ваш домен приложения).

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

Один из способов - использовать IQueryable List() и получить все документы, а затем добавьте предложение where, чтобы выбрать элементы где родитель равен 1. Это кажется плохой идеей, потому что я не могу используйте любые функции индекса в RavenDB. Так другой подход заключается в том, чтобы что-то вроде этого, IEnumerable Найти (индекс строки, предикат Func) в репозиторий, но это также кажется как плохая идея, потому что

Оба эти являются плохими идеями. То, что вы предлагаете, требует, чтобы код, вызывающий ваш репозиторий или запрос, имел информацию о вашей схеме.

Почему потребитель вашего репозитория должен заботиться или знать, что существует родительское поле? Если это изменится, если изменится определение какой-либо конкретной концепции в вашем проблемном пространстве, сколько мест в вашем коде придется изменить?

Каждое место, которое извлекает элементы с определенным родителем.

Это плохо, это антитеза инкапсуляции.

Мое мнение состоит в том, что вы захотите моделировать запросы как явные понятия, а не лямбда или строки, которые передаются и используются повсюду.

Вы можете явно моделировать запросы с помощью шаблона спецификации, методов запросов в репозитории, шаблона объекта запроса и т.д.

это не достаточно общего и требует, чтобы я реализовать этот метод, если бы я перейти от RavenDB к общей sql сервер.

Хорошо, что Func является слишком общим. Опять же, подумайте о том, что ваш потребительский код должен знать, чтобы использовать такой метод запроса, вы будете связывать верхние уровни кода непосредственно с вашей схемой DB, делая это.

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

Ответ 4

Я бы отговорил вас от использования шаблона репозитория. В большинстве случаев это чрезмерное архивирование и делает код более сложным.

Айенде в последнее время сделал несколько сообщений:

Я рекомендую просто писать против Raven native API.

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