Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Только для статических запросов, но это как раз неинтересно. Сила linq-подобных инструментов в динамической композируемости запросов, которую никак на этапе компиляции не обработаешь.
_>Это тебе так кажется) Вот та же самая склейка sql строк по твоему позволяет делать динамические запросы или нет? ) Или ты считаешь, что нельзя сделать инструмент, задающий эту же самую склейку, но автоматически на этапе компиляции? )
Ты не очень понимаешь о чем разговор.
Вот пример.
Берем неэффективный SQL запрос:
select * from Employee e
where
(@lastName is null or e.LastName = @lastName)
and (@firstName is null or e.FirstName = @lastName)
and (@employmentDateFrom is null or e.EmploymentDate >= @employmentDateFrom)
and (@employmentDateTo is null or e.EmploymentDate <= @employmentDateTo)
Делаем из него эффективный запрос на C#:
var query = context.Employees;
if(!string.IsNullOrEmpty(lastName)) query = query.Where(e => e.LastName = lastName);
if(!string.IsNullOrEmpty(firstName)) query = query.Where(e => e.FirstName= firstName);
if(employmentDateFrom.HasValue) query = query.Where(e => e.EmploymentDate >= employmentDateFrom.Value);
if(employmentDateTo.HasValue) query = query.Where(e => e.EmploymentDate <= employmentDateTo.Value);
//далее в Presentation Layer (в другом классе и другой сборке)var list = await query.Take(pageSize).Select(e => new {/*projection*/}).ToListAsync();
Теперь покажи как сделать "инстумент, задающий эту же самую склейку, но автоматически на этапе компиляции".
Естественно все параметры зависят от ввода пользователя и невозможно их вычислить на этапе компиляции.
Разделение на слои тоже является обязательным. А проекция в PL может видоизменить запрос, что появятся join_ы.
G>>Попробуй не ограничиваться C#, и предложи другой способ.
_>Ну лично мне нравится например такое https://github.com/rbock/sqlpp11 решение. Потому как оно является полным отражением sql, только статически типизированным и т.п.
Покажешь как в нем сделать:
1) Джоины
2) Группировки
3) Проекции
Так чтобы все это было типизированно. То есть чтобы тебе компилятор не позволил обратиться к полю X результата, если оно не указано в проекции.
Без этого называть "полным отражением sql" противоестественно.
_>Вообще предпочитаю "лёгкие" решения. Не в смысле быстродействия (в этом смысле все указанные мною примеры хороши), а в смысле функциональности. А если брать "тяжёлые" решения, то можно глянуть например на такое http://www.codesynthesis.com/products/odb/, но мне как-то приятнее иметь дело с "sql запросами". )))
То есть вернулись к тому, с чего начали — склейки строк. Увы, сделав пару проектов, в которых активно клеятся SQL запрос больше нет желания заниматься.
Здравствуйте, Слава, Вы писали:
С>Только вот компилятором на sql-сервер никак не положишь закэшированные планы запросов. А время перевода из синтаксического дерева в текст запроса ничтожно со временем построения плана. Так что все эти усилия с действиями на этапе компиляции есть вещь в себе, по факту не нужная.
Вот только план в SQL делается один раз и живет долго, а по Expression Tree каждый раз надо бегать.
На нетривиальных запросах это несколько миллисекунд. При тыще запросов в секунду только формирование SQL из ET скушает пару ядер процессора.
Естественно 99% проектов до такой нагрузки не доживут, поэтому проблема мало кого касается, но понимать что она есть — важно.
Здравствуйте, gandjustas, Вы писали:
G>Вот только план в SQL делается один раз и живет долго, а по Expression Tree каждый раз надо бегать. G>На нетривиальных запросах это несколько миллисекунд. При тыще запросов в секунду только формирование SQL из ET скушает пару ядер процессора. G>Естественно 99% проектов до такой нагрузки не доживут, поэтому проблема мало кого касается, но понимать что она есть — важно.
Я специально задавал вопрос IT насчет явного кэширования сгенерированных запросов, этого пока нет, но сделать их не очень сложно, как я понимаю. Для неявного кэширования надо все равно обойти дерево и получить ключ для хэша.
И кстати — а почему это обход ET занимает столько времени? Ну даже пусть там будет 1000 узлов, это же ничтожно.
Здравствуйте, Sinclair, Вы писали:
Y>>Да нет, наши потребности EF перекрывает, плюс для, скажем так, администранивного уровня, в споре "тулза от MS" vs "какие-то ребята-энтузиасты запилили прикольную штуку" выигрывает понятно что. S>Вы одной рукой пишете, что EF — страшный тормоз
Здравствуйте, Слава, Вы писали:
С>И кстати — а почему это обход ET занимает столько времени? Ну даже пусть там будет 1000 узлов, это же ничтожно.
На самом деле две части:
1) построение ET, лямбда превращается в выражение, которое при каждом запуске выполняется.
2) при построении и обработке ET используется рефлексия, которая тоже небыстрая.
Здравствуйте, IB, Вы писали:
Y>>Да нет, наши потребности EF перекрывает, плюс для, скажем так, администранивного уровня, в споре "тулза от MS" vs "какие-то ребята-энтузиасты запилили прикольную штуку" выигрывает понятно что. IB>Ну если вам так уперлось, чтобы именно от MS
Нет, "именно от МS" никому не упёрлось, не надо фантазий.
Об этом уже говорено-переговорено, не вижу смысла повторять по десятому разу.
Здравствуйте, Yoriсk, Вы писали:
Y>Это где я такое пишу?
Я, наверное, вас неверно понял. И "какие только велосипеды не велосипедировали, а всё равно приходилось если не в коде клеить, то в хранимке и exec" прочитал так, что вас перформанс ORM-решений не устраивал. Если вас устраивает EF, то зачем хранимки, склейка строк, и exec?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
Y>>Это где я такое пишу? S>Я, наверное, вас неверно понял. И "какие только велосипеды не велосипедировали, а всё равно приходилось если не в коде клеить, то в хранимке и exec" прочитал так, что вас перформанс ORM-решений не устраивал. Если вас устраивает EF, то зачем хранимки, склейка строк, и exec?
Там фраза начинается со слов "До всех этих ОRM". Это я вспоминал "старые добрые времена". Сейчас я не представляю, кто и зачем в здравом уме будет таким заниматься.
Здравствуйте, gandjustas, Вы писали:
G>Теперь покажи как сделать "инстумент, задающий эту же самую склейку, но автоматически на этапе компиляции". G>Естественно все параметры зависят от ввода пользователя и невозможно их вычислить на этапе компиляции. G>Разделение на слои тоже является обязательным. А проекция в PL может видоизменить запрос, что появятся join_ы.
Давай разберёмся, какое из двух следующих утверждений, вызывает у тебя сомнения:
1. Что можно написать на базе склейки sql строк (типа считаем это неудобным низким уровнем) код полностью аналогичный твоему примеру "эффективного запроса на C#" и при этом он будет эффективнее варианта через linq. Кстати, это можно сделать по сути на любом языке.
2. Что можно написать код (это уже не на любом языке), который на стадии компиляции полностью проверяет всю типизацию (соответственно в таком коде никаких sql строк уже нет) и корректность синтаксиса. И при этом выдаваемый компилятором код полностью идентичен итоговому коду в утверждение 1? )
_>>Ну лично мне нравится например такое https://github.com/rbock/sqlpp11 решение. Потому как оно является полным отражением sql, только статически типизированным и т.п. G> G>Покажешь как в нем сделать: G>1) Джоины G>2) Группировки G>3) Проекции G>Так чтобы все это было типизированно. То есть чтобы тебе компилятор не позволил обратиться к полю X результата, если оно не указано в проекции.
G>Без этого называть "полным отражением sql" противоестественно.
Хм, ты похоже даже приведённый на первой страничке пример не прочитал. Там же ясно написано:
"Of course there are joins and subqueries, more functions, order_by, group_by etc." Ну а типизация и т.п. там вообще везде, т.к. заложена в основу библиотеки (там же внутри сплошные игры в C++ шаблоны).
_>>Вообще предпочитаю "лёгкие" решения. Не в смысле быстродействия (в этом смысле все указанные мною примеры хороши), а в смысле функциональности. А если брать "тяжёлые" решения, то можно глянуть например на такое http://www.codesynthesis.com/products/odb/, но мне как-то приятнее иметь дело с "sql запросами". ))) G>То есть вернулись к тому, с чего начали — склейки строк. Увы, сделав пару проектов, в которых активно клеятся SQL запрос больше нет желания заниматься.
Ммм, вот специально же поставил кавычки — неужели этого мало было для понимания? )) Здесь речь шла о том, что я предпочитаю написать что-то вроде "db(insert_into(foo).set(foo.id = 17, foo.name = "bar", foo.hasFun = true));" вместо того, чтобы написать что-то вроде "db.persist(foo);", как надо делать во втором указанном мною движке (жирной ORM с кучей всяких дополнительных возможностей). И отлично видно, что в обоих случаях никакого намёка на sql строки нет.
Здравствуйте, Yoriсk, Вы писали:
Y>Там фраза начинается со слов "До всех этих ОRM". Это я вспоминал "старые добрые времена". Сейчас я не представляю, кто и зачем в здравом уме будет таким заниматься.
Простите, я окончательно потерял нить ваших рассуждений.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, alex_public, Вы писали:
_>Давай разберёмся, какое из двух следующих утверждений, вызывает у тебя сомнения:
_>1. Что можно написать на базе склейки sql строк (типа считаем это неудобным низким уровнем) код полностью аналогичный твоему примеру "эффективного запроса на C#" и при этом он будет эффективнее варианта через linq. Кстати, это можно сделать по сути на любом языке.
Конечно не вызывает сомнений, ведь внутри linq строки клеятся и вполне можно руками такое выпилить.
_>2. Что можно написать код (это уже не на любом языке), который на стадии компиляции полностью проверяет всю типизацию (соответственно в таком коде никаких sql строк уже нет) и корректность синтаксиса. И при этом выдаваемый компилятором код полностью идентичен итоговому коду в утверждение 1? )
Это сомнений не взывает если язык — C# и linq. В остальном сомнения есть и очень большие.
Ты утверждал, что можно лучше, но не смог привести пример.
_>Хм, ты похоже даже приведённый на первой страничке пример не прочитал. Там же ясно написано: _>"Of course there are joins and subqueries, more functions, order_by, group_by etc." Ну а типизация и т.п. там вообще везде, т.к. заложена в основу библиотеки (там же внутри сплошные игры в C++ шаблоны).
Еще раз приводу твои же слова:
Потому как оно является полным отражением sql, только статически типизированным и т.п.
Тут ты промахнулся как Колумб с индией. Во-первых оно не настолько типизировано, насколько хотелось бы, а во вторых самые важные возможности SQL как раз и не реализованы.
То есть ты хотел показать что-то получше Linq, а показал то, что на два порядка хуже.
_>Ммм, вот специально же поставил кавычки — неужели этого мало было для понимания? )) Здесь речь шла о том, что я предпочитаю написать что-то вроде "db(insert_into(foo).set(foo.id = 17, foo.name = "bar", foo.hasFun = true));" вместо того, чтобы написать что-то вроде "db.persist(foo);", как надо делать во втором указанном мною движке (жирной ORM с кучей всяких дополнительных возможностей). И отлично видно, что в обоих случаях никакого намёка на sql строки нет.
Прости, но твои предпочтения малоинтересны. Тыже разговор начал с того, что можно отказаться от linq и что-тотам улучшить, не потерям в типизации. Я тебе привел пример на Linq, ты даже близко ничего похожего не привел ни на каком языке.
Здравствуйте, Слава, Вы писали:
С>Я специально задавал вопрос IT насчет явного кэширования сгенерированных запросов, этого пока нет, но сделать их не очень сложно, как я понимаю.
CompiledQuery было с самого начала.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, gandjustas, Вы писали:
_>>1. Что можно написать на базе склейки sql строк (типа считаем это неудобным низким уровнем) код полностью аналогичный твоему примеру "эффективного запроса на C#" и при этом он будет эффективнее варианта через linq. Кстати, это можно сделать по сути на любом языке. G>Конечно не вызывает сомнений, ведь внутри linq строки клеятся и вполне можно руками такое выпилить.
ОК.
_>>2. Что можно написать код (это уже не на любом языке), который на стадии компиляции полностью проверяет всю типизацию (соответственно в таком коде никаких sql строк уже нет) и корректность синтаксиса. И при этом выдаваемый компилятором код полностью идентичен итоговому коду в утверждение 1? ) G>Это сомнений не взывает если язык — C# и linq. В остальном сомнения есть и очень большие.
У тебя тут сразу же логическое противоречие. Абзацем выше ты признал, что с помощью склейки строк можно добиться кода, более эффективного, чем вариант с linq. А тут вот пишешь, что не вызывает сомнений, что можно написать такой же эффективный код на C# и linq. )))
G>Ты утверждал, что можно лучше, но не смог привести пример.
Мммм, а какой собственно пример то нужен? ) Я продемонстрировал сразу два движка (лёгкую библиотеку и жирный фреймворк), решающих данную проблему. На первых же страницах описаний этих движков показаны все нужные примеры. Что ещё нужно то? ) Или есть сомнения, что шаблонный код (в котором после прохода компилятора вообще ни одного вызова функции не остаётся) будет намного эффективнее обегания деревьев с виртуальными функциями (я уже молчу про тормозную рефлексию)? )))
G>Тут ты промахнулся как Колумб с индией. Во-первых оно не настолько типизировано, насколько хотелось бы, а во вторых самые важные возможности SQL как раз и не реализованы. G>То есть ты хотел показать что-то получше Linq, а показал то, что на два порядка хуже.
ОК, показывай в каком месте у нас тут недостаточная типизация (и что под этим вообще может подразумеваться, с учётом того, что у нас язык со статической типизацией?). И называй какие же конкретно "самые важные возможности SQL" не реализованы в данной библиотеке.
G>Прости, но твои предпочтения малоинтересны. Тыже разговор начал с того, что можно отказаться от linq и что-тотам улучшить, не потерям в типизации. Я тебе привел пример на Linq, ты даже близко ничего похожего не привел ни на каком языке.
Я тебе привёл даже 2 разных примера с разными подходами (лёгкая библиотечка и тяжёлый ORM фреймворк). И указал, что лично мне больше нравится первый вариант. Но если кому-то нравится второе, то и оно имеется. В любом случае оба варианта полностью статически типизированные и не имеют лишних накладных расходов при исполнения (типа тех, что имеются в linq).
Здравствуйте, alex_public, Вы писали:
_>Мммм, а какой собственно пример то нужен? ) Я продемонстрировал сразу два движка (лёгкую библиотеку и жирный фреймворк), решающих данную проблему. На первых же страницах описаний этих движков показаны все нужные примеры.
Ну вот я тоже не вижу "всех нужных примеров" на первых страницах описания.
Вижу const auto& row : db(select(foo.name, foo.hasFun).from(foo).where(foo.id > 17 and foo.name.like("%bar%"))).
_>Что ещё нужно то?
Нужен аналог вот этого кода на приведённой вами библиотеке:
var query = context.Employees;
if(!string.IsNullOrEmpty(lastName)) query = query.Where(e => e.LastName = lastName);
if(!string.IsNullOrEmpty(firstName)) query = query.Where(e => e.FirstName= firstName);
if(employmentDateFrom.HasValue) query = query.Where(e => e.EmploymentDate >= employmentDateFrom.Value);
if(employmentDateTo.HasValue) query = query.Where(e => e.EmploymentDate <= employmentDateTo.Value);
//далее в Presentation Layer (в другом классе и другой сборке)var list = await query.Take(pageSize).Select(e => new {/*projection*/}).ToListAsync();
_>Я тебе привёл даже 2 разных примера с разными подходами (лёгкая библиотечка и тяжёлый ORM фреймворк).
Примеров кода в ваших постах ровно 0. Без них обсуждать, собственно, нечего.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, _Case, Вы писали:
_C>>Хорошо, а если рассмотреть следующую ситуацию ... — то будет просто запрос на базу вида: EXEC [ProcessDataForMonth] а если эту же задачу реализовывать средствами Entity Framework то придется сначала вытащить все эти сотни тысяч записей на BackEnd сервер, отпроцессать их, и затем сохранить снова в базу — это же займет больше времени чем сделать это всё на месте — внутри DB сервера, не гоняя данные по сети.. S>Это называется "ложная альтернатива". То, что EF сосёт в таком сценарии, вовсе не означает, что кроме хранимок некуда податься. S>Хранимки можно применять тогда, когда у вас вообше вся логика живёт в базе. В противном случае вы будете постоянно нарываться на рассогласование логики в backend и в хранимках. И на невозможность минимального рефакторинга без прогона долгих регрессионных тестов. S>То, что обычные тяжеловесные ORM сосут, известно хорошо. Несосёт нормальный SQL. И тулзы по его построению вроде link2db. Потому что они не имеют проблем с версионированием вроде "ой, мы восстановили базу из бэкапа, и теперь у нас отчёты показывают какой-то бред". И потому что компилятор статически проверяет типизацию, заодно позволяя нам лёгким манием руки исправлять опечатки в названиях полей.
_C>>Ещё пример — сложные отчеты, по моему опыту через ORM такой отчет (хотя бы 7-8 джойнов) будет строиться неприлично большое количество времени.. S>Это у вас неправильный ORM.
точно точно .... неправильный ORM.
_C>>Эта тема конечно о производительности EF, но процедуры я люблю именно за то что понятно что вызывается — запустил SQL профайлер и ясно какая страница что делает, а с потоком SQL-а от ORM так просто не разберешься..
Здравствуйте, gandjustas, Вы писали:
G>Делаем из него эффективный запрос на C#: G>
G>var query = context.Employees;
G>if(!string.IsNullOrEmpty(lastName)) query = query.Where(e => e.LastName = lastName);
G>if(!string.IsNullOrEmpty(firstName)) query = query.Where(e => e.FirstName = firstName);
G>if(employmentDateFrom.HasValue) query = query.Where(e => e.EmploymentDate >= employmentDateFrom.Value);
G>if(employmentDateTo.HasValue) query = query.Where(e => e.EmploymentDate <= employmentDateTo.Value);
G>//далее в Presentation Layer (в другом классе и другой сборке)
G>var list = await query.Take(pageSize).Select(e => new {/*projection*/}).ToListAsync();
G>
G>Теперь покажи как сделать "инстумент, задающий эту же самую склейку, но автоматически на этапе компиляции". G>Естественно все параметры зависят от ввода пользователя и невозможно их вычислить на этапе компиляции.
Один из возможных вариантов:
auto q1 = context.Employees;
auto q2 = conditional(!IsNullOrEmpty(lastName), q1.Where(e.LastName = lastName));
auto q3 = conditional(!IsNullOrEmpty(firstName), q2.Where(e.FirstName= firstName));
auto q4 = conditional(HasValue(employmentDateFrom), q3.Where(e.EmploymentDate >= employmentDateFrom.Value));
auto q5 = conditional(HasValue(employmentDateTo)), q4.Where(e.EmploymentDate <= employmentDateTo.Value));
//далее в Presentation Layer (в другом месте)auto list = await q5.Take(pageSize).Select(/*projection*/).ToListAsync();
При попытке выполнить этот запрос, будет произведено 4 runtime проверки, в результате чего будет выбрана одна из 16 сгенерированных в compile-time версий запроса (причём которые могут кардинально отличаться друг от друга).
Если не нравится экспоненциальное количество запросов в исполняемом файле, то можно добавить динамики. Да, при этом запрос будет частично строится в runtime (с возможным кэшированием), но при этом не будет дорогой runtime reflection — в ней тут нет принципиальной необходимости, достаточно compile-time reflection.
G>Разделение на слои тоже является обязательным.
Не проблема — достаточно передать q5 с его типом в другой слой.
Если же хочется больше динамики (например q5 генерируется в отдельной динамической библиотеке и нужно иметь возможность изменять запрос без переборки всех зависимых компонентов) — то можно частично стереть информацию о типе (type erasure), но тогда как минимум появятся косвенные вызовы, а максимум — построение части запроса в runtime (но опять же, без runtime reflection).
G>А проекция в PL может видоизменить запрос, что появятся join_ы.
Да, это не помеха — в предлагаемом варианте запрос строится в самый последний момент, когда известны все runtime условия, а не склеивается из отдельных кусочков после каждой проверки.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
_>>>1. Что можно написать на базе склейки sql строк (типа считаем это неудобным низким уровнем) код полностью аналогичный твоему примеру "эффективного запроса на C#" и при этом он будет эффективнее варианта через linq. Кстати, это можно сделать по сути на любом языке. G>>Конечно не вызывает сомнений, ведь внутри linq строки клеятся и вполне можно руками такое выпилить.
_>ОК.
_>>>2. Что можно написать код (это уже не на любом языке), который на стадии компиляции полностью проверяет всю типизацию (соответственно в таком коде никаких sql строк уже нет) и корректность синтаксиса. И при этом выдаваемый компилятором код полностью идентичен итоговому коду в утверждение 1? ) G>>Это сомнений не взывает если язык — C# и linq. В остальном сомнения есть и очень большие.
_>У тебя тут сразу же логическое противоречие. Абзацем выше ты признал, что с помощью склейки строк можно добиться кода, более эффективного, чем вариант с linq. А тут вот пишешь, что не вызывает сомнений, что можно написать такой же эффективный код на C# и linq. )))
У меня вызывает сомнение типизация, а не эффективность кода. Эффективность кода мне не нужна, она нужна тебе, причем настолько, что ты готов клеить строки. Но практика показывает что склейка строк — рассадник багов и значительно усложняет поддержку.
G>>Ты утверждал, что можно лучше, но не смог привести пример.
_>Мммм, а какой собственно пример то нужен? ) Я продемонстрировал сразу два движка (лёгкую библиотеку и жирный фреймворк), решающих данную проблему. На первых же страницах описаний этих движков показаны все нужные примеры. Что ещё нужно то? ) Или есть сомнения, что шаблонный код (в котором после прохода компилятора вообще ни одного вызова функции не остаётся) будет намного эффективнее обегания деревьев с виртуальными функциями (я уже молчу про тормозную рефлексию)? )))
Ты не смог привести пример, который имеет те же возможности (в том числе типизацию), но быстрее linq. Зачем нужен "шаблонный код (в котором после прохода компилятора вообще ни одного вызова функции не остаётся)" если он не умеет банальный джоин? Да и какой смысл за этими микросекундами гоняться если запрос в базе выполняется на 2-3 порядка дольше? Банальное кеширование даст гораздо более заметный прирост к скорости.
G>>Тут ты промахнулся как Колумб с индией. Во-первых оно не настолько типизировано, насколько хотелось бы, а во вторых самые важные возможности SQL как раз и не реализованы. G>>То есть ты хотел показать что-то получше Linq, а показал то, что на два порядка хуже.
_>ОК, показывай в каком месте у нас тут недостаточная типизация (и что под этим вообще может подразумеваться, с учётом того, что у нас язык со статической типизацией?). И называй какие же конкретно "самые важные возможности SQL" не реализованы в данной библиотеке.
Еще раз. Нужны в типизированном виде:
1) Проекции
2) Джоины
3) Группировки.
То есть чтобы я не мог обратиться к полю А, если я его не указал в select.
Я это уже писал, ты упорно игнорируешь.
G>>Прости, но твои предпочтения малоинтересны. Тыже разговор начал с того, что можно отказаться от linq и что-тотам улучшить, не потерям в типизации. Я тебе привел пример на Linq, ты даже близко ничего похожего не привел ни на каком языке.
_>Я тебе привёл даже 2 разных примера с разными подходами (лёгкая библиотечка и тяжёлый ORM фреймворк). И указал, что лично мне больше нравится первый вариант. Но если кому-то нравится второе, то и оно имеется. В любом случае оба варианта полностью статически типизированные и не имеют лишних накладных расходов при исполнения (типа тех, что имеются в linq).
Они даже близко не валялись с linq, ни в одном из них нет типизированной проекции. Просто напиши 5 строк кода с любой из библиотек, которые ты приводил, чтобы получить пример, эквивалентный тому, который я приводил. Твои рассуждения о скорости крайне неинтересны, тем более они крайне далеки от жизни.
Здравствуйте, Sinclair, Вы писали:
S>Ну вот я тоже не вижу "всех нужных примеров" на первых страницах описания. S>Вижу const auto& row : db(select(foo.name, foo.hasFun).from(foo).where(foo.id > 17 and foo.name.like("%bar%"))).
А требуется ещё что-то? ) Уже же из этого видно, что данная библиотека является прямым отображением sql, только типизированным. Какие могут быть ещё вопросы в таком случае? ) Или кто-то уже стал подзабывать sql? )))
_>>Что ещё нужно то? S>Нужен аналог вот этого кода на приведённой вами библиотеке: S>
S>var query = context.Employees;
S>if(!string.IsNullOrEmpty(lastName)) query = query.Where(e => e.LastName = lastName);
S>if(!string.IsNullOrEmpty(firstName)) query = query.Where(e => e.FirstName= firstName);
S>if(employmentDateFrom.HasValue) query = query.Where(e => e.EmploymentDate >= employmentDateFrom.Value);
S>if(employmentDateTo.HasValue) query = query.Where(e => e.EmploymentDate <= employmentDateTo.Value);
S>//далее в Presentation Layer (в другом классе и другой сборке)
S>var list = await query.Take(pageSize).Select(e => new {/*projection*/}).ToListAsync();
S>
По поводу этого примера вообще непонятно откуда такой интерес, т.к. тут собственно интересная часть (так называемая оптимизация) происходит не в linq, а просто в C#, причём с использованием банального оператора if — это где угодно можно повторить. Если говорить конкретно о C++ и указанной мною библиотеке, то буквально такими же if'ми всё и записывается. При этом во время компиляции под каждую ветку ветвления создастся своя версия запроса, а в рантайме останется только тот самый if, выбирающий нужный вариант запроса. Мне казалось, что это всё должно быть очевидно, а самое сложное как раз в реализации статической типизации. Но если не очевидно, то вот Евгений продемонстрировал полный аналог в сообщение выше.
_>>Я тебе привёл даже 2 разных примера с разными подходами (лёгкая библиотечка и тяжёлый ORM фреймворк). S>Примеров кода в ваших постах ровно 0. Без них обсуждать, собственно, нечего.
Примеры имеются прямо по ссылкам, которые я показал. Зачем копировать их ещё и сюда? )
EP>При попытке выполнить этот запрос, будет произведено 4 runtime проверки, в результате чего будет выбрана одна из 16 сгенерированных в compile-time версий запроса (причём которые могут кардинально отличаться друг от друга).
А что у нас в /*projection*/?
В C# там будет код
x => new { x.A, x.B, x.Y.C }
Последнее выражение вызовет добавление join_а в запрос
А в C++ что туда написать для подобного эффекта?
И как это все можно по разным функциям и сборкам (dll) растащить? Ведь суть linq в том, что собирать запрос по кускам можно в разных местах, а не надо выписывать все условия в одном месте и гонять туда-сюда все параметры.
EP>Если не нравится экспоненциальное количество запросов в исполняемом файле, то можно добавить динамики. Да, при этом запрос будет частично строится в runtime (с возможным кэшированием), но при этом не будет дорогой runtime reflection — в ней тут нет принципиальной необходимости, достаточно compile-time reflection.
В C# на compiled query можно добиться того же эффекта.
G>>Разделение на слои тоже является обязательным. EP>Не проблема — достаточно передать q5 с его типом в другой слой.
EP>Если же хочется больше динамики (например q5 генерируется в отдельной динамической библиотеке и нужно иметь возможность изменять запрос без переборки всех зависимых компонентов) — то можно частично стереть информацию о типе (type erasure), но тогда как минимум появятся косвенные вызовы, а максимум — построение части запроса в runtime (но опять же, без runtime reflection).
Ну приведи работающий пример.
G>>А проекция в PL может видоизменить запрос, что появятся join_ы. EP>Да, это не помеха — в предлагаемом варианте запрос строится в самый последний момент, когда известны все runtime условия, а не склеивается из отдельных кусочков после каждой проверки.
Осталось на работающий пример посмотреть.
Здравствуйте, Sinclair, Вы писали:
S>То, что обычные тяжеловесные ORM сосут, известно хорошо. Несосёт нормальный SQL. И тулзы по его построению вроде link2db. Потому что они не имеют проблем с версионированием вроде "ой, мы восстановили базу из бэкапа, и теперь у нас отчёты показывают какой-то бред".
Думаю это проблема конкретных ORM, которая IMO разрешима в общем случае.
Например Schema Evolution в ODB:
* part 1 (44:39), part 2
* http://www.codesynthesis.com/products/odb/doc/manual.xhtml#13
S>Несосёт нормальный SQL. И тулзы по его построению вроде link2db. Потому что они не имеют проблем с версионированием вроде "ой, мы восстановили базу из бэкапа, и теперь у нас отчёты показывают какой-то бред".
Так с "нормальным SQL" также возможны проблемы с версионированием