Построение запросов в независимом от базы данных виде - PullRequest
4 голосов
/ 13 января 2009

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

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

Например, если у меня есть код (MFC), который выглядит следующим образом:

CString query = "SELECT id FROM table"
results = dbConnection->Query(query);

и мы решили поддержать некоторую базу данных, которая использует «AVEC» вместо «FROM». Теперь всякий раз, когда пользователь использует этот механизм базы данных, этот запрос не будет выполнен.

Вариантов пока:

  • Наихудший вариант: заставить код, выполняющий запрос, проверять тип базы данных.
  • Лучший вариант: создать метод запроса запроса для объекта подключения к БД, который принимает уникальный код запроса и возвращает соответствующий запрос на основе используемого механизма базы данных.
  • Опция Betterer: создайте класс построителя запросов, который позволит вызывающему объекту создавать запросы без непосредственного использования SQL. После завершения запроса вызывающая сторона может вызвать метод «Generate», который возвращает строку запроса apppripriate для активного механизма базы данных
  • Лучший вариант: ??

Примечание. Сам движок базы данных абстрагируется от тонких слоев нашего собственного творения. Именно сами запросы являются единственной оставшейся проблемой.

Решение:
Я решил использовать «лучший» вариант (запрос «селектор») по двум причинам.

  1. Отладка : Как упомянуто ниже, отладка будет немного проще с подходом селектора, так как запросы предварительно собраны и перечислены в читабельной форме в коде.
  2. Гибкость : Мне пришло в голову, что есть некоторые базы данных, которые могут иметь значительно лучшие и совершенно разные способы решения определенного запроса. Например, с помощью Access я выполняю сложный запрос к нескольким таблицам каждый раз, потому что должен, но на Sql Server я бы хотел настроить представление. Выбор из представления и из нескольких таблиц - это совершенно разные запросы (я думаю), и этот селектор запросов легко справится с этим.

Ответы [ 6 ]

4 голосов
/ 13 января 2009

Вам нужен собственный объект для написания запросов, который может быть унаследован от реализаций, специфичных для базы данных.

Итак, вы бы сделали что-то вроде:

DbAgnosticQueryObject query = new PostgresSQLQuery();
query.setFrom('foo');
query.setSelect('id');
// and so on
CString queryString = query.toString();

Это может стать довольно сложным, когда вы пройдете простые выборы из одной таблицы. Уже есть пакеты ORM, которые имеют дело со многими из этих нюансов; возможно, стоит взглянуть на них, а не писать свои собственные.

1 голос
/ 13 января 2009

Выведите ваши запросы за пределы кода - поместите их в БД или в файл ресурсов и разрешите переопределения для различных механизмов баз данных.

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

1 голос
/ 13 января 2009

Выберите ORM и начните отображение.

Если вы хотите поддерживать более одной БД, ваша проблема только ухудшится.
И просто подумайте о БД, которые идут - облачные базы данных без (или почти без) SQL и объектные базы данных.

1 голос
/ 13 января 2009

Все ваши опции могут быть уменьшены до

Наихудший вариант: заставить код, выполняющий запрос, проверять тип базы данных.

Это просто вопрос того, куда вы помещаете логику для проверки типа базы данных.

Опция, которую я видел, лучше всего работает на практике:

Лучший вариант: создать метод запроса запроса для объекта подключения к БД, который принимает уникальный код запроса и возвращает соответствующий запрос на основе используемого механизма базы данных.

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

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

1 голос
/ 13 января 2009

Лучший вариант: выбрать базу данных и код для нее.

Как часто вы собираетесь обновлять и заменять базу данных на серверной части производственной системы? И даже если бы вы это сделали, у вас было бы гораздо больше поводов для беспокойства, чем просто незначительные проблемы с синтаксисом. (Основные вещи, такие как синтаксис объединения, даже типы данных могут сильно различаться в разных базах данных.)

Теперь, если вы разрабатываете коммерческое приложение, в котором вы хотите, чтобы клиент мог использовать один из нескольких внутренних вариантов при его реализации, вам, возможно, придется указать «мы поддерживаем Oracle, MS SQl или MYSQL "и код для этих конкретных опций.

0 голосов
/ 13 января 2009

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

По сути, вы создаете слой абстракции базы данных и взаимодействуете с ним. Если вы можете найти один из них для C ++, вероятно, стоит купить вместо того, чтобы писать. Вы также можете искать контейнеры Inversion of Control (IoC) для C ++, которые в основном делают это и даже больше. Я знаю несколько для Java и C #, но я не знаком ни с одним для C ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...