Micro ORM - поддержка ваших строк SQL-запросов - PullRequest
6 голосов
/ 14 мая 2011

Я не буду вдаваться в подробности, почему я исследую использование Micro ORM на этом этапе - за исключением того, что я чувствую себя бессильным, когда использую полноценный ORM. В фоновом режиме происходит слишком много всего, что происходит автоматически, и не все из них являются наилучшим возможным выбором. Я был вполне готов вернуться к необработанному доступу к базе данных, но я узнал о трех новых парнях на блоке: Dapper, PetaPoco и Massive. Поэтому я решил дать низкоуровневый подход к проекту с домашним животным. Это не актуально, но пока я использую PetaPoco.

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

  1. Опрыскивать запросы SQL везде, где они мне нужны. Это наименее сложный метод инфраструктуры. Тем не менее, он страдает как в области обслуживания и тестирования.

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

  3. Подготовьте несколько классов, чтобы сделать систему несколько гибкой. Я начал на этом пути. Я реализовал интерфейс репозитория и зависимый от базы данных класс репозитория. Я также создал несколько крошечных интерфейсов для захвата запросов SQL, которые можно передавать в метод GetMany () моего репозитория. Все запросы реализованы как отдельные классы прямо сейчас, и мне, вероятно, понадобится немного больше интерфейса вокруг этого, чтобы добавить некоторый уровень независимости базы данных - и, возможно, для некоторой гибкости при декорировании запросов в разбитые на страницы и отсортированные запросы (опять же, это также сделало бы они немного более гибки в работе с разными базами данных).

Сейчас меня больше всего беспокоит то, что я вступил на скользкий путь написания всех функций, необходимых для полноценного ORM, но очень плохо. Например, сейчас мне кажется разумным, что я пишу или нахожу библиотеку для преобразования вызовов linq в операторы SQL, чтобы я мог легко скомбинировать свои запросы или написать расширители, которые могут украсить любой запрос, который я ему передал, и т. Д. Но это большое задание, и уже выполнено большими парнями, поэтому я сопротивляюсь желанию пойти туда. Я также хочу сохранить контроль над тем, какие запросы я отправляю в базу данных - явно записав их.

Так что это за предложение? Должен ли я пойти вариант № 2, или попытаться наткнуться на вариант № 3? Я уверен, что я не могу показать никому код, написанный в первом варианте, без покраснения. Есть ли другой подход, который вы можете порекомендовать?


РЕДАКТИРОВАТЬ: После того, как я задал вопрос, я понял, что есть еще один вариант, несколько ортогональный этим трем вариантам: хранимые процедуры. Кажется, есть несколько преимуществ размещения всех ваших запросов в базе данных в виде хранимых процедур. Они хранятся в центральном месте и не распространяются по коду (хотя обслуживание является проблемой - параметры могут быть не синхронизированы). Опора на диалект базы данных решается автоматически: если вы перемещаете базы данных, вы переносите все свои хранимые процедуры, и все готово. И есть также преимущества безопасности.

С опцией хранимой процедуры альтернативы 1 и 2 кажутся немного более подходящими. Похоже, сущностей недостаточно, чтобы оправдать вариант 3, но все еще возможно отделить команды вызова процедуры от кода доступа к базе данных.

Я реализовал вариант 3 без хранимых процедур и вариант 2 с хранимыми процедурами, и кажется, что последний больше подходит для меня (на случай, если кто-то заинтересован в результате вопроса).

Ответы [ 2 ]

6 голосов
/ 14 мая 2011

Я бы сказал, поместите sql туда, где вы бы поместили эквивалентный запрос LINQ, или sql для DataContext.ExecuteQuery.Что касается того, где это ... хорошо, это зависит от вас и зависит от того, сколько разлуки вы хотите.- Марк Гравелл, создатель Dapper

См. Мнение Марка по этому вопросу

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

4 голосов
/ 20 мая 2011

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

При использовании хранимых процедур целесообразно использовать T4

Я склонен использовать хранимые процедуры в своем проекте, даже если он не использует PetaPoco, Dapper или Massive (проект начался раньше, чем они были здесь). Вместо этого он использует BLToolkit. Тем не мение. Вместо того, чтобы писать свои методы для запуска хранимых процедур и писать код для обеспечения параметров хранимых процедур, я написал шаблон T4 , который генерирует код для меня.

Всякий раз, когда хранимые процедуры изменяются (некоторые могут быть добавлены / удалены, параметры добавлены / удалены / переименованы / перепечатаны), мой код будет прерываться при компиляции, поскольку вызовы методов больше не будут совпадать с их сигнатурой.

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

Так или иначе. Обслуживание связано с хранимыми процедурами, изменение кода - это просто нажатие кнопки в Visual Studio, которая конвертирует все T4 одновременно. Вам не нужно искать ваши методы, которые используют эти процедуры. Вам сообщат об ошибках во время компиляции. Одной вещи меньше беспокоиться.

Так что вместо того, чтобы писать

using (var db = new DbManager())
{
    return db
        .SetSpCommand(
            "Person_SaveWithRelations",
            db.Parameter("@Name", name),
            db.Parameter("@Email", email),
            db.Parameter("@Birth", birth),
            db.Parameter("@ExternalID", exId))
        .ExecuteObject<Person>();
}

и имея кучу волшебных строк, я могу просто написать:

using (var db = new DataManager())
{
    return db
        .Person
        .SaveWithRelations(name, email, birth, exId)
        .ExecuteObject<Person>();
}

Это приятнее, чище ломает компиляцию и обеспечивает intellisense, так что это также быстрее при разработке.

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

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