Как организовать паттерн «репозиторий» с возможностью переключаться на разные СУБД, а именно в c#?

Здравствуйте.
Пишу на c#. Но язык не важен по большей части.
У меня есть библиотека, в которой я работаю с данными из БД. Для того, чтобы не писать запросы в базу даных для типичных операций, я решил организовать доступ к базе данных через паттерн "Репозиторий", главный класс которого умеет делать CRUD (обобщенный класс). Этот класс я наследую, когда нужно создать конкретный репозиторий. Например:
Репозиторий новостей, репозиторий пользователей и так далее. Фактически для каждой таблицы у меня свой репозиторий, который умеет CRUD и иногда что-то специфическое, например, для новостей есть метод "FindByUrl" и так далее.

Работаю сейчас с mysql. Поэтому, в проекте у меня есть папка Repositories/Mysql, в которой и находятся все файлы репозиториев.
В будущем планируется переходить просто переключением на другие субд. Я подумал как это реализовать и для этого для каждого репозитория создал свой интерфейс. Теперь для другой субд мне просто нужно по интерфейсам создать папку Repositories/OtherBD и в ней создавать репозитории.

Для переключения между субд я решил сделать Фабрику. Но на этом и возник ступор. И возник ряд вопросов, на которые, прошу совета:
  1. Получается теперь для каждого репозитория я должен писать свою фабрику? Можно ли это сделать одной фабрикой, чтобы выбрал субд и потом просто вызываешь необходимый репозиторий ?
  2. Является ли мой подход избежания sql запроса в коде и переключения субд в программе правильным? Есть ли другие варианты?
  3. Для паттерна "Репозиторий" верно ли постоянно наращивать методы, такие как "FindByUrl"? Если нет, то какие предложение? А если Нужно выборка по двум репозиториям(фактически join)?


P.S. По первому пункту думал создать типа Репозитория репозиториев, который в себе хранит все репозитории и потом по необходимости он их просто выдает. Например, MysqlRepo имеет методы - GetNewsRepo, GetUsersRepo и так далее. Но репозиториев будет минимум 30. Это для получается для каждого репозитория нужно писать getter/setter в главном репозитории? Очень много и накладно.

Может для .net есть решение?
  • Вопрос задан
  • 2811 просмотров
Решения вопроса 1
@Free_ze
Пишу комментарии в комментарии, а не в ответы
Это для получается для каждого репозитория нужно писать getter/setter в главном репозитории? Очень много и накладно.

Это можно решать метапрограммированием через Reflection API и дженерики.

Для переключения между субд я решил сделать Фабрику. Но на этом и возник ступор.

Реализации фабрик для этого уже написаны и называются IoC-контейнерами. Принципы работы с ними можно посмотреть здесь. Ну или где угодно в интернете. Популярные реализации: Castle Windsor, Unity, Ninject и т.п.

Суть в том, что контейнер сначала можно настроить:
interface IMyEntityRepository {...}
class MySqlEntityRpository: IMyEntityRepository  {...}
...
config.Bind<IMyEntityRepository>().ImplementsBy<MySqlEntityRpository>();


А потом позвать:
var repo = ioCContainer.Get<IMyEntityRepository>();


Кроме очевидных плюсов, IoC-контейнеры могут:
  1. собирать полный граф зависимостей по своей таблице (A зависит от B, B от C и т.п., внедряя необходимые реализации автоматически, т.е. мы можем создавать сразу A)
  2. конфигурироваться без перекомпиляции (autowiring (автоматический поиск реализаций заданных интерфейсов) или по информации из конфиг-файла, вроде XML).
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@chibitko
Нужно было использовать ORM - это уже и Generic Repository и Unit Of Work.
Например Entity Framework. Используя EF Code First и разные Entity Configurations (в общем случае достаточно одних), можно легко решить вашу задачу переключения между БД, меняя строку подключения и DB-провайдер.
И не будет проблем с JOIN.
Не нравится EF - используйте Dapper.net, легкая и быстрая ORM, на ней целый stackoverflow работает
Ответ написан
Комментировать
@BaredJJ
Контейнеры вещь очень хорошая, но чтобы ими пользоваться нужно знать и применять методики гибкой разработки. Просто наличие контейнера еще не избавляет код от ужасных зависимостей. Так что прочитайте вначале про инверсию зависимостей. Есть даже книга на русском: "Инверсия зависимостей в .Net".
Ответ написан
Комментировать
@adeptuss
3. Каноничный репозиторий должен уметь только CRUD. Посмотрите в сторону CQRS. В этом вопросе как раз Queries и подойдут.
Ещё рекомендую почитать про Domain Driven Design (DDD), например Эрик Эванс.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы