Найти в Дзене
Геннадий Шушпанов

Replace, объекты данных и гигантские запросы

Мне нравится LINQ. Но у всего есть свои пределы. В одном из проектов нужно было получать данные из базы. Для этого был набор запросов длиной до 300-400 строк, из которых 100-150 в предложении SELECT, а остальные в предложении FROM определяют 70-80 слияний разных видов. Ну и чуть-чуть условий. И дело не в том, что в контексте нужно было прописать 100+ таблиц. Запрос то уже есть, а его приходится писать заново, но уже на LINQ. И доказывать, что они дают один и тот же результат. Но нашелся другой путь. Этот метод класса Database принимает в качестве параметров текст запроса и набор параметров к нему и позволяет задать тип записей результата. Таким образом задача сводится к формированию объекта данных для каждого запроса. Запросов было всего три десятка, так что удалось сэкономить на классах для объектов данных. Эта функция Transact-SQL возвращает метаданные о результате запроса. При этом запрос может вообще ничего не возвращать. В качестве параметра принимает текст запроса, строку с декла
Оглавление

Мне нравится LINQ. Но у всего есть свои пределы. В одном из проектов нужно было получать данные из базы. Для этого был набор запросов длиной до 300-400 строк, из которых 100-150 в предложении SELECT, а остальные в предложении FROM определяют 70-80 слияний разных видов. Ну и чуть-чуть условий. И дело не в том, что в контексте нужно было прописать 100+ таблиц. Запрос то уже есть, а его приходится писать заново, но уже на LINQ. И доказывать, что они дают один и тот же результат. Но нашелся другой путь.

Шаг 1: SqlQuery<T>()

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

Шаг 2: sys.dm_exec_describe_first_result_set

Эта функция Transact-SQL возвращает метаданные о результате запроса. При этом запрос может вообще ничего не возвращать. В качестве параметра принимает текст запроса, строку с декларацией параметров, если они есть в запросе и признак включения дополнительной информации. Работает с запросами и процедурами возвращающими результирующий набор. Нам от этой функции нужен список столбцов результирующего набора, содержащий наименования и типы значений.

Шаг 3: Replace

Получив от sys.dm_exec_describe_first_result_set информацию о столбцах с помощью Replace мы можем сформировать строки описания свойств объектов данных.

-2

Выполнив запрос, копируем из левого столбца список свойств и делаем вставку в тело класса для объекта данных. Если попался неучтенный тип, добавляем в case по system_type_id дополнительную строку и повторяем запрос. Второй case формирует атрибут для nullable типов, учитывая при этом особенности string.

Класс для запросов и partial

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

Главный файл списка запросов
Главный файл списка запросов

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

-4

Часть запросов имела параметры. Сочетание лямда-функции с интерполяцией строк оказалось удобным способом записи в этом случае.

В результате получился чистый код для получения данных из базы.

-5