Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×

ORM Сначала классы, потом таблицы

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

В контексте статьи про хибер давайте ещё такую штуку обсудим.

ORM расшифровывается как Object Relational Mapping

Приходилось ли вам вначале создавать Object(классы), а потом для них Relational(таблицы)?

Или проект всегда начинался с существующей структуры базы (Relational -> Object Mapping)?

Как подбираете классы в таком случае?

Как угадать Java-классы, например, для s.dou.ua/...​-files/image1_Fh1bISl.png ?

P.S. DDL схемы pastebin.com/9dPzf7f6

P.P.S У меня есть небольшой опыт с Хибернейтом (см. статью в профиле)

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Яблоко или андроид? Вопрос в том кто отвечает за маппинг, если СУБД (то есть настоящая СУБД с полноценной поддержкой объектной модели например разновидность MUMPS — Intersystems Cache) тогда конечно создаете

Objects

и все — далее с ними работаете. Но если вы пользуетесь прослойкой

Хибернейтом

(кстати вопрос а зачем он здесь нужен на такой простейшей структуре?) — то ответьте себе на один простой вопрос — в какой момент (после какого количества времени жизни проекта/записей в таблицах и прочее) вам станет очень больно изменить (начальную стройную вечную правильную) структуру БД (объектов) добавить поля/связи переименовать что-то (это всегда случается, если проект живет долго) и каким способом вам будет проще внести изменения (когда вы создали объекты — а таблицы вам сгенерировались автоматом или наоборот?) Кстати — если проект новый вы это можете даже потестить. Сделать одним способом потом другим наполнить тестовыми записями и попробовать изменить структуру поле связь. Вы получите бесценный опыт (кроме шуток). И однозначно выберете тот вариант который вам лучше подойдет — и понимание всей этой кухни вырастет в разы. Не бояться работать с базой — это не значит отрицать использование ORM — это значит что когда вы выбираете использовать ORM вы знаете где и что вы выигрываете — где и когда возникнут могут возникнуть ограничения или трудности. Использовать ORM стоит — но только не в оправдание невозможности или неумения написать чуть более сложный чем джоин-скл запрос, а когда вы понимаете сильные и слабые стороны, пусть даже конкретно для вашего проекта вашей СУБД и вашей структуры таблиц-объектов/объектов-таблиц.

Другое дело если вам надо выкатить прототип или демо а после выкатки выбросить его. Тогда не заморачивайтесь и делайте как быстрее или как знаете.

если СУБД (то есть настоящая СУБД с полноценной поддержкой объектной модели например разновидность MUMPS — Intersystems Cache)

эх, помню эти времена объектных БД, лихо тогда все лоханулись, дружненько так.
Сколько баблища вбухали в эту парадигму.
Но потом пришел Хибернейт.

Базу даних потрібно «поважати» ... вона все-таки зберігає для вас ваші дані :)

БД — не проста штука. І коли даних багато і складних, треба вирішити як з ними швидко працювати. І тут логіка починає тягнутися: в sql створюються денормалізовані таблиці та хитрі індекси, щось виноситься в nosql, щось в elastic search, а шось взагалі в щось схоже на annoy індекс чи in-memory структури.

Як на мене, проектувати БД треба руками, писати dao класи теж (або генерити, а потім правити). Mapper між ними треба генерити і потім НЕ правити (а краще і що б не читати)

А після цього всього бажано ізолювати це все від решти проекту якимось шаром абстракції, який можна за-mock-ати.

по моему вы ищете тулзу, которая по существующей базе запилит вам классы — ну вот например
www.visual-paradigm.com (небесплатно конечно).
Но даже после неё всё равно напильником надо серъёзно прокатиться по сущностям.

«Угадывать» ничего не надо, в любой такой тулзе зашит набор правил — «вижу таблицу — создаю класс», «вижу колонку — создаю поле» и т.д.

Методологически, начинать лучше с базы, а не доверять всяким автогенерэйтам... Тем более это всё красиво работает — когда база пустая. Как только появляются данные, ключи, связи — любой чих в коде приводит жалобному вою хибернэйта — «ой не могу ничего проапдэйтить...»

Создание сущностей после базы/таблиц никак не помещает правильной и красивой архитектуре самого приложения, ведь ваша бизнес-логика всё равно должна быть вне сущностей.

если предполагается серьезная нагрузка естественно надо сначала грамотно спроектировать хранилище, какие там потом классы, какие там нужны классы вопрос десятый. Если ОРМ будет неэфективным то нифиг он нужен — ОРМ удобен для програмирования но сильно тормозит по эфективности. На набольших приложэениях это оправдано на серьезных только если ОРМ нехило оптимизиолованный как в .NET например.

Вначале база, потом классы.
Обратное для говносайтов

Прямо под вашим комментарием другое мнение. В теме поста диаграмма базы и ддл для неё. Что скажете? Какие классы предложите?

Пусть чувак постом ниже купит билет на поезд, а потом окажется что таких васей пришло 5 чел на место. Облака-с, панове! Реляционка ацтой!

Билеты на поезд (конкретно в Украине) пишуться в MUMPS — это даже не таблицы — это глобалы (не реляционная структура). Они уже тридцать лет туда пишуться и пока еще их не перевели в таблицы окончательно (хотя процесс запущен).

MUMPS — это даже не таблицы — это глобалы (не реляционная структура).
Они уже тридцать лет туда пишуться и пока еще их не перевели в таблицы окончательно (хотя процесс запущен).

I feel your pain.

Когда-то я имел удовольствие работать с NoSQL БД задолго до того,
как это стало мэйнстримом.
БД называется DbVista — там через её методы на языке Си ручками берёшь запись, лочишь, пишешь, ручками разлочиваешь итп.
Всё летает как пуля, смазанная салом — быстродействие опупенное.

Но жизнь, суко, коротка чтобы это всё ручками-ручками грести.
Поэтому на галеру установили мотор и Оракл.

Я хлебал кровавый энтрепрайз когда ORM еще не придумали.
И тогда действительно проект всегда начинался с базы. И в принципе — на ней же и заканчивался. Вся архитектура была подчинена структуре базы. ООП модели были просто копией таблиц. 80% кода — это CRUD, 80% логики и вычислений — в базе!
Самое страшное, что когда придумали ORM — многие то же пляшут от базы!

Как подбираете классы в таком случае?

Как можно «подбирать» классы под базу?! Это же телега впереди лошади!
Для чего инженерная мысль изобретала ООП и ООД? Для чего придумали DDD и Onion Architecture? Для чего Гради Буч учил девелоперов мыслить абстракциями? Что бы они подбирали классы под таблички в базе?!
Я помню как «выстрелил» NoSql: когда оказалось что если все не пихать в базу — то получается в разы быстрее. Когда оказалось что не нужно всю огромную систему проталкивать через «игольное ушко» единственного сервера БД. Оказалось что Теорема CAP работает — но на самом деле энтерпрайзу нахер не нужно лепить все в базе! В большинстве реальных систем даже на 1 уровень изоляции кладут болт: NoLock и грязное чтение — только так монструозные базы еще как-то выживают. А переход на NoSQL считался прямо чудом: умирающие под своим весом монстры начинали «летать», как только сбрасывали груз ДБ серверов.
Давайте смотреть в будущее: РЕЛЯЦИОННЫЕ БАЗЫ НЕ НУЖНЫ !!!!
Сама их концепция обеспечить надёжность и консистентность ЕДИНСТВЕННОГО эталонного набора данных — безсмысленна в эпоху облаков и распределенных вычислений!
Невозможно «залочить запись» и пускай весь мир подождёт. В облаке всегда будет масса копий и версий одних и тех же данных. Постоянные коллизии — неизбежны и нужно их разруливать, а не «лочить».
Представьте тебе криптовалюту на SQL Server: где-то в подземном бункере стоит единственный на весь мир огромный супер-сервер базы данных. На нем счета миллиардов людей. Что бы заплатить за пиццу нужно залочить 100500 записей в разных таблицах, провести транзакцию, потом дождаться всех чужих локов и в итоге через полчаса получить отлуп из-за дедлока.
Современная архитектура — это микросервисы. Это глобальная тенденция отказа от больших и тяжёлых компонентов, серверов, баз в пользу легких, расширяемых элементов.
Хватит думать о приложении как о небоскребе, который мы проектируем от подвала (с тем самым супер-сервером БД) до шпиля на крыше.
Представьте лучше что мы строим космическую станцию в невесомости и можем стыковать модули как нам удобно. Это требует совсем других архитектурных решений!

Предлагаешь одну крайность заменить другой?

Как можно «подбирать» классы под базу?! Это же телега впереди лошади!

Так делают, в совсем тяжелых случаях 1:1. Тяжело работать в таких проектах, когда все дао, сервисы и т.д. уже написаны.

Что-то много намешано в кучу — локи всей базы (зачем, есть же куча методов этого не делать), САР и «волшебные» NoSQL. Все не так просто .... вот например посмотреть историю Jepsen тестов различных баз (jepsen.io/analyses) ... много интересного.
Да и, наконец, «классик» Martin Fowler в «NoSQL Distilled» (martinfowler.com/books/nosql.html) неплохо расписал подходы, а с тех пор еще столько вещей добавили в разные типы баз.
И консистентность данных как всегда нужна — даже в 2019 :)

Давайте смотреть в будущее: РЕЛЯЦИОННЫЕ БАЗЫ НЕ НУЖНЫ !!!!

Для твиттера и фб — не нужны, потому что в-принципе пофиг если какой-то пост потеряется надолго или навсегда, да и ленты давно уже не в хронологическом порядке.

Я представляю интернет-магазин или какую-нибудь систему учета, где

масса копий и версий одних и тех же данных. Постоянные коллизии — неизбежны и нужно их разруливать, а не «лочить»

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

Про скалу скажу, что все данные хранятся в иммутабельном ADT, который обычно неплохо ложится на реляционную модель, ибо порождающие ADT операции — включение тип(а/ов) в тип и прямое произведение типов формальным образом переносятся на таблицы. Иногда могут вылезти некоторые нюансы, но их обычно можно пофиксить при помощи shapeless (хотя можно сказать что это уже и костыли, и править нужно ещё и кейс-классы). Обратный подход — кейс-классы по таблицам, сделан очень много где, в slick например, можно генерировать полную модель кейс-классов для всего имея подключение к базе.

Кстати, да. Как иммутабельность с коллекциями-то?

нормально там с коллекциями, иммутабельную полностью копировать не надо
for-loop боль, ага, если заменить на while, получается как Java.

зачем вам циклы когда у стандартных скаловских коллекций огромная пачка методов которые эти куски бойлерплейта устраняют? for comprehension используется не для тех же целей для которых используют обычные лупы.

Не для тех, ага
Но тупое скалярное умножение векторов в scala-way превращало бутылочное горлышко в игольное ушко

скалярное умножение векторов

и

scala-way

понятия не совместимые. Для математических числодробилок у нас есть библиотеки на С, вот их и используйте.

Ну вот и ответ на ваш вопрос. В Java way оно было достаточно хотя бы для POC.

Зачем и scala и java way если есть уже готовые рабочие реализации, если можно оперировать на более высоком уровне абстракции? Я пилил классификаторы на скале в качестве POC, и оно работало вменяемо, сравнимо с питонными(не те что cython, те что от и до пишут на голом питоне).

Одна из причин, потому что уже была готовая опенсорсная модель на С со стороннего проекта, выстроенная безо всяких фреймворков и было быстрее тупо в лоб повторить и загрузить в нее файлик с весами и дальше

оперировать на более высоком уровне абстракции
Я так понимаю скалушы предлагают коппировать на каждый чих List с тысячами елементов

medium.com/...​yoneda-trick-f5a0321aeba4 Скалуши предлагают копировать маленькие коллекции, а для больших использовать батчи в виде йонеды или койонеды и им подобных или реактивную обработку(fs2, akka streams) для чего то большого — там процессинг бежит чанками.

Вообще всё без исключения ФП про дополнительные астракции, которые не имеют смысла в других парадигмах.

ммогу подключить Hazelcast

стопроц платное для интерпрайзов и работает с кучей своих особенностей, которые(в отличии от ФП) не из чего не следуют. Твой хазелкаст наверняка не работает как выше перечисленная абстракция. ФП абстрауции они для всех и на халяву + хорошо работают.

О тех о которых я говорю в джаве действительно нет и действительно быть не может.

Со скалой, увы, не знаком. Поэтому на snapeless/slick только попробую посмотреть. Добавил DDL в пост, если покажете, как оно на скале, буду дополнительно благодарен.

Не знаю когда руки доберутся до вашего ddl, но вон там очень даже можно копипастой кода сгенерировать. slick.lightbend.com/...​.0.0/code-generation.html, если руки чешутся, можно поробовать.

В Java не знаю, а в node.js такое умеет делать Sequelize — задаешь классы и связи, он сам все создаст или промигрирует когда добавилось поле (sequelize.sync()). Если вы с нуля начинаете проект то можно использовать такую последовательность

Как подбираете классы в таком случае?

Неважно что вы первым напишете классы или SQL скрипты,
ДО всего этого делается этап «проектирование» (можно на UML, сделать Class Diagram и ER Diagram)
«Угадать классы по таблицам» это называется reverse engineering. Тоже бывает.

Так у нас зараз все аджайл. Вирішувати проблеми по мірі необхідності.
Ще варто пошукати відповідь на запитання, що було швидше, курка чи яйце :)

Проблема в том, что у вас — круд

Давайте переформулируем. Да, у меня круд. Это проблема?

Да, проблема. У в предметной области нет другого поведения кроме как круд (т.е. вся бизнеслогика — это работа с базой), а поэтому достаточно сделать один-два класса отвечающих за работу с базой, остальные — это pojo (джава ведь? на плюсах были бы структуры), вью и контроллер.

P.S. ORM considered harmful

а еще можно взять внезапно postgrest

У в предметной области нет другого поведения кроме как круд

Эээ... Вроде как само определение «предметная область» подразумевает, что там поведение есть, если мы не совсем про записную книжку говорим.

P.S. ORM considered harmful

Без задачи такое утверждать некорректно.

если мы не совсем про записную книжку говорим.

А мы говорим не про записную книжку?

Лучше всего сначала спроектировать базу данных, а потом на ее основе автоматически сгенерировать исходный код классов (соответствующим инструментом).

Бог создал мир за 6 дней, потому что ему не нужно было делать совместимость с предыдущими наработками.

Покажите, пожалуйста. Добавил DDL схемы в пост.

Идея, как я понимаю, в том, чтобы сначала наг*внячить код,
а потом под него подпихнуть БД.
Ну, красиво жить не запретишь, конешн.

Вообще, по-хорошему, сначала надо разработать доменную модель (справочник «понятий») и
хоть что-то типа ER — диаграм.
Эт чтобы потом всё не переделывать и не вкурчивать невкручиваемое.
Затем:
— задизайтить БД.
— писать сервисы, круды, эндпоинты — вот это всё.
— натягивать морду.

Но можно и наборот, хотя это дольше, дороже и больнее,
потому что придётся переделывать.

Мне кажется, что если делать перевод классы Java -> структура БД -> классы Java, то результат будет не очень хорош, как с любым дизассемблированием. Поэтому интересуюсь, как R -> O делают.

Такая, что при подходе code first не нужна возня с поддержкой порождающих базу SQL скриптов при каждом изменении её схемы. Я в своё время имел дело с реализацией миграций схемы БД на чистом SQL, и это была боль и простыни разнообразных проверок, в которых легко запутаться и упустить что-то важное.

я так понимаю опыта работы не с одной ORM-кой у вас нету, и даташит читать вам тоже лень, иначе к чему такие очевидные вопросы?

У меня есть небольшой опыт работы с Hibernate (см. статью). Есть мнения, что он тормозит. Поэтому спрашиваю, как его используют, особенно в случае, когда БД уже существует.

Нет, но извините. И вопрос тот же: как в случае Hibernate угадывают джава классы по таблицам? И насколько хорошо?

Как угадать java-классы для, например, s.dou.ua/...​-files/image1_Fh1bISl.png ?

Вы знаете? Поделитесь рецептом, пожалуйста.

Иначе как мне догадаться, что это простецкая схема создалась из таких классов dou.ua/...​les/how-to-use-hibernate — раздел «Правильные entities». И ладно аннотации, а там у автора ещё бизнес-методы в них.

Насколько втупую? Как в разделе «Обычный подход»? Потом с ними очень неудобно работать, в сервисах начинается код по доставанию данных из разных таблиц вперемешку с бизнес-логикой.

Если написать

@Entity
@Table(name = "orders")
public class OrderEntity {
   @Id
   private Long id;
   // ...
   private Long clientId;
}

...нужно вызывать потом метод по получению Client-а по его ID.

в Хибернейте есть фича генерации DDL по маппингам в коде,
вот ТС и решил «сэкономить».

В некоторых (хороших ) книгах по Хибернейту так работают примеры кода- база генерится «на лету».
Но в продакшене так не делается.

Почему? Необязательно ведь Хибернейту DDL в базу разрешать, но можно же взять сгенеренную схему в скрипт flyway.

ну да, первичен скрипт для создания БД.
вокруг БД и строится приложение.

Но в продакшене так не делается.

Насчёт Java не возьмусь утверждать, а в .NET, Ruby, NodeJS, Python — ещё и как делается.

ТС хочет, чтобы с его ORM — опа — сгенерилась кошерная БД.
ну, предположим, тулза правильно угадает таблицы, поля.
А индексы, триггеры? Не-не, блуд это.

Индексы — вообще без проблем:

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .HasIndex(p => new { p.FirstName, p.LastName });
    }

(а в некоторых ОРМ можно навешивать индексы прямо атрибутами / аннотациями)

Триггеры — можно через миграции или database initializers, но есть хитрый нюанс: ОРМ ничего не будет знать об изменениях, внесённых в данные триггером.

Честно говоря, с появлением ОРМ я вообще не помню случая, когда нужен был именно триггер.

Да, в дотнете это так,
но Джава имеет другую экосистему, более разнообразную и дикую.
Поэтому код и скрипты БД обычно поддерживаются параллельно.

Есть мнения, что он тормозит

Так і Java тормозить, це не проблема хібернейту.

У меня есть небольшой опыт работы с Hibernate (см. статью). Я понимаю, как по классам строятся таблицы — это делает фреймворк. Я спрашиваю, как угадать классы по таблицам.

вы пытаетесь получить молоко без коровы))

не надо угадывать.
База должна в точности быть такой, как надо по бизнес логике.
На базу делается маппинг вашего кода.

А если БД уже есть?

Обычно так и делается. Базе и должен соответствовать маппинг.
Опять же, к одной и той же БД можно примапить классы по-разному,
в том-то и задача, чтобы маппинг соответствовал особенностям приложения.

-

Підписатись на коментарі