![]() |
Модераторы: LSD, AntonSaburov |
![]() ![]() ![]() |
|
chinook |
|
|||
Unregistered |
Привет!
Есть приложение, которое получает данные из базы. Вариантов запросов много, запросы сложные. Код - отстой. Конструирование запросов разбросано по сотне классов, каждый сам для себя. Грядет переписывание этой кучи мусора, поэтому я хотел бы локализовать создание query в одном месте. Для меня очевидно (:-)), что такой объект = composit + interpreter, мы в произвольном порядке загоняем туда условия, потом получаем строку, представляющую из себя query. Я, собственно, уже продумал структуру и все такое. Но! Во-первых, не хочется изобретать велосипед, возможно, все до меня уже сделали. Во-вторых, возможно, это не самый лучший путь, и кто-то знает лучший. Собственно, вопросы: кто-нибудь про такой подход слышал? кто-нибудь с такой проблеммой сталкивался? Заранее благодарен! |
|||
|
||||
Stampede |
|
||||
![]() Гносеолог ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 963 Регистрация: 25.4.2005 Где: Calgary, Alberta, Canada Репутация: 66 Всего: 144 |
Слышать не слышать, но сталкиваться - сталкивался. И более того, реализовывал. Разумеется, задача не совсем тривиальная, и с наскоку ее не решишь. Я. в частности, поступил следующим образом. Я создал фреймворк из абстрактных понятий:
Описатели аттрибутов не зашиты в код и хранятся отдельно (в базе, в XML, в проперях - неважно). Описатель содержит такие сведения: имя таблицы/столбца, тип данных, имя атрибута и плюс еще всякие флаги. Value - это иерархия типизированных описателей значений, которые знают, как представлять себя в базе и на экране. Expression - это собственно условие поиска, которое подразделяется на логические условия и атомарные условия. Таким образом можно строить запросы неограниченной вложенности. Query - это надстройка над Expression, которая может включать дополнительную информацию о порядке сортировки, диапазоне поиска и пр. Важный момент: в этих интерфейсах нет ни намека на SQL, потому что клиенту об этом знать совершенно необязательно. На сервере эти интерфейсы расширены до SqlExpression и SqlQuery, соответственно, и у них есть методы, специфические для пострения собственно выражений SQL. Вот в общих словах и весь подход. У меня - работает. Да, там есть еще один интересный момент, связанный с поддержкой разных типов СУБД. Там фишка в том, что выносить конструкции SQL в ресурсы очень неудобно, потому что при написании/отладке хорошо видеть, что именно у тебя происходит. Поэтому тексты шаблонов у меня зашиты прямо в сорцах. А чтобы иметь возможность менять синтаксис в зависимости от СУБД, я создал базовый класс Flavored, и все прочие классы, которые содержат код SQL, унаследованы от него. У этого класса есть два метода , setFlavor(String flavor) и getFlavored(String str). Первый используется при инициализации класса, чтобы установить версию, например, "postgres". А вот когда приходит время собственно генерировать запрос, то используется примерно такой код:
А внутри происходит следующее: когда вызывается getFlavored(), он использует рефлексию и ищет имя переменной, которая соотвествует переданной строке. В данном случае это переменная sortClause. После этого он присоединяет к имени переменной ранее установленный тип базы (postgres) и ищет переменную sortClausePostgres. Если таковая находится, он возвращает ее значение, если нет - то возвращает исходную строку. Метод довольно зыбкий, потому что тут получается очень жесткий контракт, который по незнанию или забывчивости легко нарушить, и никто на этапе компиляции даже не пикнет, но если его придерживаться, то получается весьма удобно. ЗЫ. А ты чего до сих пор не зарегистрируешься? Шестым чувством чувствую, что мы с тобой земляки ![]() |
||||
|
|||||
Chinook |
|
|||
Новичок Профиль Группа: Участник Сообщений: 8 Регистрация: 21.5.2005 Где: Vancouver, BC, Ca nada Репутация: нет Всего: нет |
Спасибо за подробный ответ!
Круто и все такое! У нас планируется нечто типа того, но это у нас называется metadata. Дело в том, что в зависимости от выбора основного источника данных, связанные данные могут находится в совершенно различных таблицах с различной структурой. В результате, после обращения к классам, работающих с metadata, мы получаем таблицы и список полей, по которым они связаны. А вот дальше надо составить собственно запрос. Пока это решается компонованием строки в зависимости от условий (таблиц, подзапросов, полей для связывания и т.п.). Я не собиралься замахиваться на такого монстра, как у тебя :-) Забумывалось написать класс, не привязанный к определенной структуре данных, который может принимать: 1. Поля для select 2. таблицы для from 3. поля для where с условием связывания (=, *=, >...) и условием обязательности (or and) 4. поля для having 5. поля для order by При этом 1, 2, 3 могут быть тем же классом (т.е. вложенные подзапросы - у нас Oracle, который это понимает). Преимущества такого подхода: 1. все построение запросов в одном месте 2. нет определенного порядка добавления элементов (а то в полупостроенном запросе приходится вставлять новый подзапрос в группу from - выглядит ужасно) 3. Код бизнес-классов не захламляется всякими строками с кусками запроса (ну, это производное). 4. этот класс (скорее - пакет) можно будет использовать к любом приложении (по крайней мере с ораклом) Почему, собственно, кажется это целесообразным: 1. interpter: шаблон для перевода чего-либо с одного языка на другой. Т.е. перевод на sql - сам Бог велел. 2. composit: обход дерева, в которое превращается запрос - все точно по документации. Просто посроение такого класса(пакета) мне кажется очевидным, если начинать что-то новое, заранее зная про большое количество разнородных запросов. Поэтому я и спросил - неверняка такой пакет уже написан, и, учитывая большое количество исходников в и-нете, мог попасться кому-то на глаза(на мои не попался). Я, конечно, танцевал на этих граблях и раньше много раз, но это были уже работающие системы и, мысли о рефакторинге всего кода вызывал ужасные ночные галлюцинации, поэтому руки так и не дошли.
Зарегистрировался. Шестым!?!?! Ну, возможно :-) Я вообще-то из Воронежа, живу в Ванкувере. Добавлено @ 01:54 О, блин, Калгари! А я что-то затормозил :-) Ну да, точно, чинук - это, слава Богу, у вас :-) |
|||
|
||||
tux |
|
|||
![]() Летатель ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
Может быть еще вот эта статья Скотта Эмблера (из Торонто!!!
![]() |
|||
|
||||
batigoal |
|
|||
![]() Нелетучий Мыш ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6423 Регистрация: 28.12.2004 Где: Санктъ-Петербургъ Репутация: 16 Всего: 151 |
tux
Спасибо за линк. Обязательно прочту. -------------------- "Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли) ЖоржЖЖ |
|||
|
||||
maximb |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 48 Регистрация: 23.5.2005 Где: Украина, г.Симфер ополь Репутация: 2 Всего: 6 |
А может стоит использовать Hibernate
Зачем изобретать велосипед |
|||
|
||||
batigoal |
|
|||
![]() Нелетучий Мыш ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6423 Регистрация: 28.12.2004 Где: Санктъ-Петербургъ Репутация: 16 Всего: 151 |
Может, и стоит, просто я его пока не знаю
![]() -------------------- "Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли) ЖоржЖЖ |
|||
|
||||
maximb |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 48 Регистрация: 23.5.2005 Где: Украина, г.Симфер ополь Репутация: 2 Всего: 6 |
Да там не так сложно, главное научиться нормально писать маппинги на классы и все.
Да и еще, небольшое дополнение: Для обеспечения нормальных транзакций и упрощения работы с транзакциями очень хорошо использовать Spring в одной связке с Hibernate. |
|||
|
||||
tux |
|
|||
![]() Летатель ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
В данном случае это приведет к необходимости создания слоя хранимых объектов и преобразования запросов из SQL в объектные запросы на HQL. Не уверен, что преобразование всегда можно будет выполнить один в один. В частности это зависит от того, в каком объеме используются функции, характерные только для данной используемой СУБД. Хотя генератор запросов на HQL в Hibernate уже есть и если запросы не очень сложные и их не очень много возможно что действительно использование Hibernate оправдано.
|
|||
|
||||
maximb |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 48 Регистрация: 23.5.2005 Где: Украина, г.Симфер ополь Репутация: 2 Всего: 6 |
Если очень надо могу помочь примером "Spring + Hibernate"
Но придется денек подождать т.к. мне его надо будет сделать. То, что у меня уже есть к сожалению дать не могу т.к. это текущий проект. Добавлено @ 11:07
Да но это избавляет программиста от того, чтобы делать преобразования запросов для разных БД вручную, вся ответственность ложится на Hibernate. Насчет сложности запросов, то средствами Hibernate можно делать запросы любой сложности. |
|||
|
||||
Domestic Cat |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 13 Всего: 172 |
![]() ![]() ![]() -------------------- |
|||
|
||||
maximb |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 48 Регистрация: 23.5.2005 Где: Украина, г.Симфер ополь Репутация: 2 Всего: 6 |
Domestic Cat
![]() Сорри, сразу не увидел но обсуждение Hibernate ведется еще и в этом топике http://forum.vingrad.ru/index.php?showtopic=31813 |
|||
|
||||
3,14 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1614 Регистрация: 18.6.2004 Где: Н. Новгород Репутация: 3 Всего: 24 |
ИМХО использовать Hibernate и если есть возможность все запросы вынести на сторону БД
-------------------- Может быть, это только мой бред, Может быть, жизнь не так хороша, Может быть, я не выйду на свет, Но я летал, когда пела душа... |
|||
|
||||
tux |
|
|||
![]() Летатель ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
Язык запросов, сглаживающий различия между различными СУБД, по определению должен обладать меньшими возможностями, чем язык запросов СУБД. Хотя, не спорю, в подавляющем большинстве случаев его вполне достаточно. |
|||
|
||||
maximb |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 48 Регистрация: 23.5.2005 Где: Украина, г.Симфер ополь Репутация: 2 Всего: 6 |
За универсальность надо платить ![]() Понятно, что собственная реализация работы с БД (если все правильно сделано) может быть лучше чем универсальный подход, но в этом случае не надо забывать сколько времени и сил уйдет на эту собственную реализацию. + Суппорт, стоит внести небольшие изменения в модель данных или перейти на другую БД как придется переписывать массу запросов, что в Хибернейте решается простым переписыванием маппингов (и то это придется делать только в том случае если произошли изменения в модели) |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |