adsl club

Справочник

Форум

Программы

Фильмы

Ресурсы

Файлообмен

Хостинг

Ростелеком
Динамической структуры запросы к базе данных
Ответить на тему    Форум АДСЛ КлубаЦИФРОВОЙ ФЛЕЙМ :)ПРОГРАММИРОВАНИЕ
Автор Сообщение
AlexRock
Гуру
СообщениеДобавлено: Ср 1-06-11 : 16-26    Заголовок сообщения: Динамической структуры запросы к базе данных Ответить с цитатой

Есть шаблон для запроса:

SELECT переменнаяИмениСтолбца FROM переменнаяИмениТаблицы WHERE переменнаяИмениСтолбца = переменнаяДляСравнения

В любой переменной может быть произвольное по сложности выражение. Эти выражения должны составляться динамически (т. е. они будут изменяться в зависимости от пользовательского ввода или других условий работы программы). Например, количество столбцов после выражения SELECT и их имена должны быть динамическими. Имя таблицы после выражения FROM должно быть динамическим. Количество параметров и их значения для отбора строк после выражения WHERE должны быть динамическими. И т. д. Как это делается?




Старый вариант - много текста, зато подробно. )
Нажмите сюда, чтобы просмотреть текст

Есть реляционная БД с отношениями "один ко многим" и "много ко многим".

Обычно делается как - программист заранее знает, какие запросы будут к БД, по каким алгоритмам пользователь будет работать, поэтому просто составляет эти запросы и всё. А если пользователь захочет произвольно "ходить" по базе данных, переходить от одной таблице к другой по отношениям и записям (строкам) этих таблиц с учётом этих отношений? Т. е. надо либо перебрать все возможные варианты запросов пользователя (какая таблица выбрана первой, какая второй - составить запрос от первой ко второй), либо писать динамически составляемый запрос, где все параметры - названия таблиц, названия столбцов и условия отбора - будут переменными. Как это делается? Я пока только придумал составлять строку запроса, что-то вроде этого (язык C#, все переменные в реальном коде должны переводиться в строку, но это явно не показано для простоты):

Код:
// Будущая строка запроса.
string query = "";

query +=
"SELECT " +
переменнаяИмениСтолбца +
" FROM " +
переменнаяИмениТаблицы +
" WHERE " +
переменнаяИмениСтолбца +
" = " +
переменнаяДляСравнения;


Т. е. получается, что статична только сама структуры запроса, порядок ключевых слов и операторов, а всё остальное набирается из "кирпичиков". Тогда получается, что вместо написания кучи запросов, можно сделать один шаблон для выборки записей следующей таблицы по результатам выборок записей (в качестве "переменнойДляСравнения", например) из предыдущей таблицы.

Но и это ещё не всё. Ведь может быть много условий для отбора, тогда блок WHERE приходится формировать более изощрёнными способами. Например (всё, что до WHERE, делаю сразу в строке для простоты, но реально там тоже всё из кирпичиков набирается, как было выше показано):

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

selectedEntity - выбранная пользователем следующая таблица, из которой надо выбрать записи

Код:
string query = "SELECT id FROM " + selectedEntity + " WHERE ";
            for (int i = 0; i < selectedRows.Count; i++)
            {
                if (i + 1 == selectedObjects.Count)
                {
                    query += "name = " + selectedRows[i];
                }
                else
                {
                    query += "name = " + selectedRows[i] + " OR ";
                }
            }


Т. е. тут я уже должен написать логику, которая учитывает, что если достигнут последний элемент массива переменных для условий отбора, то в конце уже OR ставить не нужно. А в результате получится запрос наподобие такого (если в selectedRows три выбранных ранее строки):

Код:
SELECT id FROM selectedEntity WHERE name = selectedRows[0] OR name = selectedRows[1] OR name = selectedRows[2]


У меня правильный подход, или как-то по-другому, более рационально и лучше всё делается? Просто, если всё это учитывать, то вся логика составления такого запроса может занимать несколько экранов кода. Ведь это для каждого блока (SELECT, FROM, WHERE и т. п.) нужно свой код громоздить.

Как вообще правильно, есть ли методика написания динамических запросов (и шаблонов к ним) с переменными именами таблиц, столбцов, условиями отбора и количеством этих условий? Потому как, опять же, писать на каждый случай отдельный запрос никуда не годится, и в то же время нужно пользователю предоставить возможность "ходить" по базе данных как угодно и делать какие угодно выборки, в пределах заложенных в базу данных отношений между таблицами.
Последний раз редактировалось: AlexRock (Ср 1-06-11 : 18-19), всего редактировалось 3 раз(а)
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
ultrancux
Продвинутый форумчанин
СообщениеДобавлено: Ср 1-06-11 : 17-47    Заголовок сообщения: Ответить с цитатой

Trollface еще один велосипедист

http://ru.wikipedia.org/wiki/ADO.NET
http://nhforge.org/Default.aspx
http://ru.wikipedia.org/wiki/Language_Integrated_Query
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Ср 1-06-11 : 17-55    Заголовок сообщения: Ответить с цитатой

ultrancux
Мне нужен ответ на вопрос и пример, а про существование тонн литературы я и так знаю.

И если уж вы указали на LINQ to SQL, как на нём будет выглядеть запрос к произвольной сущности (чтобы её тип выводился динамически в соответствии с выбранным пользователем), к произвольному столбцу этой сущности и с произвольным количеством условий и количества параметров для сравнения в выражении отбора (where)?
Последний раз редактировалось: AlexRock (Ср 1-06-11 : 18-00), всего редактировалось 1 раз
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Richard Ferlow
Гуру
Предупреждений : 2
СообщениеДобавлено: Ср 1-06-11 : 18-00    Заголовок сообщения: Ответить с цитатой

AlexRock
реально думаешь что кому-то хочется вникать в твои бредни ? пиши как-нибудь проще и компактнее
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение   Номер ICQ
AlexRock
Гуру
СообщениеДобавлено: Ср 1-06-11 : 18-01    Заголовок сообщения: Ответить с цитатой

Richard Ferlow
Хорошо, щас перепишу, а старое по кат запрячу.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
ultrancux
Продвинутый форумчанин
СообщениеДобавлено: Ср 1-06-11 : 18-02    Заголовок сообщения: Ответить с цитатой

AlexRock
прочитав по диагонали, я понял, что ты пилишь новую ORM и дал тебе уже готовые продукты

Если тебе надо как-то рефлексировать БД, то юзай sys.objects

А в FROM одна таблица или скажем joined dataset?
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Ср 1-06-11 : 18-17    Заголовок сообщения: Ответить с цитатой

ultrancux писал(а):
прочитав по диагонали, я понял, что ты пилишь новую ORM и дал тебе уже готовые продукты

Нет, как минимум, об одной я уже знаю - LINQ to SQL - и с помощью неё я не знаю, как сделать такой универсальный запрос.
ultrancux писал(а):
А в FROM одна таблица или скажем joined dataset?

Да, запрос всего к одной таблице - со всякими JOIN я ещё не разобрался.

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

Кстати, я исправил первый пост - теперь там суть.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
ultrancux
Продвинутый форумчанин
СообщениеДобавлено: Ср 1-06-11 : 18-24    Заголовок сообщения: Ответить с цитатой

ну делаешь шаблон запроса во-первых

Код:
const string QUERY_FORMAT = "SELECT {0} FROM {1} WHERE {2};


Потом три метода или свойства на твой вкус:

Код:
string GetColumnExpression(...);
string GetTableExpression(...);
string GetWhereExpression(...);


Внутри каждого метода должна быть логика по созданию запроса из действий пользователя. Например как я это вижу

Код:

public string GetColumnExpression(IEnumerable<MyColumn> columns)
{
   StringBuilder sb = new StringBuilder();
   foreach(var column in columns)
   {
       sb.AppendFormat("{0}, ", column.Name);
   }
   return sb.ToString().TrimEnd(new char[] { ' ', ','});
}


Ну а в конце концов просто собрать запрос.

Код:
string query = string.Format(QUERY_FORMAT, GetColumnExpression(...), GetTableExpression(...), GetWhereExpression(...));
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Ср 1-06-11 : 18-41    Заголовок сообщения: Ответить с цитатой

ultrancux
Вот! Про то, что в запросе имена таблиц и столбцов могут быть параметрами, я чего-то неподумал. Использовал параметры только для множественного сравнения в выражении WHERE.

Ладно, а ещё есть какие пути-подходы? Например, как в таком случае использовать выражения LINQ to SQL? Например, есть такое выражение

from items in db.Items
where items.Id == itemId
select items.Name

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

Type.GetType("MyDatabase." + переменнаяИмениТаблицыВведённаяПользователем);

то в выражении where как сделать динамическую структуру по количеству параметров, с которыми надо сравнивать? Это же уже кусок кода, а он не может динамически изменяться (по крайней мере, я не знаю, как), а позволяет только ветвление. А ветвление - это тупо перебор всех возможных вариантов по количеству параметров для сравнения, что неприемлемо - ведь все варианты надо вручную ввести в виде запросов LINQ to SQL.
Последний раз редактировалось: AlexRock (Ср 1-06-11 : 18-44), всего редактировалось 1 раз
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
ultrancux
Продвинутый форумчанин
СообщениеДобавлено: Ср 1-06-11 : 18-43    Заголовок сообщения: Ответить с цитатой

так делать к сожалению не получится. но можешь копнуть вторую ссылку и там можно строить критерии динамически, предварительно прогнав по рефлексии сущность (это относится только к WHERE)
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Ср 1-06-11 : 18-45    Заголовок сообщения: Ответить с цитатой

ultrancux
Спасибо.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Показать сообщения:   
Ответить на тему    Форум АДСЛ КлубаЦИФРОВОЙ ФЛЕЙМ :)ПРОГРАММИРОВАНИЕ Часовой пояс: GMT + 7
Страница 1 из 1

 

 
Аватары: Вкл|Выкл   ЮзерИнфо: Вкл|Выкл   Подписи: Вкл|Выкл
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете вкладывать файлы
Вы можете скачивать файлы