Форум сайта python.su
На новом проекте пришлось изобретать велосипед.
Причина весьма серьезная - часть обращений к базе данных делается напрямую, большая часть через весьма специфический внешний объектный интерфейс, поддерживающий sql-подобные запросы. Возвращающий объекты, разумеется (мы все равно вынуждены преобразовывать их в наши доменные объекты). И позволяющий много чего еще. Например, он слушает специфические сервисы и может сказать о том, что данные устарели (при этом обновляя локальный cache).
sqlaclhemy напрямую использовать нельзя.
За две недели написал свою ORM. Из алхимии безбожно драл идею (session, query, mapper&table definition, query language from sql package). Unit of work взят с минимальными изменениями. topologic sort - без изменений.
В результате - есть sessions, уверенные тразакции, простой в описании mapping объектов на внутренне предсталение, ленивая загрузка, foreingn relations, one-to-many relations with back references, язык построения запросов для query.filter, query.order_by и прочего. (Я забыл упомянуть что-то важное???)
Наследование доменных объектов (как в алхимии) - очень важное требование. Поддерживается аналог polimorphic_on для описаня mapper.
Результат - таки работает.
Выводы:
не очень-то сложно написать “с нуля” ORM. Если знаешь, что нужно сделать.
sqlalchemy - отличная штука. Даже простое заимствование архитектуры мне сильно облегчило жизнь.
Почему пишу:
не бойтесь “изобретать велосипед”, если это действительно необходимо (изучите все аналоги перед таким серьезным шагом).
написание такой непростой вещи, как ORM, на деле заняло не очень много времени (конечно же, я имел превосходный пример для подражания)
Может кому-нибудь будет интересно….
Офлайн
Интересно.
У тебя блог есть?
Офлайн
Да, дествительно интересно. Ещё бы подробностей ну хоть чуть-чуть :)
Построение архитектуры, и некоторые “особенности” при решении такой задачи - очень интересный опыт…
Дьявол то он - в деталях :)
Офлайн
Андрей СветловМне пришлось делать практически тоже самое. Я создал расширяемый набор классов для разных частей СУБД. При этом обысная схема работы такова:
На новом проекте пришлось изобретать велосипед.
Отредактировано (Май 2, 2008 01:26:05)
Офлайн
ZZZ
Увидел, что у тебя есть. Не совсем понял, зачем используется proxy… Только для сокрытия факта обращения к БД?
Маловато будет… Если еще на прокси осуществляется кеширование данных - самое оно. Позволит сильно снизить нагрузку на базу данных.
Что не понравилось: не увидел, где именно место для доменного объекта (представляющего собой строку из базы данных).
Если это прокси - ты вынужден делать запрос по сети каждый раз. Если клиент - все еще сложнее. Ты должен создавать еще одну тяжелую прослойку.
У меня получилось: есть доменные объекты. Каждый имеет описание (схему, mapper+Table в терминах алхимии). Схемы, в отличие от алхимии, полиморфны (т.е. имеют базовый класс и перегруженные методы. Еще полиморфны колонки (сейчас каждая схема работает со своим типом).
Перед чтением дальнейшей части настоятельно рекомендую ознакомиться с основами sqlalchemy.
Есть абстрактный язык запросов ql (сейчас это самописное подмножество sqlalchemy.sql)
Что потребовалось перегружать в схеме:
- выполнять запрос, возвращая внутренние представления объектов. (rows для db, ael or acm objects for FrontArena)
- создавать объект по внутреннему представлению
- помогать в построении запроса, позвращая то, что может быть выполнено в первом пункте. В отличии от алхимии, формат запроса зависит от явно указанной схемы. А не от диалекта базы данных (MySQL, PostreSQL, Oracle…), указанного в metadata. Почему у себя не использую диалекты? Да потому, что описания колонок для разных схем кардинально отличаются по списку требуемых для описания параметров.
следующие требования появились для оптимизации скорости…
- получать объект по первичному ключу (primary key)
- получать объект по внешнему ключу (foreign key)
- получать коллекцию объектов в случае отнощения один-ко-многим или один-к-одному со стороны “одного”, не имеющего foreign key.
FrontArena позволяет сильно оптимизировать эти запросы.
Для чего нужны перегруженные колонки:
- чтобы правильно представить себя для ql
- чтобы позволить схеме правильно взять значение из внутреннего представления.
FrontArena - мощная система для финансовых операций. Просто помните, что это - не sql, но нечто по своей архитектуре выглядящее как объектно-ориентированная база данных. Мне нужен фасад и для нее тоже.
PS. Понимаю, что без примеров мои слова мало кому понятны. Попытаюсь написать более развернуто (и даже заведу для этого блог) после того, как вернусь из Нью-Йорка в Киев. Возвращаюсь в выходные.
Заказчик дал добро на использование кода библиотеки для иллюстраций.
Более того, высказал заинтересованность в том, чтобы перенести библиотеку в open source. Звучит неплохо, и довольно легко выделить общую часть, не зависящую от нижнего уровня (plain database, sqlalchemy, FrontArena objects). Но для этого мне нужен по меньшей мере еще один участник, использующий данную штуку для своих целей. Интерполяция по одной точке обречена на неудачу, а фреймворк для одного-единственного проекта неизбежно будет содержать слишком много специфического для этого проекта кода.
PPS. Спасибо за проявленный интерес. Этот пост заставил заново взглянуть на получившуюся архитектуру и переписать часть кода. Переместив ответственность выполнения отдельных операций на те классы, которые действительно владеют всей необходимой информацией. Лучшая инкаплуляция. Внешне ничего не изменилось.
Отредактировано (Май 2, 2008 06:39:01)
Офлайн
Андрей СветловНе совсем. Да и не всё это.
Увидел, что у тебя есть. Не совсем понял, зачем используется proxy… Только для сокрытия факта обращения к БД?
Андрей СветловКэширование у меня организуется отдельно. Правда оно пока в зачаточном состоянии, но способ работы уже определён и для некоторых вещей уже работает.
Маловато будет… Если еще на прокси осуществляется кеширование данных - самое оно. Позволит сильно снизить нагрузку на базу данных.
Андрей СветловИзвини, я не понял сути вопроса…
Что не понравилось: не увидел, где именно место для доменного объекта (представляющего собой строку из базы данных).
Если это прокси - ты вынужден делать запрос по сети каждый раз. Если клиент - все еще сложнее. Ты должен создавать еще одну тяжелую прослойку.
Андрей СветловВо! Это интересно…
Перед чтением дальнейшей части настоятельно рекомендую ознакомиться с основами sqlalchemy.
Андрей СветловХм… +1 за умные мысли и наставление на путь истиный…
Есть абстрактный язык запросов ql (сейчас это самописное подмножество sqlalchemy.sql)
Андрей СветловУдачно долететь! Будем ждать новых мыслей…
PS. Понимаю, что без примеров мои слова мало кому понятны. Попытаюсь написать более развернуто (и даже заведу для этого блог) после того, как вернусь из Нью-Йорка в Киев. Возвращаюсь в выходные.
Андрей СветловНе раньше сентября. Я принял решение пока оставаться на том, что есть.
Но для этого мне нужен по меньшей мере еще один участник, использующий данную штуку для своих целей.
Офлайн
ZZZЭта формулировка значительно лучше. По поводу удобства интерфейса: быть может, а может быть можно и лучше… Сложно говорить, не сравнив твой и мой код. Свои примеры надеюсь выложить на следующей неделе.
Это, фактически, RPC, с возможностью фрагментации больших данных, для лучшей асинхронности. При этом, вся работа по разбиению/сборки данных делается без участия пользователя этого прокси. И, что самое главное, удобный интерфейс. Когда я писал тот пост, я ещё не знал, удобно ли будет с ним работать, а сейчас… Он идеально вписался в остальную часть архитектуры и удобно работает.
ZZZВ этом то и проблема. Словарь (python dict, как я понимаю) - слишком низкий уровень для полноценного общения. Нужна еще информация о foreign key и о коллекциях.Андрей СветловИзвини, я не понял сути вопроса…
Что не понравилось: не увидел, где именно место для доменного объекта (представляющего собой строку из базы данных).
Если это прокси - ты вынужден делать запрос по сети каждый раз. Если клиент - все еще сложнее. Ты должен создавать еще одну тяжелую прослойку.
Строка из базы данных сразу преобразуется в словарь и только после используется/передаётся.
ZZZНовые мысли появились уже сегодня.
Удачно долететь! Будем ждать новых мыслей…
Офлайн
Андрей СветловЯ думал, что в моём примере это-то понятно… Там же не слова про базы данных.
Эта формулировка значительно лучше.
Андрей СветловДавай. Интересно сравнить.
По поводу удобства интерфейса: быть может, а может быть можно и лучше… Сложно говорить, не сравнив твой и мой код. Свои примеры надеюсь выложить на следующей неделе.
Андрей СветловУ меня так не получится. Слишком разнородные запросы. У меня клиент далеко не только к СУБД стучтся. Например “прямое” общение двух (и более!) клиентов. Оно всё-равно будет идти через сервер, но минуя СУБД.
По поводу кеширования: у меня это неотъемлимая часть фреймворка. Позволяющая использовать механизмы кеширования нижних уровней (FrontArena и наш самописный сервис для отслеживания изменений) и обеспечивающая более высокоуровневый кеш.
Андрей СветловС эти у меня всё просто. Как система может прислать оповещение (редко и только там, где это критически необходимо), так и при обращении к кэшу он проверяет насколько давно данные обновлялись и, если надо, обновляет их. Для каждого типа данных своё всемя.
Над извещениями об устаревании кэша (а часть используемых в моем проекте подсистем могут посылать такие извещения) планирую занятся позднее, через месяц другой.
Андрей СветловНе вижу проблемы. Если, например, нужно узнать о юзере, отравившим сообщение, то мы просто берём UserId из сообщения и спрашиваем у библиотеки пользователей кто он такой. Опять же класс Message просто будет обладать аттрибутом (property) User, спрашивающим нужную информацию.
В этом то и проблема. Словарь (python dict, как я понимаю) - слишком низкий уровень для полноценного общения. Нужна еще информация о foreign key и о коллекциях.
Андрей СветловПосмотрю позже. Сейчас нужно спать…
А еще - о наследовании. У меня часто объект из базы данных на самом деле может относится к унаследованному типу. Для лучшего понимания данного тезиса стоит скачать sqlalchemy trunk и посмотреть в sqlalchemy\examples\polymorph\single.py. Пример хорошо иллюстрирует задачи наследования, актуальные для меня.
Андрей СветловОб этом я выше и говорил.
В моей интерпретации foreign key - “прозрачный” атрибут в доменном объекте, возвращающий объект, на который ссылается. Делая дополнительный запрос, если требуется.
Андрей СветловЯ, наверное, эту часть также организую. А в некоторых случаях выгодней прислать обновлённый объект вместе с сообщением об изменении. У меня есть довольно критичные к этому моменты.
Я попытаюсь научить сессию лениво обновлять все объекты, содержащиеся в ней, если приходит сообщение о том, что данный объект изменился. Лениво - значит удалить объект из кэша и перечитать его при следующем обращении.
Отредактировано (Май 4, 2008 00:56:01)
Офлайн
Нормально.
Дальше нужно более детальное рассмотрение, чтобы не говорить попусту.
Используем немного разные подходы (что естественно).
Офлайн