Комментарии 259
ORM дает общую обертку над кучей разных СУБД, у которых часто разный синтаксис, несмотря на SQL92 стандарт.
Дело даже не в обертке — все равно большинство проектов использует на протяжении всей жизни одну и ту же СУБД — а в уменьшении количества разного рода boilerplate кода.
С ORM код становится проще и понятнее, и поддерживает автоматические плюшки типа миграций и рефакторинга.
Код с чистым SQL выглядит намного более громоздко (простыни SQL на десятки строк), понимается на самом деле сложнее (так как более многословен и часто требует дополнительных усилий по сериализации и десериализации данных).
Как только вы напишите один и тот же sql запрос в 6 местах, а потом нужно будет его поменять, возможно, вам захочется вынести это в отдельный метод.
А потом еще замапить данные на объект окажется неплохо.
И вот у вас ORM.
Как только вы напишите один и тот же sql запрос в 6 местах, а потом нужно будет его поменять, возможно, вам захочется вынести это в отдельный метод.
Ну вы же не пишете один и тот же кусок кода в 6 разных местах. Зачем это делать с SQL?
Значит вам надо выносить это в отдельную функцию, как я и описал.
Когда вас будет несколько — вы тоже не очень будете знать, какой же там запрос написал тот человек. Ну а необходимость залазить и смотреть, что же там написано приводит нас к такой же проблеме как ORM, в которой надо просто включить логгирование запросов.
В простых случаях и человек, и ORM ведут себя довольно предсказуемо, а вот как начинаются сложности, тут сложно сказать, что хуже, ORM или человек, который плохо пишет запросы.
В общем случае человек который плохо знает SQL и пишет его, лучше чем человек который плохо умеет ORM и пишет его.
Потому что проблема в SQL видна сразу, а проблема в ORM — нет.
Потому что проблема в SQL видна сразу, а проблема в ORM — нет.
select index, name, state from user_address where state like 'U%' and index >= 6
Подскажите тут проблему?
База пусть будет PostgreSQL.
Кроме той что index возможно строка. Но это не проблема голый запрос просто упадет с ошибкой.
Проблема ORM в том, что он генерирует запрос который «вроде бы правильно работает». И в итоге нужно смотреть что же он там нагенерил и перепроверять.
Соответственно если я могу проверить корректность запроса — зачем мне ORM я и так могу написать нормально.
А если не могу — то давать мне ORM это почти тоже самое что давать обезьяне гранату.
Если вы знаете как работает конкретный ORM — то в большинстве случаев не нужно. В крайних случаях приходится, но абсолютно так же надо будет смотреть что же там написал коллега.
Проблема сырых запросов в том, что ORM делает за вас очень много вещей для поддержки схемы данных и отображения ее структуры в коде. А так же ленивые выгрузки данных, кеширование, инструменты для пре- и пост-процессинга запросов и так далее.
Ну и так же, что вам все равно нужен минимальный ORM (который будет доставать результат из запроса и запихивать в объекты) для нормальной работы.
И если программисты, когда им нужно одно поле одной записи, вытаскивают из таблицы абсолютно все значения, они и с sql будут делать так же, если не хуже.
Автор же не имеет ничего против поддержки схемы, кэширование итд. Но ведь запросы можно же писать с использованием SQL. Не обязательно для этого новый язык придумывать.
Для задачи минимального маппинга есть Jdbc template.
Он делает ровно то что должен и ничего больше. Мапит result-set на объект.
Дело в том что ORM поощряет доставать всю таблицу чтобы получить одно значение, а SQL — нет.
Мне кажется, вы говорите про какую-то конкретную ORM и распространяете ее проблемы на всех.
Сначала конкретно про автора — он не шарит и применяет ту же логическую ошибку, что и по всей статье — у вас нет единого SQL. А значит вам все равно нужно изучить конкретную базу, что бы шарить с ее SQL диалектом, индексами, настройками и прочим.
А после этого вам нужно будет искать инструмент, который позволит вам поддерживать схему базы данных в актуальном состоянии, распространять эту схему, версионировать, генерировать миграции. И разумеется, мапить на объекты. А значит держать схему в коде.
Потом получится, что вместо того, что бы писать условный блок кода:
with connection() as conn:
query_raw_result = query.execute('select * from x where x.c > 5)
record = mapping(query_raw_result)
Вы напишите свою функцию и привяжите ее к классу, в который мапиться результат. Потом таких функций будет все больше и больше — и после рефакторинга вы получите легковестный orm способный на простые select/insert/update
, а все остальное вы будете писать пока сырыми запросами. Ну и оно будет немного расширятся.
Мне кажется, такой вариант вполне реальным, потому что я сам через такое прошел. ORM позволяет вместо изобретения своего велосипеда использовать стандартизированный.
Дело в том что ORM поощряет доставать всю таблицу чтобы получить одно значение, а SQL — нет.
Мне кажется, если у ORM отдельный метод на достать все и отдельный метод на фильтрацию — доставать все будет только оооочень плохой человек. А в sql можно просто where
завтыкать написать и готово.
ORM это хорошо когда у вас простые однострочные запросы. ORM плохо когда надо через него генерить сложные вложенные запросы с аналитическими функциями. Вот где адок начинается.
И в таких случаях используется или сырой SQL или же специальный класс, за которым скрывается view, который тоже написан на сыром SQL.
И лично я не вижу в этом проблемы. ORM для рутинных запросов, сложные запросы на сыром SQL.
Если вы используете ORM, у вас нет обязанности вот прямо все запросы писать на ORM, но большинство запросов, которые будут обычные select с парой фильтром или же insert вполне можно отдать ORM.
Как вы представляете использование сырого SQL на языках программирования, в которые они не встроены?
То есть, вместо условного T1.objects.filter(pub_date__lte=5)
мне стоит написать сырой sql запрос? Довольно много лишнего кода получится.
Плюс я еще могу писать что-то в духе T1.expired()
как алиас для запроса.
Опять же таки, а как решить вопрос поддержки схемы базы данных, которая должна хранится в коде? Хранить схему в базе это полный треш, а отдельно от проекта мне кажется, не имеет смысла.
Но если вы все-равно мапите результаты запроса на ваши доменные объекты, то проверить соответствие этих доменных объектов структуре базы не представляется сложным. Можно даже использовать стандартные аннотации.
P.S. Все что я говорю относится к Java.
Если я вас правильно понимаю, то вы предлагаете подход database-first, когда база данных служит источником схемы. По идее, это очень трешовый подход связанный с большим количеством проблем и рассинхронизации.
Поэтому обычно предпочитают вариант, когда используется code-first и схема базы управляется непосредственно из кода.
То есть вам все равно нужен ORM, пусть и без возможности составления запросов.
вы предлагаете подход database-first, когда база данных служит источником схемы. По идее, это очень трешовый подход связанный с большим количеством проблем и рассинхронизации.
Отнюдь — habr.com/post/413597
Ну и может я читал плохо, но я так и не нашел инструмента, который вы предлагаете использовать, что бы синхронизировать схемы базы на разных окружениях. Если этот инструмент «sql-скрипт» или «админ», то вас ждет очень много боли.
Это ваши java/hibernate проблемы, правда. У нас вот на python/django таких проблем нет и пишутся модельки прямо из кода, потом создаются миграции и все это чудо няшно работает.А вы внимательно прочитали статью? Там вообще-то универсальные проблемы. Создаст ли ваш мигратор индексы? А в нужном порядке? А все ли он правильно сделает? А не снесет ли случайно колонку с данными? На проде между прочим. Поэтому тут я согласен, мигрировать базу можно только чистым SQL и никак иначе. В противном случае на то, чтобы проверить что мигратор реально ничего не поломал вы потратите раз так в 5 больше времени чем на написание честного SQL обновления.
Отбросив вопрос про "все ли он правильно сделает", который применим в целом в sql скрипту в том числе, могу ответить одной фразой — "там прямо написано".
Миграции выглядят как-то так и все, что они сделают, в них написано. Поэтому проблема в том "а не сломает ли нам что-то мигратор" у нас обычно не стоит.
А в дополнение к этому еще можно вести версионность и зависимость между миграциями.
Ну и да, я имел дело с миграциями на чистом языке запросов и это всегда очень классно, потому что нужно самому отслеживать состояние схемы и угадывать, что уже было накачено, а что только нужно накатить.
потому что нужно самому отслеживать состояние схемы и угадывать, что уже было накачено, а что только нужно накатить.
Зачем есть же тонна инструментов для этого. Тот же flyway.
Если я вас правильно понимаю, то вы предлагаете подход database-first, когда база данных служит источником схемы. По идее, это очень трешовый подход связанный с большим количеством проблем и рассинхронизации.Что делать если новый код мы написали и развернули, а миграцию должны выкатить позже?
Вы написали код, который использует новое поле, но миграцию для него, которая добавит поле в таблицу не сгенерировали или что вы имеете в виду?
Ну, миграции вы накатываете отдельной командой. Так что прямо во время запуска приложения всей кучей они не ломятся.
Как в ORM с миграциями когда надо добавить новую колонку, а заполнять надо данными из другой таблицы?
Лишить премии? Новая функция не будет работать, если нет данных. Если у вас в коде IF, который фактически отключает эту новую функцию, то можно было и не выкладывать.
По уму нужно сначала миграции, потом код.
В нашем ORM есть случи когда пользователь создает тикеты на микрооптимизации то на параметр, то на использование той или другой функции. И мы соглашаемся что такое надо исправлять, ведь если мы не дадим ему этой возможности, ему придется писать голый SQL, что сводит усилия ORM на нет.
Также code-first по своей сути исключает возможность cross database запросов, по крайней мере в мире .NET
Как только в базе появляются данные — база становится легаси. Наличие *любого* Undefined Behaviour на вашем пути миграции означает, что базу придётся мигрировать вручную, т.к. ORM с высокой вероятностью в чём-то напортачит, а закрытый (может быть) баг в его процедурах миграции — слабое для Вас утешение.
(цитирую почти один в один вот отсюда, и практически целиком согласен с автором: blog.jooq.org/2018/06/06/truth-first-or-why-you-should-mostly-implement-database-first-designs)
базу придётся мигрировать вручную, т.к. ORM с высокой вероятностью в чём-то напортачит
Вы же видите миграции ORM, как они могут напортачить?
В том то и дело, что нужен. Потому что каждый раз мапить вручную — это полный бред. Значит писать под каждый случай функцию, которая достанет данные и замапит. Какой практический смысл в этом?
А вы попробуйте написать запрос с 5ью джоинами и сложными условиями.
А давайте попробуем.
$query = User::find()->as('u')->with('articles');
if ($cond1) {
$query->joinWith('profile p');
$query->andWhere(['<', 'p.age', 18]);
}
if ($cond2) {
$query->andWhere(['=', 'u.type_id', UserType::EXTERNAL]);
}
$users = $query->all();
// ------------------
// User.php
class User
{
...
function getProfile()
{
return $this->hasOne('profile', 'user_id', 'id');
}
function getArticles()
{
return $this->hasMany('articles', 'author_id', 'id');
}
}
Как это будет с использованием SQL?
В результате должен быть список пользователей с заполненным свойством $user->articles
, где находится список статей, написанных конкретным пользователем. Джойн естествено должен быть только если $cond1 == true
, $cond1
и $cond2
зависят от параметров GET-запроса.
StringBuilder sql = "Select articles from user "
if (cond1) {
join = ("join profile p on p.id = u.profile_id")
conditions.put("and p.age < :age")
}
if (cond2)
{
conditions.put("and u.type_id = :type")
}
sql = sql.append(join).append("WHERE 1=1 ")
condtions.foreach(sql::append)
SqlParameterSource namedParameters = new MapSqlParameterSource()
.addValue("age", 1)
.addValue("type": type);
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, User.class);
P.S. почему-то разметка поплыла не получается выровнять :-(
Ну во-первых, articles
это отдельная таблица со своими полями. Во-вторых, вы как-то незаметно пропустили объявление 2 важных переменных, а это тоже дополнительный код, который надо писать, читать, и поддерживать. К тому же вам было лень писать SQL-операторы капсом, что тоже сказывается на читаемости. В-третьих, если я правильно понял, queryForObject
возвращает один результат, а не список.
И даже если перевести ваш код в PHP, он все равно будет в 1.5 раза больше, чем код с ORM, и с увеличением количества WHERE
и JOIN
его будет больше. У меня 1 переменная для запроса, а у вас 4. И все их надо будет копипастить в другие места, где есть WHERE
и JOIN
. А если название колонки или таблицы в JOIN
поменяется, то искать по всему коду и исправлять.
Говорить про читаемость вот этого вот странного порядка я даже говорить не буду
$query->andWhere(['<', 'p.age', 18]);
капс исправить можно, а вот порядок не очень.
представьте что вместо query for object аналогичный метод для списка. Это не принципиально.
А какая разница сколько переменных если они инкапсулированы внутри метода. Это же не глобальные переменные.
Говорить про читаемость вот этого вот странного порядка я даже говорить не буду
$query->andWhere(['<', 'p.age', 18]);
Говорить на самом деле нечего — здесь все интуитивно понятно. Операция и два значения.
ну я пропустил 2 переменные, а вы их просто захардкодили
Так в том и смысл, что вам надо их объявлять, и по-другому никак) И у меня в строке не join, а название связи, а аналога conditions вообще нет, захардкожены только сами условия, как и у вас.
капс исправить можно, а вот порядок не очень
Если вы напишете не капсом, то ошибки не будет, и так оно и останется, а если порядок другой поставите, то будет, и придется исправлять. Порядок нестандартный конечно, но он просто непривычный для вас. Аргументы могут быть довольно длинные, и так получается читабельнее, чем выискивать короткий оператор в середине строки. Но если хочется, порядок тоже можно поменять, переопределив класс запроса.
если они инкапсулированы внутри метода
Так речь о том, как поддерживать код метода. Естественно, если там никогда ничего не будет меняться, то неважно что там написано. Хотя написание тоже удобнее получается.
Так в том и смысл, что вам надо их объявлять, и по-другому никак)
Можно точно так же захардкодить.
Если вы напишете не капсом, то ошибки не будет, и так оно и останется, а если порядок другой поставите, то будет, и придется исправлять.
Правильно настроенный check-style скажет все что думает о таком коде.
Аргументы могут быть довольно длинные, и так получается читабельнее, чем выискивать короткий оператор в середине строки. Но если хочется, порядок тоже можно поменять, переопределив класс запроса.
ну то есть это по сути класс-генератор sql запросов. Уверен если покопаться в java я таких же десяток найду только использующих стандартный синтаксис.
Можно точно так же захардкодить.
Ну конкретно в этом случае можно заменить на конкатенацию, потому что в sql
фактически только название таблицы, и ее можно считать началом джойнов. А если надо будет в SELECT
поля по условию добавлять?
Правильно настроенный check-style скажет все что думает о таком коде.
Ну вот, не только дополнительный код писать, а еще и дополнительные инструменты настраивать. Зачем, в чем профит-то?
ну то есть это по сути класс-генератор sql запросов
Не только, потому что джойны заменяются на связи ( R ), описанные в классе, условие джойна генерируется по ним. Можно даже превратить в many-to-many без изменения вызывающего кода.
И вы игнорируете что articles
это таблица. ORM по связям определит ключи, сделает второй запрос с IN
, и заполнит свойство articles
у всех объектов в списке users
. Для SQL будет джойн с дублированием строк таблицы users
или еще одна портянка кода c ручным распределением.
Уверен если покопаться в java я таких же десяток найду
Ну так вы же предлагаете пользоваться SQL вместо них) Разговор не о том, что есть, а о том, чем пользоваться.
Я веду к тому что в нормальных ORM используется не только фильтрация, а и в полный рост query decomposition. Склеиваете такие маленькие подзапросы, накладываея ограничения по доступу, и на выходе получаете взрослый оптимизированный запрос. Поверьте оптимизированный, намного лучше чем руками бы писал.
Сколько не смотрел на другие языки и их ORM, только .NET с его IQueryable позволяет такое делать типобезопасно и предсказуемо. Естественно зависит от linq провайдера. Мой выбор давно пал на linq2db
применяет ту же логическую ошибку, что и по всей статье — у вас нет единого SQL
Т.е. ребята из ISO и ANSI с 83-го года работают в пустую?
Конкретно про базу он начинает топить 42:53
youtu.be/o_TH-Y78tt4?t=2573
Не надо за ORM перепроверять. Если у вас запрос на 10 строк — пишите вручную, если хотите. А одну строку ORM сделает лучше и предсказуемее. Потому что защита от опечаток. Вы попробуйте просто.
Когда вас будет несколько — вы тоже не очень будете знать, какой же там запрос написал тот человек.А как же code review?
Сначала у вас функция, которая возвращает массив данных по клиенту. Потом вы захотите объект User. Потом, когда объектов много, вы захотите не делать под каждый объект функцию Something::getByID. Потому что зачем вам 50 одинаковых по сути функций?
Наверно, надо научиться пользоваться ORM?
Вообще, как по мне, так с ORM ты по итогу приходишь к тому, что оборачиваешь их ещё одним слоем абстракции как раз из-за того, чтобы не дублировать код построения запросов. И в итоге понимаешь что на самом деле тебе хочется просто удобно (за минимум манипуляций) мапить результат выполнения запроса на сущность, сохранив возможность писать чистый SQL
С сырым SQL — создать коннект, выполнить запрос? Ровно так же, как и с ORM нужно получить сессию и отправить запрос на выполнение. Ровно тот же самый код
P.S. У дядьки явно бомбануло, ему бы подорожничек приложить.
Поменять ORM или отказаться от него. Серебряной пули не бывает, у любого решения есть как преимущества, так и недостатки. Но я ни за какие плюшки не перейду с хорошего ORM на чистый SQL.
хорошего ORMКак понять хорошии или нет?
По опыту использования скорее всего. Я вот пользуюсь одним ORM уже 10 лет, и если первые 3-4 года приходилось иногда писать чистый SQL, то в последнее время он развился до такого уровня, что я уже не могу вспомнить, когда мне в последний раз пришлось писать чистый SQL. При этом я постоянно просматриваю запросы, которые он генерирует, и меня в них все устраивает.
Так что на этот вопрос тоже однозначного ответа дать нельзя. Только читать документацию и пробовать использовать.
Встроенный в Django: https://docs.djangoproject.com/en/2.1/topics/db/models/
Django ORM хорош когда нужно сделать что-то простое, это и правда удобно. Когда же нужно сделать что то не стандартное то появляется ощущение что у тебя все колесо в палках.
И согласен, и нет.
Django is a quite opinionated framework. Со временем просто привыкаешь не писать поперек линованной бумаги, и количество палок резко снижается.
А вот с legacy database это полный ад, да.
В качестве дисклаймера: я, на самом деле, django orm не люблю. Автокомплит в разных редакторах от плохого до омерзительного, паршивая расширяемость, куча магии плюс сильная заточка под OLTP, так что при малейших поползновениях в сторону аггрегации/аналитики удобней откатиться в сторону raw sql.
Но вашей проблемы я не прочувствовал :)
Если миграцией базы управляет django, то есть https://github.com/rapilabs/django-db-constraints, ну или на худой конец sql прямо в миграциях.
Если база управляется извне, то в чем проблема c unmanaged моделями-то?
Если же и так и так, то в проекте есть проблемы посерьезней, чем выбор орм =)
Перформанс из рук вон плох, и это даже не из-за Django, а из-за того что он мало чего позволяет из мира SQL.
С ORM код становится проще и понятнее, и поддерживает автоматические плюшки типа миграций и рефакторинга.
Еще большинство ОРМ сами санитайзят параметры, т.е. бесплатная защита от инъекций.
Самому за этим везде следить — бОльшая вероятность допустить ошибку.
Действительно проблема уже не очень актуальная, тем не менее до сих пор периодически натыкаюсь.
И как сделать ps для SELECT когда количество входных параметров варируется? :)
Кстати, criteria API для РСУБД тоже монстр, в mongo API всё на порядок продуманнее. Ещё и транзакции прикрутили в Монго 4.
Итого сейчас муки выбора sql vs orm почти не возникают, т.к. почти всегда больше плюсов у mongo. Но ретрограды, конечно ещё не все умерли :)
Уверен, что через java mongo API ничего такого в принципе не сделать. А проблемы вызывает обезьянний JS-код с использованием eval и прилепленными входными данными. Но это уже никак не проблема Монго.
const { name } = JSON.parse(query);
userModel.findBy({ name: name });
Вот в этом коде может быть инъекция
В твоем примере, допустим query пришло извне и никак не проверяется. В итоге, оно либо распарсится в объект, либо не распарсится. Где инъекция-то? :)
Вот тут: { name: name }
. Автором кода предполагается, что name — строка, но реально тут может быть запрос любой сложности.
Возможно, что утечки данных и правда не произойдет — но DoS через километровый запрос организовать можно и попробовать.
В твоем примере, допустим query пришло извне и никак не проверяется. В итоге, оно либо распарсится в объект, либо не распарсится. Где инъекция-то? :)
Ну ладно. Представьте такой код:
const { name, token } = JSON.parse(query);
userModel.findBy({ name: name, token: token });
И вот пользователь вместо
{ name: 'Вася', token: '123e4567-e89b-12d3-a456-426655440000' }
Передает такое:
{ name: 'root', token: { $ne: '1' } }
Догадываетесь, какой будет результат?
«прогера» будут больно пинать ногами на первом же ревью?
Я даже у джунов никогда такой откровенно притянутой за уши ереси не встечал. Это не аналог SQL-инъекции, а из разряда взять и полностью выполнить SQL запрос пришедший с веба. Таким образом можно вообще любую СУБД положить, если делать максимально идиотские вещи.
Нет инъекций. Почитай для начала что это такое.
Когда findBy(блабла) сделает insert(блабла) тогда и приходи.
Проблемы js-макак решайте без меня, если они есть. Все примеры выше выглядят очень сильно искуственными или вообще неработоспособными. Инъекция это или не инъекция мне тоже фиолетово.
В монге, кстати, тоже инъекции бывают, особенно при использовании языков с динамической типизацией (таких как javascript).
А ты сказал, что только если eval использовать. А я доказал, что это не так. Так зачем тут распинался, если тебя не волнует?
У тебя корона как у Джобса, а знаний и опыта как у краба. Подтянись немного перед тем, как в такие споры вступать и научись признавать свои ошибки.
Если дыра у JS-макак, не надо со своей больной головы на Монго перекладывать.
Да у меня опыта в JS как у краба. И слава богу. И надеюсь не добавится.
Пока что я о таких случаях не слышал, но это случайность. Разбирать JSON через DOM вместо десериализации индусы уже умеют, осталось дождаться когда JSON-десериализаторы научатся использовать BSON-объекты.
JS-макак
Ты — самовлюблённый сноб, ты знаешь об этом? Питон, кстати, имеет точно такую же уязвимость. И, главное, в Джава есть пакет
com.mongodb.util.JSON
, который точно так же позволяет произвольный JSON привести к Монге.DBObject dbObject = (DBObject) JSON.parse(
"{ name: 'root', token: { $ne: '1' } }"
);
Так и тут. В жабе есть куча сериализаторов получше. Но зачем прогонять через них непроверенное абы что и потом выполнять Монгой? Если считаешь, что это уязвимость в Монге, сделай себе инъекцию эвтаназии уже.
Это особенности использования. Если я буду ехать на спорткаре на полной скорости и специально въеду в дерево — это ведь не ошибка создателей спорткаров. Но я могу разбиться на спорткаре и это факт.
Так само и здесь. Монго — прекрасен, но любому, кто его использует важно понимать, что он не прикрыт со всех тылов, а он может наглупить и создать уязвимость в своем приложении
ОК, открытие недели: если в Монго запустить некий код, этот код что-то сделает. Британские учёные отдыхают!
Если в Монго передавать неотфильтрованный ввод пользователя, это может вылиться в уязвимость в вашем ПО. Это называется инъекция. Именно об этом мы и говорили. И именно о такой возможности вы еще пару дней назад не догадывались, а теперь стараетесь построить хорошую мину при плохой игре
Джава дебилы совсем охуели…
Единственное что я узнал из этой ветки
То, что ты не способен к обучению и познанию — я уже понял. Но тут нечем гордиться
Если считаешь, что это уязвимость в Монге
че за бред то? В каких вообще дб есть уязвимости к инъекциям? Ни в каких. Уязвимости в коде.
Во всех приличных СУБД защита от инъекций уже встроена. Используйте биндинги и враг не пройдёт.
ORM дает общую обертку над кучей разных СУБДКак часто вы меняете СУБД?
Меняем не часто а вот добавить новую — это вот бывает. У меня например через Eloquent безшовно связаны 2 таблицы одна из mysql а другая из postgres.
Если бы писать запросы — тогда я бы путал сам язык запросов разных баз особенно если бы залез в этот код через пол года, а тут ORM сама генерит нужные запросы через лексер для нужной базы, и еще и хранит логическию звязь между таблицами.
Напрмер вытянув первую сущьность я могу через нее вытянуть вторую и на лету обновить её, хотя вытянул из postgres а обновил в mysql и все это 3 строки кода.
Запросами вышло бы на 20 без отлова ошибок.
Вы же знаете, что на самом деле у каждой реляционной базы данных свой диалект SQL и этого вашего мифического "SQL", который единый стандарт не существует и каждую базу все равно надо изучать, так как какие-то фишки работают не так, а какие-то не работают?
Следовательно пост не имеет никакого смысла.
Следовательно пост не имеет никакого смысла.
Странный вывод. Вспомнился текст из защиты Чуббаки
Я вполне понимаю автора. Он хочет sql-подобный язык запросов. Он готов почитать специфику, но основная идея написания запроса должна быть похожая. И это есть в SQL, выборка пишется одинаково на любом диалекте, поддерживающем SQL92. Да, есть специфичные конструкции или функции, но они, как правило, расширяют стандарт. В случае с ORM, язык запросов часто настолько своеобразен, что без документации что-то написать сложно. Для примера, в мире Java есть Criteria API и JPQL. Последний сделали максимально похожим на sql, видимо была такая потребность. Наверное, дело вкуса, но читать даже небольшие запросы на Criteria API очень тяжело.
Так уж повелось, что в мире Java все, что имеет официальную спецификацию JSR, неудобно и эстетически неприятно. Зато сторонние библиотеки типа QueryDSL исправляют ситуацию. В большом проекте подобные type-safe врапперы сильно спасают ситуацию, например, когда нужно найти все места, где используется какое-то поле или таблица.
List<Person> persons = queryFactory.selectFrom(person)
.where(
person.firstName.eq("John"),
person.lastName.eq("Doe"))
.fetch();
Понятно, что синтаксис не один в один, но по логике формирования вполне. QueryDsl — это такой компромисс между типизацией из CriteriaApi и читабельностью SQL/JPQL.
Потому что куча программистов напишет запрос еще хуже?)
У девятой java вроде есть repl режим и можно интерактивно выполнять запросы и смотреть, что происходит.
У нас на python так сразу есть shell режим где можно оттестировать абсолютно все.
Ну то есть инструмент для генерации запросов генерит плохие запросы
Не, не так. Вот так: инструмент для упрощения работы с БД, который позволяет не писать много SQL кода и в большинстве случаев делает это неплохо, иногда генерит неоптимальные запросы. Так вот для многих задач это не критично. А там, где критично, надо тюнить или использовать нативный запрос. Как-то так.
Да, человек смертен, но это было бы ещё полбеды. Плохо то, что он иногда внезапно смертен, вот в чём фокус!
И если проверить sql запросто достаточно просто, то с запросо-генерацией все обычно чуть более запутанно. Да что там говорить, в гибернейте каждый релиз фиксят тонну багов. Я что-то не помню такого количества багов в SQL.
И если проверить sql запросто достаточно просто, то с запросо-генерацией все обычно чуть более запутанно.
В чем запутанность то? Включаем в опциях логирование запросов, получаем все sql запросы с параметрами. Дальше процедура ничем не отличается от sql запроса. В чем сложность-то?
Полагаю просто, что в простоте тестирования sql есть лукавство. Его более-менее легко тестировать, когда ты сам его только что написал. А когда это другой человек и прошло пару месяцев с момента написания, тогда все будет обстоять ровно также как и с sql от ORM.
Нормально написанный SQL нормально читается и через день и через месяц.
Я же не говорю, что ORM плохо читается. Читается то он замечательно. Но не всегда делает то, что написано.
Читается то он замечательно
Вот тут я бы поспорил, далеко не всегда.
Но не всегда делает то, что написано.
Делает то. Просто не всегда именно так, как вам хочется. Т.е. проверить запрос ORM именно на правильность несложно прямо в браузере, в code review (особенно какой-нить jpql).
Но в целом, я понял вашу позицию, вам просто не нравится ORM или он не подходит для ваших сценариев использования. Тогда просто не стоит его использовать и мучатся.
убедиться, что человек правильно написал ORM запрос
Можно человека попросить прислать вам что он нагенерит.
Ну и в 99% случаев для более сложных запросов используют «голый» sql.
И кроме того, вы достаточно уверены что во время review вы заметите где-то опечатку или то что все параметры правильно 'заэскейпены'?
String sql = "INSERT INTO CUSTOMER " +
"(CUST_ID, NAME, AGE) VALUES (:custId, :name, :age)";
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("custId", customer.getCustId());
parameters.put("name", customer.getName());
parameters.put("age", customer.getAge());
getSimpleJdbcTemplate().update(sql, parameters);
Тут все параметры типа Object. т.е. в age можно передать строку и это упадет только в runtime! И это еще запрос хорошо написан, с именованными параметрами, обычно для параметров просто используют вопросики и нужный порядок параметров. Только не надо говорить, что для этого есть код-ревью.
я где-то внизу уже писал про «эскейпинг». Если вы в 2к18-ом думаете об «эскейпинге» — в вашем проекте что-то не так.
В нашем проекте совершенно точно «что-то не так», но не все проекты идеальные. Согласен что это не очень важная вещь, но лучше с ней чем без нее.
И кроме того, вы достаточно уверены что во время review вы заметите где-то опечатку или то что все параметры правильно 'заэскейпены'?Для этого есть тесты
Я вот как раз сторонник вызова цепочки методов типа .select().where().where().fetch() вместо написания чистого SQL, особенно когда условия в where собираются динамично, т.е. может быть одно, а может и семнадцать, плюс пара джойнов, но красиво и понятно это выглядит только на простых запросах. Как только что-то чуть сложнее пары вложенных AND и OR с JOIN, так, как тут выше уже писали, без дебаггера и документации уже не разобраться, и быстрее выйдет написать SQL.
Закулисная магия, порождающая медленных уродцев, богомерзкие актив рекорды и прочие протекающие абстракции годны лишь для прототипирования, да на личные поделки авторам ORM, на 100% понимающим как оно там внутри работает.
У остальных же кодеров, зачастую, отнимают больше времени, чем экономят.
Для обычных CRUD-проектов же ORM очень сильно экономит время как на разработку, так и на поддержку. Просто за счёт отсутствия кучи бойлерплейта. Да, ORM может составить неоптимальный запрос, но это не всегда страшно. Даже если будет десяток лишних JOIN, то в базе с правильными индексами такой запрос всё равно будет обработан быстро. А потратив совсем чуток времени (даже не переписывая запрос на SQL, просто правильно настроив связи в ORM-запросе) всех этих лишних JOIN можно будет избежать.
ORM — предсказуемая вещь по части получения результата. С этим проблем нет. Результат может быть получен не самым оптимальным образом, но это будет именно тот результат, который нужен. А оптимизация с точки зрения быстродействия/памяти далеко не всегда критична. Мне проще потратить лишнюю условную тысячу рублей на железо, чем тратить скажем 10 тыс. в месяц на дополнительную работу программиста на написание и поддержку чистых SQL-запросов.
К тому же с ORM не такой уж и зоопарк. Для каждого языка программирования как правило не более 2-3 популярных решений, которыми все пользуются.
Да, в коде это выглядит на порядок понятнее, чем простыня из SQL. Кроме того, позволяет моментально отрефакторить или найти в проекте весь код, где есть обращения к конкретному полю. Поэтому я даже редко делаю кодогенерацию, а в замен использую aliases.
Есть еще офигенная библиотека JINQ, но она сейчас находится в standby. Хоть и рабочая, но с грядущими изменениями в JDK что-то боязно ее использовать в серьезном проекте.
Ну вот автор пишет, что ему не понятен синтаксис mongo, хотя в основе там лежат абсолютно те же самые операции insert, select (называется find), update, delete.
Что ему не нравится? Синтаксис вызова этих операций?
И это есть в SQL, выборка пишется одинаково на любом диалекте, поддерживающем SQL92
Вы не правы. Например, прочитайте, например, вот это. Между тем же PostgreSQL и MySQL существует приличное количество различий, которые будут мешать. В этом и смысл моего комментария — стандарта SQL не существует и вам нужно каждый раз учить новый диалект SQL, когда вы работаете с другой базой данных. И разница с NoSQL базами данных лишь в том, что они честно сказали, что сделают свой язык запросов, потому что эмулировать sql и потом отходить от стандарта во всех местах для них не имеет никакого смысла.
Автор же, предполагая, что SQL в целом один раз можно выучить и готово совершает ошибку и вполне возможно знает SQL на том уровне, на котором любой язык запросов можно выучить за 1-2 день.
Вы не правы. Например, прочитайте, например, вот это. Между тем же PostgreSQL и MySQL существует приличное количество различий, которые будут мешать.
Это просто еще один пример отступления от стандарта. То что реляционные базы это делают повод пожурить их, а не давать индульгенцию остальным.
Напомните мне хоть один стандарт, который все соблюдают полностью, хотя за его несоблюдение не предусмотрено штрафов.
Ах да, его нет. Абсолютно все стандартны нарушаются в том или иной мере, потому что они сложны в имплементации, не удобны, дороги, не продуманы и так далее.
Поэтому стандарт всегда будет нарушен, просто смиритесь с этим. Ну или штрафуйте, но конкретно в этом случае у вас не получится.
По nosql на самом деле не все так очевидно. Не всегда можно/стоит натягивать SQL на то, что под него не задумывалось. И тут я не понимаю, почему автор критикует mongo. Но в случае некоторых ORM замечания вполне адекватны.
Я вполне понимаю автора. Он хочет sql-подобный язык запросов
Не-не-не. Посмотрите внимательнее на примеры, которые автор критикует. Минимум три из пяти — SQL-подобные языки и он их называет свалкой
Вот да. Более-менее общепринятых стандартов SQL было несколько (89, 92, 99, 2003, 2008, википедия подсказывает, что есть еще 2011, и 2016). Причем, например, СУБД не может быть полностью быть SQL92-compliant и SQL99-compliant: стандарты противоречат в некоторых нюансах. Я из любопытства читал драфты этих стандартов — там изрядное количество какого-то лютого трэшака, который не реализует и не использует никто. Я не знаю, сколько надо выкурить самокруток из книг Дейта и Кодда и чем их надо забивать, чтобы придумать этот фарш. Ах, да, стандарт этот найти бесплатно не так-то и просто. Видимо из-за это оторванности от практики, закрытости и объёма этот стандарт никто не использует (в отличие от спек C++, C#, Java, ECMAScript и т.п.)
Я вряд ли ошибусь, если скажу, что 99% "SQL-совместимых" СУБД это MySQL(+Maria), PostgreSQL, MS SQL Server, Oracle и SQLite. Да-да, я понимаю, что есть еще кучка древних и/или нишевых (IBM DB/2, Sybase/SAP ASE, Terradata, MS Jet, H2, Firebird и прочая экзотика, плюс стали появляться облачные движки), но основная часть всё-таки первая пятёрка. Так вот, даже в этой пятерке шаг в сторону от SELECT name FROM users WHERE age > 18
сразу приводит к несовместимости. Именно поэтому поддержка нескольких СУБД не так-то и распространена, особенно без ORM. И, наверное, ни одна из них не реализует стандарт SQL.
А как эти СУБД "реализуют стандарт SQL"? А по принципу шведского стола: СУБД выбирает чуть ли не до абзаца чему именно соответствовать и говорит "я поддерживаю SQL". На этом фоне MS C++ просто образец дисциплинированности реализации стандарта.
И вишенкой на торте: у самих СУБД между версиями весьма большие различия.
Так что, да, "стандартный SQL" это миф.
Был у меня как-то разговор на эту тему https://twitter.com/GraminMaksim/status/1034745469413609472?s=19
ORM — это безусловно зло, но зло меньшее из возможных. Вопрос не в поддержке замены БД в любой момент, а в ортогональности системы типов любого языка и любой СУБД, не говоря уже о «стандартном» SQL, где она весьма маловменяемая. И в любом случае приходится делать трансляцию между этими несовместимыми системами типов каким-то способом.
И если не нравится, что ORM слишком умничает/тупит, то для своего проекта можно же и собственную прослойку навалять, причём такую, чтобы и нативный SQL допускала. Мне вот однажды нужно было специализированную под bulk inserts, так я написал, использую иногда.
Не факт. Я вот чем дольше программирую, тем меньше мне нравится концепция ORM… Она из серии "натянуть сову на глобус"… В реляционных БД нет никаких объектов и чтобы написать хороший запрос надо про объекты вообще забыть, а не пытаться как-то методы ORM в цепочку объединить. Да, само собой, в тривиальных случаях ORM работает хорошо, но если у вас что-то посложнее банального CRUD, то вам по-любому нужно знать SQL и проверять что там ORM сгенерил, а заставить ORM сгенерировать нужный запрос бывает тем ещё аттракционом.
надо про объекты вообще забыть, а не пытаться как-то методы ORM в цепочку объединить.
C SQL вы будете не методы ORM в цепочку объединять, а условия для WHERE и таблички для JOIN-ов в массивах собирать. Во вложенных.
в тривиальных случаях ORM работает хорошо, но если у вас что-то посложнее банального CRUD, то вам по-любому нужно знать SQL и проверять что там ORM сгенерил, а заставить ORM сгенерировать нужный запрос бывает тем ещё аттракционом.
Так почему бы не использовать ОРМ для тривиальных случаев и рукописные запросы (которые практически во всех ОРМ поддерживаются) для нетривиальных? Учитывая что подавляющее большинство запросов — как раз тривиальные, то только профит.
Учитывая что подавляющее большинство запросов — как раз тривиальные, то только профит.Каждый тривиальный запрос со временем может превратится в не тривиальный, и что, переписывать каждый раз?
Каждый тривиальный запрос со временем может превратится в не тривиальный, и что, переписывать каждый раз?
Да, но к этому моменту у вас на каждый такой "переписанный" запрос появится сотня новых тривиальных, на которых вы сэкономите.
В целом я согласен с изложенным, хоть и на мой взгляд притянуто немало лишнего. ORM по мне вообще должен всё реализовывать через компилируемые функции, иначе, на мой взгляд, это будет вообще не ORM. Но вот хороших ORM и впрямь не хватает. Был вариант отображения хранимых процедур в EF через XML-описание, но потом от последнего варианта отказались, а в поддерживаемом теперь варианте в самом коде отображение хранимых процедур ушло на вечность в backlog. Про Hibernate не интересовался в последние годы, может хоть он лучше.
Конечно, по мне неправильно притягивать сюда язык полнотекстовых запросов или запросов к разметке (XML, JSON). Не слышал, чтоб хоть что-то из этого входило в стандарт SQL, а запросы в XML и JSON нынче стандартизированы лучше, чем SQL. Вопрос, скорее, в избыточной на мой взгляд популярности JSON, т. е. в использовании его не только для тех целей, где он удобен, но и для тех, где он не очен удобен. Но это по мне совсем другой вопрос.
Что за ORM подразумевался здесь, мне интересно, кстати. Может, тот самый Hibernate.
Не слышал, чтоб хоть что-то из этого входило в стандарт SQL, а запросы в XML и JSON нынче стандартизированы лучше, чем SQL.
C 2003 года XML точно входит: https://en.wikipedia.org/wiki/SQL/XML
А вот SQL/JSON вроде только в 2016 году в стандарт добавили.
Давайте делать посты не поста ради, а так, чтобы позже их можно было найти и использовать по делу?
"У рыбы нет шерсти, но если бы была, то там жили бы блохи..."
Еще некоторые стесняются схемы «ключ-блоб» и с умным видом говорят: «а у нас тут вообще никакой схемы то и нет».
я должен изучить 34 разных ORM
А еще все эти продукты SaaS
Что-то все в кучу. Каким боком Adwords это ORM?
Нативная для языка часть называется LINQ (Language INtegrated Query)
Автор не хочет учить все ORM. Я не хочу учить все подводные камни всех баз данных.
Проблема вот в чем. Автор не хочет учить ORM и может справиться без этого.
Но вот лично вас подводные камни баз данных достанут в любом случае (на промежутке времени стремящемся к бесконечности).
Потому что главное свойство абстракций — они протекают. И не сможет вас ORM от всего прикрыть, более того еще и своих проблем докинет для счастья.
P.S. Idea замечательно умеет автодополнение для SQL.
src
+--sql
+--packageXx
и в sql складывать .sql файлики которые собирались как встраиваемые ресурсы. Таким образом их можно было отдельно тестировать и обеспечивалась связка с конкретной версией бинарника. А код работы с базой был в виде ВыполнитьЗапрос(ПолучениеЗаказовПоИд).
Может быть кто-нибудь уже пробовал так же делать и может рассказать связанные с этим подходом грабли?
Начнем с ORM. Их основная фича — это сокращение времени разработки
Не просто разработки, а поддержки — тут кроется маленькая, но существенная разница.
Я стесняюсь указать на слоника притаившегося в комнате, но…
Во-первых ORM в большинстве своем это таки DSL (domain specific language, где предметной областью является C(Q)RUD). То, что семантика распихана по нескольким файликам, часть из которых на привычном ОО-языке, не более чем попытка не слишком пугать программиста. Тот же Hibernate нормально преобразует все эти удобства в весьма формальную модель и генерит кучу байткода на лету, существенно не отличаясь от DSL компилятора.
Во-вторых SQL как бы не работает с любой произвольной структурой данных. Как минимум требуется (даже логически) первая степень нормализации, чтобы можно было вообще произносить слово "таблица", а для слова "ключ", в его нормальном понимании, хорошо бы иметь как минимум вторую. Упомянутые вами Splunk и Lucene как раз специфические языки и придумывают от того, что "поток частично структурированных сообщений" и "некоторое количество коллекций гетерогенных слабо-структурированных документов" несколько не ложатся на любимые всеми таблички.
В общем не надо бояться языков, тем более что большинство из DSL-ей простые как дрова. Если вы справились с SQL, маппингом в ОО, транзакциями через аспекты и реляционной алгеброй, все вариации на тему "100500 способов описать логический фильтр" для вас проблем не составят.
Про ОРМ — настолько феерический бред, что не могу не отметиться.
Все звучит красиво, пока твои потребности умещаются в select * from table. В реальности же… ну, давайте на примере DSL Django ORM (первое, что в голову пришло).
queryset = User.objects.all()
if len(statuses) > 0:
queryset = queryset.filter(status__in=statuses)
if last_comment:
queryset = queryset.filter(user__post__comment__сreated_at__gt=last_comment)
if signed_in_from:
queryset = queryset.filter(signed_in__gte=signed_in_from)
if signed_in_to:
queryset = queryset.filter(signed_in__lte=signed_in_to)
cnt = queryset.count()
admins = queryset.filter(is_admin=True)
data = admins[:100]
Знакомая ситуация? Думаю, да. Неужели кому-то по кайфу каждый такой запрос обписывать этим всем ворохом " AND ".join(chunks) и прочей бесполезной белибердой????
Но это всё не отменяет того, что нужно хорошо понимать особенности работы БД, причём довольно глубоко
Последних должно быть больше, но не общеупотребимых, а действительно специализированых под конкретную, может быть даже бизнес, задачу. Ну и разумеется их тоже нужно делать и применять обоснованно, а не потому, что думать лень.
Если точнее то имеем GKE + Stackdriver + json logging + export to BigQuery + BigQuery.
Поиск по логам в Stackdriver Logging. Если нужны какие-то агрегации или статистика за большой период времени то в BigQuery.
Одна из важнейших проблем sql — в чем? В том, что sql-конструкции не являются частью языка, а искусственно вставляются в него через «строки». А потому возникает необходимость эти строки «склеивать».
Если же sql был бы нативной частью языка (да еще поддерживал бы условные джойны или условные добавления where-выражений), плюс имелся бы слой, который из “select *” сразу возвращал бы объект предметной области, а не «ассоциативный массив», то и получилось бы то, что хочет и автор, и комментаторы: с одной стороны, это чистый sql (ну почти), а с другой, отсутствует boilerplate (прямо как в orm).
Много лет назад я пытался что-то в этом направлении делать (а именно, язык условного построения джойнов и where-выражений без склейки строк), получилось github.com/DmitryKoterov/DbSimple/blob/master/README.txt (см. там {}-конструкции и плейсхолдеры типа ?a, в них самая соль). Но это все очень старое и было давно, плюс оно по-прежнему оставалось строками (хотя строками уже совсем другого рода, практически атомарными), плюс не было слоя возврата/сохранения объектов, типа как $mapper->save($object) или $object = $mapper->get($id).
Пример оттуда для иллюстрации идеи:
$rows = $DB->select(' SELECT * FROM goods g { JOIN category c ON c.id = g.category_id AND 1 = ? } WHERE 1 = 1 { AND c.name IN(?a) } LIMIT ?d ', (empty($_POST['cat_names'])? DBSIMPLE_SKIP : 1), (empty($_POST['cat_names'])? DBSIMPLE_SKIP : $_POST['cat_names']), $pageSize );
Сам я тоже предпочитаю ORM, однако считаю, что ежа с ужом скрестить в теории вполне можно, только почему-то этого особо не делают.
Одна из важнейших проблем sql — в чем? В том, что sql-конструкции не являются частью языка, а искусственно вставляются в него через «строки». А потому возникает необходимость эти строки «склеивать».
www.jooq.org
Вообще, когда некто гребёт все NOSQL в одну кучу, сразу становится понятно его место в жизни :) Скорее всего его дальнейший полёт мысли заключается в том, что NOSQL и ООП не нужны, есть ведь могучий SQL и какой-нибудь Cobol!
По существу: пусть прикрутит к neo4j свой SQL. Или к Cassandra, а потом рассказывает как всё предсказуемо и прозрачно работает.
А у господина автора посыл «если б не надо было учить все эти не-SQL языки, я бы был огого-админом любой СУБД».
И что примечательно, что active record — это то что принимается легче чем SQL. Естственно, на них легче накрутить патерны репозиторий, UoW, и вообще забыть что такое база данных и как ее готовят. И тут всплакнули алгоритмы оптимиций баз данных, их просто обошли сторной,. Да и зачем, есть id, мы по ней прыгаем, по них удаляем, джоины практически на клиентской стороне делаем. А кеши! Вот она панацея от неугодного «кверяния».
Да не обижу знатоков EF, знающих как обходить его ухабы, просто советую не зацикливайтесь.
https://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext(v=vs.113).aspx
A DbContext instance represents a combination of the Unit Of Work and Repository patterns such that it can be used to query from a database and group together changes that will then be written back to the store as a unit.
В таких проектах я вообще не использую хранимые процедуры и прочую SQL-логику. Да, с ними быстрее, но бизнес-логика раскидывается по разным местам, и становится сложнее тестировать и отлаживать.
Если вы разрабатываете приложение, где скорость критична и нужно отлаживать каждый запрос — это одно дело. А если мощностей хватает, то разрабатывать в ORM куда быстрее и приятнее.
Зато программист теперь сможет писать чисто бизнес-логику, не задумываясь о бойлерплейте. И становится гораздо легче подключать падаванов к работе, так как есть чёткий и понятный API.Ну так разнесите код по уровням, DAO и Service.
Я противник патерна репозиторий и уж тем более generic repository, так как считаю что вместо улучшения кода они порождают тучу затычек да и время разработки увеличивают раза в два.
Хотите тестировать, тестируйте на эталонной базе функциональными тестами. Да это медленней, но это чертовски как надежней. И констрейнты срабатывают и хранимки дергаются.
Поделюсь болью…
Работаю с СУБД с 1992, разные прослойки между базками и приложениями появлялись и забывались, а SQL продолжает спасать производительность, когда оптимизация на уровне ORM бессильна.
Последнюю боль, NHiberbate, 10 лет назад внешние консультанты втолкнули в архитектуру.
Толпы братских народов налопатили перлы и получили монстра. SQL Profiler давно уже забросили как бесполезный — ORM генеримые запросы бесполезно трейсить в профайлере.
Переход на облако подвис т.к. ORM генерит немерянное кол-во запросов и если в дата центре этот траффик не заметен, то с переходом на облако общение между application layer и базкой серьезно подтормаживает и выхода не видно, кроме как переписывать наиболее тормознутые куски с ORM на оптимизированные SQL запросы.
Толпы братских народов налопатили перлы и получили монстра.А, виноват то хибер конечно, а не те самые толпы братских народов.
ПС: вполне живу с хибером в облаке, просто его тоже надо писать оптимально, как и обычный SQL.
SQL Profiler давно уже забросили как бесполезный — ORM генеримые запросы бесполезно трейсить в профайлере.
Ха-ха-ха, очень смешно… Правда, с NHiberbate я не работал — но запросы тех же EF и linq2sql отлично трейсятся в профайлере.
А чтобы не было "огромного числа запросов" — надо отключать ленивую загрузку данных после выхода проекта из стадии прототипа.
А чтобы не было «огромного числа запросов» — надо отключать ленивую загрузку данных после выхода проекта из стадии прототипа.Хм, если на проде не нужна ленивая загрузка, зачем она нужна на стадии прототипа?
Код проще получается, пишется быстрееА код разве не один и тот-же что с ленивой загрузкой что без?
Нет. Вот так выглядит ленивая загрузка:
var list = db.Foos.Where(a => a.Id = id).ToList();
foreach (var foo in list)
{
Console.WriteLine(foo.Bar.Baz.Message); // +2 запроса при каждом выполнении строки
}
А вот так — без:
var list = db.Foos.Where(a => a.Id = id).Include(a => a.Bar.Baz).ToList();
foreach (var foo in list)
{
Console.WriteLine(foo.Bar.Baz.Message);
}
UPD: сам нашел. Судя по документации, в Hibernate нельзя полностью запретить ленивую загрузку — отсюда и возможность кучи запросов. В EF все немного не так — там при отключенной ленивой загрузке первый кусок кода просто упадет с NullReferenceException. Мне кажется, этот вариант более устойчив к "толпам братских народов".
Вот так без, и черт, я очень надеюсь тут не надо писать AsNoTracking()
var query = db.Foos
.Where(a => a.Id = id)
.Select(a => a.Bar.Baz.Message);
foreach (var m in query)
{
Console.WriteLine(m);
}
Каждый SaaS-продукт должен предоставлять возможность скопировать все данные в мою собственную SQL БД
Как быть с тем, что подобные продукты подразумевают огромные объемы данных.
И процесс копирования может быть даже медленее, чем процесс порождения новых данных в исходной БД?
Кстати, а что скажете о качестве перевода? А то мне тут пишут, что все очень плохо, например что rant неприлично переводить как «напыщенная речь».
да, SQL — неидеален, но действительно понятен.
и раз выучил и всегда используешь.
а запомнить 100500 DSL у разных ORM — довольно напряжно, притом с сомнительной выгодой.
есть, конечно, приятные исключения вроде «абстрактного» SQL, который конвертится уже в специфичный для конкретной БД (вот у hibernate например).
Я не буду учить твой Garbage Query Language