Есть база данных. В ней есть таблицы. Талицы справочники представляют собой какие-то сущности: например — поставщики, товары, адреса....
Есть программа, которая работает с базой данных. По хорошему, как я понимаю, все эти сущности из БД должны каким-то образом отображаться на классы в программе. То есть у меня в программе должны присутствовать классы Поставщик, Товар, Адрес. Более того, как я понимаю, все изменения в БД должны происходит через методы этих объектов. То есть продажа товара поставщику должна происходить примерно так: Поставщик.Sale(Товар), а уже реализация этого метода должна вызывать измениея в БД.
Как я понимаю, это общепринятая практика ? По моему, если я не ошибаюсь, именно это называется mapping. Это так ?
Где можно почитать про способы, подходы, рекомендации реализации этой идеи.
очень советую книжку Фаулера. сейчас на в открытом доступе остался только каталог: http://martinfowler.com/eaaCatalog/, но у меня осталась выкачанная бета-версия. надо — могу прислать.
... <<RSDN@Home 1.0 beta 4>> слушаю Porcupine Tree — Metanoia II
Здравствуйте, DemAS, Вы писали:
DAS> Есть база данных. В ней есть таблицы. Талицы справочники представляют собой какие-то сущности: например — поставщики, товары, адреса....
Тема очень большая, поэтому расскажу в двух словах как делается у нас. Действительно, самый надежный способ это отображать "сущности" базы данных на классы.
Чтение-запись в БД не встраивается в сами классы представления данных. Причин очень много, в том числе:
Эффективность
Более четкое разделение приложения на подсистемы.
Нужно будет спланировать механизмы синхронизации представления данных внутри программы. В том числе такие штуки как каскадное удаление.
Пользовательский интерфейс должен быть одним из способов управления данными. Потому что через некоторое время захочется прикручивать подобие автоматизации, и если сразу не предусмотреть изолированность данных от их представления, то потом прийдется все переписывать с нуля.
Транзакционность на уровне программы. Если объектов будет очень много (да и когда их мало, тоже не помешает) нужно будет реализовать надежный механизм перехода системы из одного состояния в другое. Например, при записи объектам будут назначаться идентификаторы и будут сбрасываться признаки изменения. Если происходит сбой и последующий откат транзакции в базе данных, то нужно вернуть все объеты в первоначальное состояние. За два года лучше, чем использование полных копии данных, я не придумал.
Тут сейчас другие напишут
А если опускаться до уровня — как именно это реализуется, то описания хватит на целую книгу
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Roman Avramov, Вы писали:
RA>очень советую книжку Фаулера. сейчас на в открытом доступе остался только каталог: RA>http://martinfowler.com/eaaCatalog/, но у меня осталась выкачанная бета-версия. надо — могу прислать.
Понимаю, что здесь про все не расскажешь, но может прокомментируешь вот это:
КД> Чтение-запись в БД не встраивается в сами классы представления данных. Причин очень много, в том числе: КД>
КД> Эффективность КД> Более четкое разделение приложения на подсистемы. КД>
А куда оно встраивается. Писать для этого отдельные классы. Каким образом они будут связаны с классами-сущностями (Поставщик, Товар..) ?
Здравствуйте, DemAS, Вы писали:
DAS>Здравствуйте, Коваленко Дмитрий, Вы писали:
DAS> А куда оно встраивается. Писать для этого отдельные классы. Каким образом они будут связаны с классами-сущностями (Поставщик, Товар..) ?
В программу, куда же еще
Попробую кратко объяснить, что я имею в виду. У нас используется следующая архитекутра приложения хранения данных: Главный контейнер данных. Пусть он будет называться Document. В его обязанности входит:
Управление списком копий данных. Методы StartTrandaction, CommitTransaction, RollbackTransaction. Имеется в виду не транзакции в базе данных, а транзакции внутри документа (ну или набора данных) на уровне программы.
Метод, исторически названный Data, который возвращает текущую копию данных. Например, текущая копия может быть последним элементом списка.
Чтение-запись данных из базы данных. Методы SaveToDatabase, LoadFromDatabase. Перед чтением/записью начинается транзакционное изменение данных — через вышеуказанные методы
Получение уведомления об изменении данных и их транслирование на уровень пользовательского интерфейса. То есть в Document есть обратная связь с просмотром и редактированием данных юзером.
Вообще говоря, этот Document оформлен в виде COM объекта и он же представляет собой точку входа для доступа к данным через интерфейсы автоматизации.
Контейнер данных. Здесь хранятся сами данные и связи между ними.
Наборы данных. Например, поставщик, покупатель, список товаров
Контроллер. Специальный объект, который получает уведомления от данных и обеспечивает их синхронизацию. Формально он же, обработав событие, уведомляет главный контейнер, об изменении.
То есть, как видишь, чтение-запись отделенно от самих данных, поскольку они в этих операциях полностью пассивны. Фактически пишутся не те объекты, которые создал юзер, а их копии. Если операция прошла успешно — оригинал выкидывается, а копия становится актуальной. Если сбой — мы выкинем копию и вернемся к исходному состоянию.
Если интересно, можно еще пообщаться — у меня сечас выход из глубокого погружения, после которого потрепаться — единственный способ не навредить своей работе
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
1. Document и контейнер данных одни на все прилдожение или по экземпляру для каждой сущности (Поставщик, Товар...)
КД>Получение уведомления об изменении данных и их транслирование на уровень пользовательского интерфейса. То есть в Document есть обратная связь с просмотром и редактированием данных юзером.
Связь двухстороняя ? То есть если пользователь изменил данные на форме, то об этом "узнает" и БД. И если изменились данные в БД(например их изменил другой юзер) то все пользователи узнают про это изменение. Если да, то каким образом реализовано последнее утверждение ?
Здравствуйте, DemAS, Вы писали:
DAS>Здравствуйте, Коваленко Дмитрий, Вы писали:
DAS> DAS> 1. Document и контейнер данных одни на все прилдожение или по экземпляру для каждой сущности (Поставщик, Товар...)
Одни на все приложение.
Твою накладную, или как она там — счет фактура, я бы разложил так:
Document:
Контейнер:
1. Список юр. лиц
2. Список товаров. Каждый товар содержит
- Список цен. Каждая цена это объект
3. Указатель на продавца
4. Указатель на покупателя
5. Табличная часть накладной, каждая запись содержит
- Указатель на цену. Из объекта цены, можно узнать к какому
товару она относится
- Количество
Обрати внимание, что покупатель и продавец могут быть одним и тем же объектом.
Формально, перед тем как грузить что одно, что другого из базы данных,
Document сначало проверяет, что его нет в Списке юр лиц.
То, что в табличной части держаться не сами товары, а их цены, позвляет
один и тот же товар добавить в накладную с разными ценами. Это если, конечно,
цены вводятся отдельно, а не набиваются прямо в накладной :)
Document это совокупность данных, которыми управляет контейнер. У Document'a может быть несколько контейнеров - см. про список копий и транзакцинность изменения Document'a.
КД>>Получение уведомления об изменении данных и их транслирование на уровень пользовательского интерфейса. То есть в Document есть обратная связь с просмотром и редактированием данных юзером.
DAS> Связь двухстороняя ? То есть если пользователь изменил данные на форме, то об этом "узнает" и БД. И если изменились данные в БД(например их изменил другой юзер) то все пользователи узнают про это изменение. Если да, то каким образом реализовано последнее утверждение ?
У нас пока никак. Хотя при записи в базу данных, можно распознать, что после загрузки они изменялись, но на этом мы пока не заморачиваемся.
Вообще, между нами девочками, я тоже когда то был очень озабочен тем, чтобы юзер получал уведомления о том, что его данные кто-то похерил. А сейчас меня это волнует меньше всего — все это отдано на откуп скриптерам, которые пишут логику управления редакторами. Моя стихия — эти редакторы проектировать
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>У нас пока никак. Хотя при записи в базу данных, можно распознать, что после загрузки они изменялись, но на этом мы пока не заморачиваемся.
Ну вот те раз. Начали за здравие а закончили... признанием в любви к stateless-модели.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, DemAS, Вы писали:
DAS> Есть база данных. В ней есть таблицы. Талицы справочники представляют собой какие-то сущности: например — поставщики, товары, адреса.... DAS> Есть программа, которая работает с базой данных. По хорошему, как я понимаю, все эти сущности из БД должны каким-то образом отображаться на классы в программе. То есть у меня в программе должны присутствовать классы Поставщик, Товар, Адрес. Более того, как я понимаю, все изменения в БД должны происходит через методы этих объектов. То есть продажа товара поставщику должна происходить примерно так: Поставщик.Sale(Товар), а уже реализация этого метода должна вызывать измениея в БД. DAS> Как я понимаю, это общепринятая практика ? По моему, если я не ошибаюсь, именно это называется mapping. Это так ? DAS> Где можно почитать про способы, подходы, рекомендации реализации этой идеи. DAS>
Эй! Вы чего в самом деле?
Какой тип "программы"?
"Программа" это локальная БД — один клиент? (Десктоп)
Или "Программа" это активный клиент пассивного сервера?
Или "Программа" это активный клиент активного сервера?
А сколько клиентов только читают, а сколько еще и активно пишут?
И т.д.
А уж потом можно говорить про паттерны, объекты или фуекции, statefull, stateless-but-timestaps или stateless-fire-n-forget и ...
Здравствуйте, Геннадий Васильев, Вы писали:
КД>>У нас пока никак. Хотя при записи в базу данных, можно распознать, что после загрузки они изменялись, но на этом мы пока не заморачиваемся.
ГВ>Ну вот те раз. Начали за здравие а закончили... признанием в любви к stateless-модели.
Вы чего при детях выражаетесь ?
Двунаправленный обмен данных подразумевает наличие сервера приложений. По крайней мере, если сервером базы данных является InterBase, то из него app-сервер не сделаешь. А я трезво оцениваю свои возможности и возможности нашей команды — мы такую архитектуру ПО просто не потянем. А может нам просто нужен новый архитектор системы
А с другой стороны, что именно должен увидеть юзер, когда редактируемые данные изменились? Предупреждение в строке состояния ? Дык, как я уже сказал, это можно отложить до момента записи и сравнить дату модификации, которую мы прочитали при загрузке, с той, которую мы увидим на момент записи. Во время записи — мы её обновим.
Если я правильно все понял, то лучше вынести это обсуждение в отдельную ветку — чукча будет читателем
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
CS>Какой тип "программы"? CS>"Программа" это локальная БД — один клиент? (Десктоп) CS>Или "Программа" это активный клиент пассивного сервера? CS>Или "Программа" это активный клиент активного сервера? CS> CS>А сколько клиентов только читают, а сколько еще и активно пишут?
На самом деле спрашивал про программу работающую на локальном компе с Access. Ну например так, как Janus.
Другое дело, что по ходу ответов, меня заинтересовали и другие варианты
Здравствуйте, Roman Avramov, Вы писали:
RA>очень советую книжку Фаулера. сейчас на в открытом доступе остался только каталог: RA>http://martinfowler.com/eaaCatalog/, но у меня осталась выкачанная бета-версия. надо — могу прислать.
А вот бы и на lucker@csl.minsk.by получить копию
Здравствуйте, Коваленко Дмитрий, Вы писали:
ГВ>>Ну вот те раз. Начали за здравие а закончили... признанием в любви к stateless-модели.
КД>Вы чего при детях выражаетесь ? КД>Двунаправленный обмен данных подразумевает наличие сервера приложений. По крайней мере, если сервером базы данных является InterBase, то из него app-сервер не сделаешь.
Из сервера БД app-сервер вообще сделать сложно (хотя иногда можно).
КД>А я трезво оцениваю свои возможности и возможности нашей команды — мы такую архитектуру ПО просто не потянем.
Потянете, вы и так её тянете, просто размазали сложность по нескольким независимым подсистемам.
КД>А может нам просто нужен новый архитектор системы
Коней на переправе не меняют.
КД>А с другой стороны, что именно должен увидеть юзер, когда редактируемые данные изменились? Предупреждение в строке состояния ? Дык, как я уже сказал, это можно отложить до момента записи и сравнить дату модификации, которую мы прочитали при загрузке, с той, которую мы увидим на момент записи. Во время записи — мы её обновим.
Это всё верно, но только для относительно простых случаев. Есть ещё несколько соображений. Например, юзер А тратит много времени на обновление какой-то записи, тогда как другой (Б) в это время вносит в неё изменения и тем самым блокирует для Б возможность обновить запись. Что делать? По идее — А должен перечитать запись и отредактировать её заново. Всё бы хорошо, но ему снова придётся тратить время (и нервы) на сию операцию. И так далее и тому подобное. А в идеале Б просто не должен получить доступ на обновление к записи, которую уже захватил А.
Другой вариант. Запись (вернее — логический обновляемый объект) состоит из тучи мелких связанных записей, которые могут обновляться независимо (допустим — через drill-down навигацию), притом обновление одной из них может привести к недопустимости обновления агрегата, который при такой схеме и знать не будет о том, что какая-то его часть изменилась. Здесь вроде бы, логически, выход в том, чтобы вынести всю логику контроля целостности на... сервер БД и привет app-серверу как концепции, здравствуй расползание дизайна во все мыслимые и немыслимые стороны, а потому так делать нежелательно, следовательно разумный выход один — усложнять app-сервер.
Теперь о том, что должен увидеть пользователь.
Если запись захвачена им для просмотора, то хорошо бы её просто изменить, если для редактирования — то он не может увидеть сообщения о том, что запись кем-то изменена, поскольку она не может быть изменена кем-то. Единственный вариант, когда возможна такая ситуация — это при offline-транзакциях (захватили запись на изменение и отключились нафиг), которые сброшены сервером из-за превышения допустимого интервала времени между захватом записи и выполнением транзакции. Но здесь пользователь просто получит сообщение о прекращении транзакции и всё.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, DemAS, Вы писали:
DAS>Здравствуйте, c-smile, Вы писали:
DAS> CS>>Какой тип "программы"? CS>>"Программа" это локальная БД — один клиент? (Десктоп) CS>>Или "Программа" это активный клиент пассивного сервера? CS>>Или "Программа" это активный клиент активного сервера? CS>> CS>>А сколько клиентов только читают, а сколько еще и активно пишут?
DAS> На самом деле спрашивал про программу работающую на локальном компе с Access. Ну например так, как Janus.
DAS> Другое дело, что по ходу ответов, меня заинтересовали и другие варианты
В этом случае делай что душе угодно.
Базовые посылки следующие:
Записи в таблицах реляционных БД не есть то же самое что объекты реального мира и классы UI.
Есть некоторое соответсвие. Ну и только.
Попытки построить стройную классовую структуру над всем этим делом обречены на провал.
Разве что в наипростейших случаях.
Более того во взрослых системах очень сильно отличается структура информации (запросов, объектов) на чтение и на запись.
В них же общение клиент сервер выполняется механизмом больше похожим на механизм вызова функций чем на передачу/сохранение объектов.
Я бы порекомендовал тебе сделать две функции типа:
и спрятать за ними весь код физической работы с базой данных.
Т.е. если тебе придется перейти на другую архитектуру БД или в сеть тебе не придется глобально все переделывать.
Заодно такой подход дисциплинирует от размазывания БД по всему приложению.
В UI слое ты можешь делать те классы которые тебе удобны. Но это больше UI oriented классы типа формы редакторы броузеры диалоги.
Реально работать хоть как-то с классами и объектами получается в OODB.
В RDB — забудь. Не забудешь так вспомнишь в очередной раз когда будешь добавлять/убирать колонки в таблицах.
Здравствуйте, DemAS, Вы писали:
DAS> Есть база данных. В ней есть таблицы. Талицы справочники представляют собой какие-то сущности: например — поставщики, товары, адреса.... DAS> Есть программа, которая работает с базой данных. По хорошему, как я понимаю, все эти сущности из БД должны каким-то образом отображаться на классы в программе. То есть у меня в программе должны присутствовать классы Поставщик, Товар, Адрес. Более того, как я понимаю, все изменения в БД должны происходит через методы этих объектов. То есть продажа товара поставщику должна происходить примерно так: Поставщик.Sale(Товар), а уже реализация этого метода должна вызывать измениея в БД. DAS> Как я понимаю, это общепринятая практика ? По моему, если я не ошибаюсь, именно это называется mapping. Это так ?
Да.
DAS> Где можно почитать про способы, подходы, рекомендации реализации этой идеи.