Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.12.08 18:58
Оценка: 45 (10) +2
Писал тут редакционную статью (все заняты, свалили ответственность на меня) для нашего журнала Технология Клиент-Сервер. В результате получились мысли о LINQ которые мне давно приходили в голову, но времени изложить в форуме не было. Вот что получилось:

Начитавшись в форумах тем, посвященных LINQ и его разновидностям – LINQ to SQL и LINQ to EF (Entity Framework, далее просто EF), я захотел порассуждать на эту тему. Отчасти это желание возникло от того, что я заметил некую терминологическую путаницу, которая сильно влияет на выводы. А отчасти желание подогревается какой-то дикой непоследовательностью в подходе Microsoft.
Итак, разберем все по порядку.
Терминология. На RSDN разгорелся нешуточный флэйм по поводу того, что с точки зрения поклонников Hibernate (и других похожих продуктов, основанных на идеях EJB, которые в свою очередь основаны на идеях CORBA), Microsoft сделала неправильный O/R Mapper (по-русски это будет звучать вроде объектно-реляционные отображальники ). С точки зрения поклонников Hibernate, Microsoft сделал не полноценный O/R Mapper, так как он не предоставляет мощной и законченной подсистемы Persistence Ignorance (PI), а защитники подхода Microsoft отвечают своим оппонентам, что Microsoft вовсе не пытался создать O/R Mapper.

Небольшая справка. PI – это давняя идея, о которой я впервые услышал при знакомстве с CORBA-ой. Ее суть заключается в том, что программист должен работать с «чистой» объектной моделью, а слой персистентности (это изобретение человеческой мысли даже назвать, то по русски трудно) «прозрачно» для программиста хранит данные в БД. При этом программист думает об объекте как о долгоживущей сущности. Объект (в мыслях программиста) живет дольше чем какое либо приложение им манипулирующее, будь то Web-страница или сервер приложений. В общем, программист манипулирует объектом (или их коллекциями), а подсистема персистентности сама когда надо сохраняет его состояние в персистентом хранилище (которым обычно выступает СУБД, но с точки зрения чисто идеологии может выступать все что угодно). Иногда на эту идею смотрят как на «объектизацию» БД, в том смысле, что программист думает, что в БД хранятся объекты (в полном понимании ООП).

Учитывая вышесказанное, можно смело сказать, что под поклонниками Hibernate я имею в виду поклонников PI.
Кто же здесь прав, а кто неправ? Неправы оба лагеря. И неправы они в восприятии понятия O/R Mapper. O/R Mapper не подразумевает реализации каких-то там идей «объектизации» БД и тем более PI. Задача O/R Mapper – просто отобразить данные, получаемые из РСУБД, в объекты, которыми удобно манипулировать в программе. Эту функцию в реализациях LINQ (особенно EF) реализована довольно неплохо. Но и LINQ to SQL, и EF вообще не предназначены для реализации идей персистентности, и в частности, PI. Вместо этого они (точнее, их создатели) пропагандируют старую как мир идею воспринимать модель данных, хранимых в БД и отображаемых на объекты, как ER-модель (Entity Relation). В этой модели данные рассматриваются как набор сущностей, связанных между собой отношениями. Она отлично ложится на РСБУД с их «реляционно-алгеброическим бэкграундом».
Учитывая вышесказанное, довольно глупо ожидать от реализаций LINQ качественной реализации абстракций, для поддержки которых они не предназначены. LINQ просто не должен быть предназначен для обработки объектов путем перебора их в циклах и изменения их свойств. Вместо этого он должен манипулировать наборами сущностей с помощью запросов. Только сущности в LINQ представлены не кортежами, как в РСУБД, а объектами. Вот почему в LINQ to SQL даже нет сложной системы поддержки наследования. Ведь по уму одна сущность должна отображаться на один класс. Это самое прямое отображение, а значит, самое очевидное.
Однако LINQ должен быть удобным. А применение соединения таблиц (join) трудно назвать удобной штукой. Куда логичнее написать нечто order.Details.Sum(d => d.UnitPrice * d.Quantity), нежели возиться с соединениями «таблиц», указывая ключи и прочую чепуху. Тем более что совершенно элементарно реализовать отображение красивой объектно-функциональной нотации в те же самые join-ы.
Вот почему в LINQ-ах есть возможности так похожие на те, что есть в Hibernate. Но у них другая природа и другие задачи. Да, и не спорьте со мной насчет того, что Hibernate тоже может делать запросы. Я знаю. Но у него другие отправные точки в дизайне. Он сначала PI, а уж затем может выполнять запросы на внутреннем языке. А LINQ – это интегрированный в язык язык запросов и ничего большего.
Все вроде бы встало на свои места? Как бы ни так. К сожалению, нормальному восприятию LINQ to SQL и EF как O/R Mapper-а, основанного на идеях ER, мешает тот способ, которым LINQ предлагает вносить изменения в БД. А способ это самый что ни на есть неподходящий для LINQ-а, пропагандирующего подход «ER-моделирования». Чтобы изменить данные в обеих реализациях LINQ нужно получить объект, изменить его свойства, поместить этот объект в специальный контекст (если он еще не находится в нем) и, в конце концов, выполнить у этого контекста процедуру записи. Это тот же самый подход, что используется в Hibernate и ему подобных PI-средах. И нужен этот подход именно потому, и только для того, чтобы скрыть от разработчика реальную – реляционную – суть обрабатываемых данных, и позволить ему возиться с объектами, как будто они являются полноценными (в смысле ООП) объектами, а не отображением ER-сущностей.
На мой взгляд – это жутчайшая непоследовательность и грубейшая ошибка дизайна.
Изменение данных в системах, пропагандирующих ER-подход, должно вестись теми же реляционными средствами, т.е. с помощью операторов insert, update и delete, как в оригинальном SQL, под который пытается мимикрировать LINQ. Тогда все бы встало на свои места. Сущности не нужно было бы прицеплять к контексту. Транзакции можно было бы объявлять явно. А возможности манипуляций данными значительно расширились бы, так как в выражениях insert, update и delete можно было бы применять всю мощь запросов!
В общем, на мой взгляд, Microsoft со своим EF пошла не в ту степь. Она (видимо, поддавшись крикам Hibernate-щиков) пошла по пути превращения EF в клон «классического» O/R Mapper-а, а реально – персистентной подсистемы. На мой взгляд, идея персистентности и манипуляции данными как объектами в корне порочна. Мне казалось, что Microsoft нащупал правильный путь, но сейчас я наблюдаю, как Microsoft твердой поступью идет в обратном направлении.
Единственное, что меня радует – это то, что Microsoft-таки показала, как интегрировать ER-подход с современными объектно-ориентированными языками с функциональным уклоном, и кто-то из посторонних сможет реализовать, казалось бы, такие напрашивающиеся для LINQ insert, update и delete. Жаль, что, в отличие от Nemerle, такие языки, как C# и VB, не позволяют расширить свой синтаксис чтобы бесшовно ввести эти операторы в язык. Но хотя бы в виде процедур, принимающих условия в виде деревьев выражений, их можно добавить в любой язык. Продаю идею .
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Некоторые мысли о LINQ
От: mogadanez Чехия  
Дата: 30.12.08 19:42
Оценка:
Здравствуйте, VladD2, Вы писали:
<skip>
VD>Учитывая вышесказанное, можно смело сказать, что под поклонниками Hibernate я имею в виду поклонников PI.
<skip>
VD> Да, и не спорьте со мной насчет того, что Hibernate тоже может делать запросы. Я знаю. Но у него другие отправные точки в дизайне. Он сначала PI, а уж затем может выполнять запросы на внутреннем языке.
<skip>

использую nHibernate, хотя не являюсь его ярым поклонником — появится чтото более дойтойное — можно переключится.
для меня PI != nHibernate. и nHibernate !=PI.

PI — это принцип построения DomainModel слоя, а не Persistent слоя.
если смотреть на приложение в целом в этом свете — то тут есть три больших куска:

Application
Domain
Infrastructure

PI относится к архитектуре Domain куска, это значит что мне по...й, хибернейт у меня или нет. все queries у меня тут в терминах доменной модели а не в терминах хибернейта или линка

nHibernate это в Infrastructure, причем тут может быть и LINQ и в Domain вообще ничего не изменится.
Re[2]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.12.08 20:45
Оценка:
Здравствуйте, mogadanez, Вы писали:


M>использую nHibernate, хотя не являюсь его ярым поклонником — появится чтото более дойтойное — можно переключится.

M>для меня PI != nHibernate. и nHibernate !=PI.

M>PI — это принцип построения DomainModel слоя, а не Persistent слоя.

M>если смотреть на приложение в целом в этом свете — то тут есть три больших куска:

Сама терминология "DomainModel" как раз из тех самых про-гибернэйтовских (а точнее сказать про-корбовских или про-еджебишных) подходов. По этому == или != — это уже не важно. Важно, что это никакого отношения к ER-подходу, на котором вроде как (судя по докам и статья от МС) основан LINQ, не имеет.

Ну, и мыслей ты моих не понял. И видимо не сможешь понять, так как рассуждаешь другими понятиями. В прочем, может быть я просто плохо изложил свои мысли.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Некоторые мысли о LINQ
От: mogadanez Чехия  
Дата: 30.12.08 22:51
Оценка: 6 (1) +1
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, mogadanez, Вы писали:


VD>Сама терминология "DomainModel" как раз из тех самых про-гибернэйтовских (а точнее сказать про-корбовских или про-еджебишных) подходов. По этому == или != — это уже не важно. Важно, что это никакого отношения к ER-подходу, на котором вроде как (судя по докам и статья от МС) основан LINQ, не имеет.


DDD откуда собственно взят термин DomainModel прекрасно живет с LINQ, и совершенно незавязан на про-гибернэйтовские фреймворки, более того — вполне могут сосуществовать и hibernate и LINQ в одном приложении.

мысль твою я понял, просто не очень согласен =)
я бросил читать споры Hibernate vs LINQ ибо жалко времени, но последннее что помню, было главное противоречие:
* LINQ: БД это очень важно, проектируем начиная с нее, посему sqlLINQ у нас главный ибо хорошо( по крайней мере лучше хибернейта отражает структуру БД )
* Hibernate: БД в лес. можно написать все приложение вообще без БД а потом прикрутить Хибернейт или чтото другое, выбор зависит от разных факторов( скорость/стоимость ), но этот выбор не отражается на архитектуре системы.
Re[4]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.12.08 06:47
Оценка: +1
Здравствуйте, mogadanez, Вы писали:

M>DDD откуда собственно взят термин DomainModel прекрасно живет с LINQ, и совершенно незавязан на про-гибернэйтовские фреймворки, более того — вполне могут сосуществовать и hibernate и LINQ в одном приложении.


Видимо ты путаешь аббревиатуры DDD в смысле Domain-Driven Design и DDD в смысле Data Driven Development.

Еще раз повторяю, что LINQ основывался на идее ER, а она имеет очень отдаленное отношение к Domain-Driven Design.

M>мысль твою я понял, просто не очень согласен =)

M>я бросил читать споры Hibernate vs LINQ ибо жалко времени, но последннее что помню, было главное противоречие:
M>* LINQ: БД это очень важно, проектируем начиная с нее, посему sqlLINQ у нас главный ибо хорошо( по крайней мере лучше хибернейта отражает структуру БД )

Это утрированный взгляд. Но здравое зерно в нем есть. Реально LINQ использует в качестве модели ER-модель. Ее сто лет уже используют в проектировании баз данных. Она действительно близка к БД, но все же это не одно и то же.

M>* Hibernate: БД в лес. можно написать все приложение вообще без БД а потом прикрутить Хибернейт или чтото другое, выбор зависит от разных факторов( скорость/стоимость ), но этот выбор не отражается на архитектуре системы.


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

Ну, так теперь подумай не является ли противоречием тот факт, что в LINQ нет операций update, delete и insert, но ест совершенно не подходящий для этой модели DataContext?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 02.01.09 17:50
Оценка: 2 (1) +1
Здравствуйте, VladD2, Вы писали:

VD>Терминология. На RSDN разгорелся нешуточный флэйм по поводу того, что с точки зрения поклонников Hibernate (и других похожих продуктов, основанных на идеях EJB, которые в свою очередь основаны на идеях CORBA),


Hibernate основан на идея EJB? На каких, если не секрет?
Имхо, все как раз наоборот — hibernate возник как ответ на неоправданную сложность и негибкость CMP Entity-ей.

VD>Microsoft сделала неправильный O/R Mapper (по-русски это будет звучать вроде объектно-реляционные отображальники ). С точки зрения поклонников Hibernate, Microsoft сделал не полноценный O/R Mapper, так как он не предоставляет мощной и законченной подсистемы Persistence Ignorance (PI),


Невозможно в принцыпе создать подсистему PI. PI — это подход к дизайну Domain Model. Поэтому O/R Mapper может только поддерживать или нет этот подход.

VD>а защитники подхода Microsoft отвечают своим оппонентам, что Microsoft вовсе не пытался создать O/R Mapper.

VD>

VD>Небольшая справка. PI – это давняя идея, о которой я впервые услышал при знакомстве с CORBA-ой. Ее суть заключается в том, что программист должен работать с «чистой» объектной моделью, а слой персистентности (это изобретение человеческой мысли даже назвать, то по русски трудно) «прозрачно» для программиста хранит данные в БД. При этом программист думает об объекте как о долгоживущей сущности. Объект (в мыслях программиста) живет дольше чем какое либо приложение им манипулирующее, будь то Web-страница или сервер приложений. В общем, программист манипулирует объектом (или их коллекциями), а подсистема персистентности сама когда надо сохраняет его состояние в персистентом хранилище (которым обычно выступает СУБД, но с точки зрения чисто идеологии может выступать все что угодно). Иногда на эту идею смотрят как на «объектизацию» БД, в том смысле, что программист думает, что в БД хранятся объекты (в полном понимании ООП).


Мне кажется у вас некоторая путаница в терминах.
PI относится исключительно к дизайну Domain Model. Суть его заключается в том, что класс сущности никак не должен быть связан с подсистемой хранения. Это означает, что класс сущности — это обычный класс того языка программирования, на котором вы пишите, не должно быть завязки ни на какой базовый класс, ни на наличие атибутов, ни на реализацию интерфейса.
По поводу CORBA тоже не все понятно. Как (с учетом вышеприведенного определения) связаны PI и CORBA? Автор случайно не путает PI и Location Transparency?

VD>Учитывая вышесказанное, можно смело сказать, что под поклонниками Hibernate я имею в виду поклонников PI.

VD>Кто же здесь прав, а кто неправ? Неправы оба лагеря. И неправы они в восприятии понятия O/R Mapper. O/R Mapper не подразумевает реализации каких-то там идей «объектизации» БД и тем более PI. Задача O/R Mapper – просто отобразить данные, получаемые из РСУБД, в объекты, которыми удобно манипулировать в программе.

В том-то и суть. Если доменная модель следует принцыпу PI, с ней становится очень легко работать, в отличие от объектов, привязанных к "хранилищу".

VD>Эту функцию в реализациях LINQ (особенно EF) реализована довольно неплохо. Но и LINQ to SQL, и EF вообще не предназначены для реализации идей персистентности, и в частности, PI. Вместо этого они (точнее, их создатели) пропагандируют старую как мир идею воспринимать модель данных, хранимых в БД и отображаемых на объекты, как ER-модель (Entity Relation).


Это не совсем так. Создатели EF понимают важность следования PI и планируют в следующих версиях поддерживать его в большей степени. Подробности можно прочитать в блоге ADO.NET Team-а.

VD>В этой модели данные рассматриваются как набор сущностей, связанных между собой отношениями. Она отлично ложится на РСБУД с их «реляционно-алгеброическим бэкграундом».

VD>Учитывая вышесказанное, довольно глупо ожидать от реализаций LINQ качественной реализации абстракций, для поддержки которых они не предназначены. LINQ просто не должен быть предназначен для обработки объектов путем перебора их в циклах и изменения их свойств. Вместо этого он должен манипулировать наборами сущностей с помощью запросов. Только сущности в LINQ представлены не кортежами, как в РСУБД, а объектами. Вот почему в LINQ to SQL даже нет сложной системы поддержки наследования. Ведь по уму одна сущность должна отображаться на один класс. Это самое прямое отображение, а значит, самое очевидное.

Мне кажется, при обсуждении технологий нельзя утверждать что что-то должно быть сделано именно так, без упоминания зачем это должно быть сделано именно так, без обсуждения преимуществ предложенного подхода. Если вы со мной согласны, не могли бы вы описать, в чем преимущество такого подхода?

VD>Однако LINQ должен быть удобным. А применение соединения таблиц (join) трудно назвать удобной штукой. Куда логичнее написать нечто order.Details.Sum(d => d.UnitPrice * d.Quantity), нежели возиться с соединениями «таблиц», указывая ключи и прочую чепуху. Тем более что совершенно элементарно реализовать отображение красивой объектно-функциональной нотации в те же самые join-ы.

VD>Вот почему в LINQ-ах есть возможности так похожие на те, что есть в Hibernate. Но у них другая природа и другие задачи. Да, и не спорьте со мной насчет того, что Hibernate тоже может делать запросы. Я знаю. Но у него другие отправные точки в дизайне. Он сначала PI, а уж затем может выполнять запросы на внутреннем языке. А LINQ – это интегрированный в язык язык запросов и ничего большего.
VD>Все вроде бы встало на свои места? Как бы ни так. К сожалению, нормальному восприятию LINQ to SQL и EF как O/R Mapper-а, основанного на идеях ER, мешает тот способ, которым LINQ предлагает вносить изменения в БД. А способ это самый что ни на есть неподходящий для LINQ-а, пропагандирующего подход «ER-моделирования». Чтобы изменить данные в обеих реализациях LINQ нужно получить объект, изменить его свойства, поместить этот объект в специальный контекст (если он еще не находится в нем) и, в конце концов, выполнить у этого контекста процедуру записи. Это тот же самый подход, что используется в Hibernate и ему подобных PI-средах. И нужен этот подход именно потому, и только для того, чтобы скрыть от разработчика реальную – реляционную – суть обрабатываемых данных, и позволить ему возиться с объектами, как будто они являются полноценными (в смысле ООП) объектами, а не отображением ER-сущностей.
VD>На мой взгляд – это жутчайшая непоследовательность и грубейшая ошибка дизайна.
VD>Изменение данных в системах, пропагандирующих ER-подход, должно вестись теми же реляционными средствами, т.е. с помощью операторов insert, update и delete, как в оригинальном SQL, под который пытается мимикрировать LINQ. Тогда все бы встало на свои места.

Увы не стало бы. Приведенные вами операторы не являются реляционными. За подробностями, отсылаю вас к книжке Дейта.

VD>Сущности не нужно было бы прицеплять к контексту. Транзакции можно было бы объявлять явно.


Их и так можно объявлять явно. Что может быть более явным чем TransactionScope?

VD>А возможности манипуляций данными значительно расширились бы, так как в выражениях insert, update и delete можно было бы применять всю мощь запросов!


Возможность писать insert/update/deletе прямо в языке штука конечно интересная, но стоит ли ее рассматривать как замену (а не как дополнение) существующим способам работы с данными — вот в чем вопрос.

VD>В общем, на мой взгляд, Microsoft со своим EF пошла не в ту степь. Она (видимо, поддавшись крикам Hibernate-щиков) пошла по пути превращения EF в клон «классического» O/R Mapper-а, а реально – персистентной подсистемы. На мой взгляд, идея персистентности и манипуляции данными как объектами в корне порочна.


Почему вы так считаете?

VD>Мне казалось, что Microsoft нащупал правильный путь, но сейчас я наблюдаю, как Microsoft твердой поступью идет в обратном направлении.

VD>Единственное, что меня радует – это то, что Microsoft-таки показала, как интегрировать ER-подход с современными объектно-ориентированными языками с функциональным уклоном, и кто-то из посторонних сможет реализовать, казалось бы, такие напрашивающиеся для LINQ insert, update и delete. Жаль, что, в отличие от Nemerle, такие языки, как C# и VB, не позволяют расширить свой синтаксис чтобы бесшовно ввести эти операторы в язык. Но хотя бы в виде процедур, принимающих условия в виде деревьев выражений, их можно добавить в любой язык. Продаю идею .

Viva la Nemerle!
Re[2]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.01.09 16:29
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Hibernate основан на идея EJB? На каких, если не секрет?


На идее персистентности объектов.

T>Имхо, все как раз наоборот — hibernate возник как ответ на неоправданную сложность и негибкость CMP Entity-ей.


Именно так, но улучшал он как раз исходную идею EJB. В прочем идея эта родилась за долго до EJB. Просто уж больно распространен стал EJB. Так что в него тыкать пальцем удобнее.

VD>>Microsoft сделала неправильный O/R Mapper (по-русски это будет звучать вроде объектно-реляционные отображальники ). С точки зрения поклонников Hibernate, Microsoft сделал не полноценный O/R Mapper, так как он не предоставляет мощной и законченной подсистемы Persistence Ignorance (PI),


T>Невозможно в принцыпе создать подсистему PI. PI — это подход к дизайну Domain Model. Поэтому O/R Mapper может только поддерживать или нет этот подход.


Я не улавливаю разницы между этими двумя высказываниями. Так что называй как хочешь, только в печь не ставь.

VD>>а защитники подхода Microsoft отвечают своим оппонентам, что Microsoft вовсе не пытался создать O/R Mapper.

VD>>

VD>>Небольшая справка. PI – это давняя идея, о которой я впервые услышал при знакомстве с CORBA-ой. Ее суть заключается в том, что программист должен работать с «чистой» объектной моделью, а слой персистентности (это изобретение человеческой мысли даже назвать, то по русски трудно) «прозрачно» для программиста хранит данные в БД. При этом программист думает об объекте как о долгоживущей сущности. Объект (в мыслях программиста) живет дольше чем какое либо приложение им манипулирующее, будь то Web-страница или сервер приложений. В общем, программист манипулирует объектом (или их коллекциями), а подсистема персистентности сама когда надо сохраняет его состояние в персистентом хранилище (которым обычно выступает СУБД, но с точки зрения чисто идеологии может выступать все что угодно). Иногда на эту идею смотрят как на «объектизацию» БД, в том смысле, что программист думает, что в БД хранятся объекты (в полном понимании ООП).


T>Мне кажется у вас некоторая путаница в терминах.

T>PI относится исключительно к дизайну Domain Model. Суть его заключается в том, что класс сущности никак не должен быть связан с подсистемой хранения.

Я скорее имел в виду под PI саму идеологию "Объектизации". Т.е. когда программисты пытаются скрыть детали реализации хранилища данных и доступ к этим данным за объектной моделью.

T>Это означает, что класс сущности — это обычный класс того языка программирования, на котором вы пишите, не должно быть завязки ни на какой базовый класс, ни на наличие атибутов, ни на реализацию интерфейса.


Детали маппинга не существенны в данном случае. Основная разница именно в том от чего пляшут люди. От ER-модли или от объектной модели.

T>По поводу CORBA тоже не все понятно. Как (с учетом вышеприведенного определения) связаны PI и CORBA? Автор случайно не путает PI и Location Transparency?


Наверно я не очень правильно использовал термин PI. Но я объяснил, что я под ним понимаю, так что с пониманием (при желании) проблем возникнуть не должно.

Попробуй прочесть текст еще раз подразумевая под PI — "идеологию отталкивающуюся от объектной модели и позволяющую манипулировать объектными графами в императивном стиле".

VD>>Учитывая вышесказанное, можно смело сказать, что под поклонниками Hibernate я имею в виду поклонников PI.

VD>>Кто же здесь прав, а кто неправ? Неправы оба лагеря. И неправы они в восприятии понятия O/R Mapper. O/R Mapper не подразумевает реализации каких-то там идей «объектизации» БД и тем более PI. Задача O/R Mapper – просто отобразить данные, получаемые из РСУБД, в объекты, которыми удобно манипулировать в программе.

T>В том-то и суть. Если доменная модель следует принцыпу PI, с ней становится очень легко работать, в отличие от объектов, привязанных к "хранилищу".


На самом деле это не так. Работать легко с тем где меньше заморочек и удобнее средства, а не там где меньше связей с СУБД или еще чего-то.

VD>>Эту функцию в реализациях LINQ (особенно EF) реализована довольно неплохо. Но и LINQ to SQL, и EF вообще не предназначены для реализации идей персистентности, и в частности, PI. Вместо этого они (точнее, их создатели) пропагандируют старую как мир идею воспринимать модель данных, хранимых в БД и отображаемых на объекты, как ER-модель (Entity Relation).


T>Это не совсем так. Создатели EF понимают важность следования PI и планируют в следующих версиях поддерживать его в большей степени. Подробности можно прочитать в блоге ADO.NET Team-а.


Еще раз. PI как его понимаешь ты — это не совсем то что я имел в виду.
С другой стороны EF говоря (часто и настойчиво) о том, что EF основан на идее ER-отображения, на самом деле все дальше уходят от этой идее и приходят к идеям работы с объектной моделью, которая, по-моему, плохая идея.

VD>>В этой модели данные рассматриваются как набор сущностей, связанных между собой отношениями. Она отлично ложится на РСБУД с их «реляционно-алгеброическим бэкграундом».

VD>>Учитывая вышесказанное, довольно глупо ожидать от реализаций LINQ качественной реализации абстракций, для поддержки которых они не предназначены. LINQ просто не должен быть предназначен для обработки объектов путем перебора их в циклах и изменения их свойств. Вместо этого он должен манипулировать наборами сущностей с помощью запросов. Только сущности в LINQ представлены не кортежами, как в РСУБД, а объектами. Вот почему в LINQ to SQL даже нет сложной системы поддержки наследования. Ведь по уму одна сущность должна отображаться на один класс. Это самое прямое отображение, а значит, самое очевидное.

T>Мне кажется, при обсуждении технологий нельзя утверждать что что-то должно быть сделано именно так, без упоминания зачем это должно быть сделано именно так, без обсуждения преимуществ предложенного подхода. Если вы со мной согласны, не могли бы вы описать, в чем преимущество такого подхода?


Не согласен. Есть походы вредные и не нужные. Вот императивная обработка объектов отображаемых на БД — это идея вредная и не нужная. К сожалению, с легкой руки тех самых Корба и EJB она проела плеш очень многим и эти многие уже и представить себе не могут альтернативный подход.

Наличие (в LINQ to SQL и EF) возможности это делать (обрабатывать объекты императивно) — есть отход от декларируемой идеологии, что есть несомненной (для меня) зло. В то же время отсуствие декларативных средств обработки данных в стиле insert, update и delete просто не оставляет шансов не использовать иделогию противоречащую ER-идеологии.

Потом это твое высказывание вообще-то само по себе требует доказательства. Скажем на С++ можно писать в худших традициях С (повсеместно используя goto, адрессную арифметику, пользуясь только sprintf-ом и т.п. Но стоит ли так писать? Мне кажется — нет. Будет ли хорошо если кто-то будет писатиь программы так? Опять — нет. Так почему же "нельзя утверждать что что-то должно быть сделано именно так"?

VD>>Изменение данных в системах, пропагандирующих ER-подход, должно вестись теми же реляционными средствами, т.е. с помощью операторов insert, update и delete, как в оригинальном SQL, под который пытается мимикрировать LINQ. Тогда все бы встало на свои места.


T>Увы не стало бы.


С чего бы это?

T>Приведенные вами операторы не являются реляционными. За подробностями, отсылаю вас к книжке Дейта.


Это утверждение чушь, хотя формально оно и верно. Конечно в реляционной алгебре используются другие подходы, но суть их та же.
Главное, что insert, update и delete позволяют декларативно описывать изменения множеств (наборов данных). Это делает обрабтку эффективной, так как открывает возможность переложить обработку данных на СУБД.

Хочется задать встречный вопрос. Ты серьезно считашь, что обработка данных в императивном стиле, в виде объектов лучше? Если да, то попробуй обосновать это. Если нет, то опиши вариант который ты считашь лучшим.

VD>>Сущности не нужно было бы прицеплять к контексту. Транзакции можно было бы объявлять явно.


T>Их и так можно объявлять явно. Что может быть более явным чем TransactionScope?


Более явным может быть объявление транзакции. Что-то вроде:
using (myDb.BeginTran())
{
  insert into myDb.TableA values(1, 2, "test");
  delete from myDb.TableA where Col1 = 2;
}


T>Возможность писать insert/update/deletе прямо в языке штука конечно интересная, но стоит ли ее рассматривать как замену (а не как дополнение) существующим способам работы с данными — вот в чем вопрос.


Стоит. Я уже молчу об эффективности и удобстве. Но хотя бы с точки зрения концептуальной целостности стоит. Ведь МС явно декларирует, что LINQ to SQL и EF основаны на ER-модели. ER не ООП. Это модель отлично описывает БД в РСБУД, но не объектный граф. По сему и работать с ней надо как с БД, а не как с объектным графом.

VD>>В общем, на мой взгляд, Microsoft со своим EF пошла не в ту степь. Она (видимо, поддавшись крикам Hibernate-щиков) пошла по пути превращения EF в клон «классического» O/R Mapper-а, а реально – персистентной подсистемы. На мой взгляд, идея персистентности и манипуляции данными как объектами в корне порочна.


T>Почему вы так считаете?


Это мое мнение. Он в общем-то и обосновано в этой заметке.

VD>>Мне казалось, что Microsoft нащупал правильный путь, но сейчас я наблюдаю, как Microsoft твердой поступью идет в обратном направлении.

VD>>Единственное, что меня радует – это то, что Microsoft-таки показала, как интегрировать ER-подход с современными объектно-ориентированными языками с функциональным уклоном, и кто-то из посторонних сможет реализовать, казалось бы, такие напрашивающиеся для LINQ insert, update и delete. Жаль, что, в отличие от Nemerle, такие языки, как C# и VB, не позволяют расширить свой синтаксис чтобы бесшовно ввести эти операторы в язык. Но хотя бы в виде процедур, принимающих условия в виде деревьев выражений, их можно добавить в любой язык. Продаю идею .

T>Viva la Nemerle!


Болезнь какая-то. Одно упоминание Nemerle и у человека истерика.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 04.01.09 17:50
Оценка: +1 -1
Здравствуйте, VladD2, Вы писали:

VD>>>Учитывая вышесказанное, можно смело сказать, что под поклонниками Hibernate я имею в виду поклонников PI.

VD>>>Кто же здесь прав, а кто неправ? Неправы оба лагеря. И неправы они в восприятии понятия O/R Mapper. O/R Mapper не подразумевает реализации каких-то там идей «объектизации» БД и тем более PI. Задача O/R Mapper – просто отобразить данные, получаемые из РСУБД, в объекты, которыми удобно манипулировать в программе.

T>>В том-то и суть. Если доменная модель следует принцыпу PI, с ней становится очень легко работать, в отличие от объектов, привязанных к "хранилищу".


VD>На самом деле это не так. Работать легко с тем где меньше заморочек и удобнее средства, а не там где меньше связей с СУБД или еще чего-то.


Это два ортогональных "удобства", одно не отрицает другое.

T>>Мне кажется, при обсуждении технологий нельзя утверждать что что-то должно быть сделано именно так, без упоминания зачем это должно быть сделано именно так, без обсуждения преимуществ предложенного подхода. Если вы со мной согласны, не могли бы вы описать, в чем преимущество такого подхода?


VD>Не согласен. Есть походы вредные и не нужные. Вот императивная обработка объектов отображаемых на БД — это идея вредная и не нужная. К сожалению, с легкой руки тех самых Корба и EJB она проела плеш очень многим и эти многие уже и представить себе не могут альтернативный подход.


Нет, сам по себе подход не может быть "вредным и не нужным". Всегда нужно обосновывать почему он вреден и чем он лучше существующих подходов.

VD>Наличие (в LINQ to SQL и EF) возможности это делать (обрабатывать объекты императивно) — есть отход от декларируемой идеологии, что есть несомненной (для меня) зло.


А можно ссылку на информацию о том, что ER-подход был когда-либо продекларирован командой ADO.NET. Я всегда считал, что они делают O/R Mapper, а тут оказывается такое.

VD>В то же время отсуствие декларативных средств обработки данных в стиле insert, update и delete просто не оставляет шансов не использовать иделогию противоречащую ER-идеологии.


VD>Потом это твое высказывание вообще-то само по себе требует доказательства.


Которое высказывание требует доказательства? О том, что нужно обосновывать преимущества?

T>>Увы не стало бы.


VD>С чего бы это?


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

T>>Приведенные вами операторы не являются реляционными. За подробностями, отсылаю вас к книжке Дейта.


VD>Это утверждение чушь, хотя формально оно и верно. Конечно в реляционной алгебре используются другие подходы, но суть их та же.

VD>Главное, что insert, update и delete позволяют декларативно описывать изменения множеств (наборов данных). Это делает обрабтку эффективной, так как открывает возможность переложить обработку данных на СУБД.

Не понимаю, чем код customer.Name = "XXX"; ctx.SubmitChangs(); менее декларативен, чем update customer set Name = "XXX" where customer.id = 123 ?

VD>Хочется задать встречный вопрос. Ты серьезно считашь, что обработка данных в императивном стиле, в виде объектов лучше? Если да, то попробуй обосновать это. Если нет, то опиши вариант который ты считашь лучшим.


Я считаю этот вопрос стоит разделить на 2:
1) ER vs ObjectModel: мой выбор однозначно в пользу ObjectModel. Потому что она банально предоставляет больше возможностей. Кроме того, er может быть смоделирована через object model, обратное — неверно.
2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее. Единственный его недостаток — это когда нужно массово обновить большое количество объектов. В этом случае все объекты приходится тащить из базы, менять их в коде и сабмитить обратно. Это дико неэффективно. Для таких случаем было бы неплохо иметь возможность запускать DML непосредственно из кода. Как LINQ2SQL, так и EF такую возможнось имеют.

VD>>>Сущности не нужно было бы прицеплять к контексту. Транзакции можно было бы объявлять явно.


T>>Их и так можно объявлять явно. Что может быть более явным чем TransactionScope?


VD>Более явным может быть объявление транзакции. Что-то вроде:

VD>
VD>using (myDb.BeginTran())
VD>{
VD>  insert into myDb.TableA values(1, 2, "test");
VD>  delete from myDb.TableA where Col1 = 2;
VD>}
VD>


using(new TransactionScope())
Найди 10 отличий.

T>>Возможность писать insert/update/deletе прямо в языке штука конечно интересная, но стоит ли ее рассматривать как замену (а не как дополнение) существующим способам работы с данными — вот в чем вопрос.


VD>Стоит. Я уже молчу об эффективности и удобстве.


А ты не молчи, ты расскажи.

VD>>>В общем, на мой взгляд, Microsoft со своим EF пошла не в ту степь. Она (видимо, поддавшись крикам Hibernate-щиков) пошла по пути превращения EF в клон «классического» O/R Mapper-а, а реально – персистентной подсистемы. На мой взгляд, идея персистентности и манипуляции данными как объектами в корне порочна.


T>>Почему вы так считаете?


T>>Viva la Nemerle!


VD>Болезнь какая-то. Одно упоминание Nemerle и у человека истерика.


Да не, я серьезно. Хорошо, когда есть техническая возможность включить такого рода функциональность в язык.
Re[4]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 04.01.09 18:33
Оценка: +1
T>Не понимаю, чем код customer.Name = "XXX"; ctx.SubmitChangs(); менее декларативен, чем update customer set Name = "XXX" where customer.id = 123 ?

Тем, что он императивный
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[4]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 04.01.09 18:43
Оценка: +1
T>Я считаю этот вопрос стоит разделить на 2:
T>1) ER vs ObjectModel: мой выбор однозначно в пользу ObjectModel. Потому что она банально предоставляет больше возможностей. Кроме того, er может быть смоделирована через object model, обратное — неверно.
T>2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее. Единственный его недостаток — это когда нужно массово обновить большое количество объектов. В этом случае все объекты приходится тащить из базы, менять их в коде и сабмитить обратно. Это дико неэффективно. Для таких случаем было бы неплохо иметь возможность запускать DML непосредственно из кода. Как LINQ2SQL, так и EF такую возможнось имеют.

Не стоит свои предпочтения выдавать за истину в последней инстанции.
В корпоративных системах очень важны:
— глубокая транзакционность vs минимум блокировок
— быстрый доступ к пересечению и агрегации больших объёмов данных
— высокая актуальность данных
— единовременное изменение больших объёмов данных — операция разовая, если вообще может быть
Для совокупности этих принципов ER подходит намного лучше.
Для настольных систем — конечно лучше ObjectModel, особенно учитывая качество используемых БД и квалификацию разработчиков (в том числе и в смысле отсутствия разделения труда).
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[5]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 04.01.09 18:51
Оценка:
VGn>Не стоит свои предпочтения выдавать за истину в последней инстанции.
VGn>В корпоративных системах очень важны:
VGn>- глубокая транзакционность vs минимум блокировок
VGn>- быстрый доступ к пересечению и агрегации больших объёмов данных
VGn>- высокая актуальность данных
VGn>- единовременное изменение больших объёмов данных — операция разовая, если вообще может быть
VGn>Для совокупности этих принципов ER подходит намного лучше.
VGn>Для настольных систем — конечно лучше ObjectModel, особенно учитывая качество используемых БД и квалификацию разработчиков (в том числе и в смысле отсутствия разделения труда).

Не согласен. Есть походы вредные и не нужные. Вот императивная обработка объектов отображаемых на БД — это идея вредная и не нужная. К сожалению, с легкой руки тех самых Корба и EJB она проела плеш очень многим и эти многие уже и представить себе не могут альтернативный подход.

Туда же
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[4]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 04.01.09 19:10
Оценка: +2
Здравствуйте, Tissot, Вы писали:

T>Я считаю этот вопрос стоит разделить на 2:

T>1) ER vs ObjectModel: мой выбор однозначно в пользу ObjectModel. Потому что она банально предоставляет больше возможностей. Кроме того, er может быть смоделирована через object model, обратное — неверно.
И какой в этом смысл? ER-модель — это модель данных, из этой модели можно получить наборы классов. Имея произвольный набор классов у вас не всегда получится достаточно быстро сформировать ER-модель для хранения данных.

Кроме того ER модедль в программе позволяет оперировать только с нужными данными, а не тащить целый граф объектов из базы для изменения одного поля.

T>2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее. Единственный его недостаток — это когда нужно массово обновить большое количество объектов. В этом случае все объекты приходится тащить из базы, менять их в коде и сабмитить обратно. Это дико неэффективно. Для таких случаем было бы неплохо иметь возможность запускать DML непосредственно из кода. Как LINQ2SQL, так и EF такую возможнось имеют.

А в чем принципиальная разница между таким кодом
using(context.Batch()) //extension-метод Batch() вполне можно сделать как для Linq to SQL, так и для EF
{
    var q = from c in context.Customers where c.Id == 1;
    foreach(var customer in q)
    {
      c.Name = "aaa";
    }
}


и таким
using(context.Batch())
{
    update c in context.Customers where c.Id == 1 set c.Name = "aaa"; //Предположим что так можно написать
}

В обоих местах используется Unit of Work, только во втором случае его даже легче сделать будет.
При этом второй кусок гораздо более декларативен и позволяет внести изменения в коллекцию (таблицу в базе) без материализации самих записей.

В обоих случаях может работать тяжелый маппинг между объектной моделью и БД.

T>>>Возможность писать insert/update/deletе прямо в языке штука конечно интересная, но стоит ли ее рассматривать как замену (а не как дополнение) существующим способам работы с данными — вот в чем вопрос.

VD>>Стоит. Я уже молчу об эффективности и удобстве.
T>А ты не молчи, ты расскажи.
на примере выше можете увидеть что в в случае наличия update не надо тянуть из базы изменяемые записи.
Re[5]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 05.01.09 02:51
Оценка: -2
Здравствуйте, VGn, Вы писали:

VGn>Не стоит свои предпочтения выдавать за истину в последней инстанции.


Не стоит выдавать де-факто стандарт в области разработки корпоративных приложений за мое предпочтение.

VGn>В корпоративных системах очень важны:

VGn>- глубокая транзакционность vs минимум блокировок

Что значит глубокая транзакционность?
Почему вариант с update/insert будет иметь меньшее кол-во блокировок?

VGn>- быстрый доступ к пересечению и агрегации больших объёмов данных


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

VGn>- высокая актуальность данных


И?

VGn>- единовременное изменение больших объёмов данных — операция разовая, если вообще может быть


Спасибо за еще один довод против ER

VGn>Для совокупности этих принципов ER подходит намного лучше.

VGn>Для настольных систем — конечно лучше ObjectModel, особенно учитывая качество используемых БД и квалификацию разработчиков (в том числе и в смысле отсутствия разделения труда).

Конечно-конечно, довод и разряда "все гандоны, а я супер". Продолжай в том же духе.
Re[5]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 05.01.09 03:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Я считаю этот вопрос стоит разделить на 2:

T>>1) ER vs ObjectModel: мой выбор однозначно в пользу ObjectModel. Потому что она банально предоставляет больше возможностей. Кроме того, er может быть смоделирована через object model, обратное — неверно.
G>И какой в этом смысл? ER-модель — это модель данных, из этой модели можно получить наборы классов. Имея произвольный набор классов у вас не всегда получится достаточно быстро сформировать ER-модель для хранения данных.

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

G>Кроме того ER модедль в программе позволяет оперировать только с нужными данными, а не тащить целый граф объектов из базы для изменения одного поля.


Как EF, так и Linq2Sql поддерживают ленивую загрузку.

T>>2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее. Единственный его недостаток — это когда нужно массово обновить большое количество объектов. В этом случае все объекты приходится тащить из базы, менять их в коде и сабмитить обратно. Это дико неэффективно. Для таких случаем было бы неплохо иметь возможность запускать DML непосредственно из кода. Как LINQ2SQL, так и EF такую возможнось имеют.

G>А в чем принципиальная разница между таким кодом
G>
G>using(context.Batch()) //extension-метод Batch() вполне можно сделать как для Linq to SQL, так и для EF
G>{
G>    var q = from c in context.Customers where c.Id == 1;
G>    foreach(var customer in q)
G>    {
G>      c.Name = "aaa";
G>    }
G>}
G>


G>и таким

G>
G>using(context.Batch())
G>{
G>    update c in context.Customers where c.Id == 1 set c.Name = "aaa"; //Предположим что так можно написать
G>}
G>

G>В обоих местах используется Unit of Work, только во втором случае его даже легче сделать будет.

Только во втором случае его придется-таки делать. А первый уже есть. Как говорится, почувствуйте разницу.

G>При этом второй кусок гораздо более декларативен и позволяет внести изменения в коллекцию (таблицу в базе) без материализации самих записей.


Вы уверены, что именно это является узким местом?

G>В обоих случаях может работать тяжелый маппинг между объектной моделью и БД.


T>>>>Возможность писать insert/update/deletе прямо в языке штука конечно интересная, но стоит ли ее рассматривать как замену (а не как дополнение) существующим способам работы с данными — вот в чем вопрос.

VD>>>Стоит. Я уже молчу об эффективности и удобстве.
T>>А ты не молчи, ты расскажи.
G>на примере выше можете увидеть что в в случае наличия update не надо тянуть из базы изменяемые записи.

Пример надуманный. Де-факто, прежде чем изменить что-то в базе понадобится еще сделать валидацию, поправить информацию о дате последнего изменения, изменить зависимые данные и так далее и тому подобное.
Re[6]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.01.09 06:58
Оценка: 56 (7) +3
Здравствуйте, Tissot, Вы писали:
T>Что значит глубокая транзакционность?
T>Почему вариант с update/insert будет иметь меньшее кол-во блокировок?
Вопрос не в количестве, а во времени удержания.
Даже модификация одного объекта через "сохранение состояния" несёт в себе заметный оверхед.
А если мы модифицируем набор объектов, то сервер может вообще отпускать блокировки по мере выполнения запроса.
Я уж не говорю о том, что то, что большинство Full-blown O/R Mapper-ов называют "Optimistic locking" — вообще фикция.

Возьмем классический пример: резервирование товара.
Катя забивает накладную на отгрузку. Затем Оля делает операцию "Зарезервировать накладную". В O/R мире это означает:
1. Загрузить все позиции накладной в кэш
2. Загрузить все позиции складских остатков, использованные в накладной, в кэш (тут обычно вмешивается Lazy Loading, просаживая эффективность до нуля, но мы сейчас не о нём, и представим, что хитрый программист уже оптимизировал код этого бизнес-метода так, что он поднимает нужные объекты в кэш одним запросом)
3. Пройтись по складским позициям и сделать StoreItem.Available-=OrderItem.Amount; StoreItem.Reserved + =OrderItem.Amount.
4. Если где-то Available получился отрицательным, то сделать откат транзакции
5. Иначе вызвать Context.SubmitChanges() или его аналог.
6. Аналог начинает шариться по списку dirty items и строить набор update statements. В эти statements, естеснно, входит проверка, не изменил ли кто-то еще наши storeItems в промежутке между 2 и 6. Если мы говорим об OLTP системе, то шансы на это весьма велики. В принципе, ничего страшного нет, потому что совершенно неважно, в каком порядке резервировать товар на складе (если только его хватает на всех, а это почти всегда так), но Блокировка Оптимистов показывает стальные зубы, и говорит, что на всякий случай нужно рестартовать всю транзакцию
7. Cамое классное — если Катя в последний момент исправляет количество заказанного товара в накладной. Блокировка Оли, будучи Оптимистичной, никак этого не замечает — в её commit нет изменений OrderItem, и сравнивать их не с чем. А в коммите Кати нет изменений StoreItem. В итоге мы имеем замечательную ситуацию: Катя думает, что зарезервировано 1000 банок майонеза, а на складе в резерв встало 500. Просто чудо, а не блокировка.

А теперь посмотрим, как бы это работало без Full Blown O/R mapper.
В старые добрые времена программист БД просто написал бы один запрос вида:
update StoreItem set Available = Available - OrderItem.Amount, Reserved = Reserved + OrderItem.Amount
from StoreItem inner join OrderItem on StoreItem.ProductID = OrderItem.ProductId
where OrderItem.OrderID = @OrderId and StoreItem.Available >= OrderItem.Amount;

Сервер бы сам проследил за целостностью транзакции, не давая Кате модифицировать накладную в процессе резервирования. (Обеспечение запрета модифицировать накладную после резервирования потребовало бы чуть больше приседаний, но в чистом Оптимистично Блокированном мире это вообще невозможно без лишних телодвижений).

Фишка в том, что в этом подходе коду бизнес логики вообще неинтересно, сколько там товара на складе. Ему не нужно поднимать эти данные ни в какой кэш, ни в серверный, ни в клиентский. Это экономит трафик.
Кроме того, весь код транзакции исполняется максимально близко к данным. Это обеспечивает самое короткое время удержания блокировок, что существеннно улучшает пропускную способность.

В итоге, невозможность конструировать такие запросы через Linq и вызывает недоумение у всего прогрессивного человечества.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 05.01.09 08:38
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>Я считаю этот вопрос стоит разделить на 2:

T>>>1) ER vs ObjectModel: мой выбор однозначно в пользу ObjectModel. Потому что она банально предоставляет больше возможностей. Кроме того, er может быть смоделирована через object model, обратное — неверно.
G>>И какой в этом смысл? ER-модель — это модель данных, из этой модели можно получить наборы классов. Имея произвольный набор классов у вас не всегда получится достаточно быстро сформировать ER-модель для хранения данных.

T>Конечно же, на объектную модель тоже накладываются определенные ограничения. Но зачем целиком отказываться от удобств, предоставляемых ею?

Так никто не предлагает отказываться от удобств, как раз предлагают отказаться от неудобств объектной модели при работе с данными.

G>>Кроме того ER модедль в программе позволяет оперировать только с нужными данными, а не тащить целый граф объектов из базы для изменения одного поля.

T>Как EF, так и Linq2Sql поддерживают ленивую загрузку.
Неправда, EF не поддерживает ленивую зугрузку. Да и вообще ленивая загрузка — большое зло, в программе надо видеть где происходит обращение к БД.

T>>>2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее. Единственный его недостаток — это когда нужно массово обновить большое количество объектов. В этом случае все объекты приходится тащить из базы, менять их в коде и сабмитить обратно. Это дико неэффективно. Для таких случаем было бы неплохо иметь возможность запускать DML непосредственно из кода. Как LINQ2SQL, так и EF такую возможнось имеют.

G>>А в чем принципиальная разница между таким кодом
G>>
G>>using(context.Batch()) //extension-метод Batch() вполне можно сделать как для Linq to SQL, так и для EF
G>>{
G>>    var q = from c in context.Customers where c.Id == 1;
G>>    foreach(var customer in q)
G>>    {
G>>      c.Name = "aaa";
G>>    }
G>>}
G>>


G>>и таким

G>>
G>>using(context.Batch())
G>>{
G>>    update c in context.Customers where c.Id == 1 set c.Name = "aaa"; //Предположим что так можно написать
G>>}
G>>

G>>В обоих местах используется Unit of Work, только во втором случае его даже легче сделать будет.

T>Только во втором случае его придется-таки делать. А первый уже есть. Как говорится, почувствуйте разницу.

Второго варианта вообще нету сейчас, а если появятся, то обязательно появятся транзакции\батчи.

G>>При этом второй кусок гораздо более декларативен и позволяет внести изменения в коллекцию (таблицу в базе) без материализации самих записей.

T>Вы уверены, что именно это является узким местом?
Более чем. Даже в случае изменения в одной записи можно получить заметный выйгрыш, а в слчуае обновления\удаления многих записей быстродействие увеличится в разы.

T>>>>>Возможность писать insert/update/deletе прямо в языке штука конечно интересная, но стоит ли ее рассматривать как замену (а не как дополнение) существующим способам работы с данными — вот в чем вопрос.

VD>>>>Стоит. Я уже молчу об эффективности и удобстве.
T>>>А ты не молчи, ты расскажи.
G>>на примере выше можете увидеть что в в случае наличия update не надо тянуть из базы изменяемые записи.

T>Пример надуманный.

Ну настолько же надуманный, как и весь SQL.

T>Де-факто, прежде чем изменить что-то в базе понадобится еще сделать валидацию, поправить информацию о дате последнего изменения, изменить зависимые данные и так далее и тому подобное.

То что касается целостности данных должно находится в БД и все проверки и изменения должны осуществляться самой БД.
То что касается бизнес-логики вполне может быть условием в самом запросе или проверяться до обращения к данным.
Re: Некоторые мысли о LINQ
От: alvas  
Дата: 05.01.09 08:50
Оценка: 2 (1) +2
Здравствуйте, VladD2, Вы писали:

VD>напрашивающиеся для LINQ insert, update и delete. Жаль, что, в отличие от Nemerle, такие языки, как C# и VB, не позволяют расширить свой синтаксис чтобы бесшовно ввести эти операторы в язык. Но хотя бы в виде процедур, принимающих условия в виде деревьев выражений, их можно добавить в любой язык. Продаю идею .


Планируется ли добавление в Nemerle insert, update и delete?
http://alvas.net — Аудио-инструменты для .Net разработчиков
Re[7]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 05.01.09 14:10
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Что значит глубокая транзакционность?

T>>Почему вариант с update/insert будет иметь меньшее кол-во блокировок?
S>Вопрос не в количестве, а во времени удержания.

Вот как раз в случае UoW удержание будет меньше.
Рассмотри сценарий чуть посложнее, чем "обновить поле". Например в результате какой-то операции сначала нам понадобилось обновить у сustome-а поле A, потом провести какие-то достаточно длительные вычисления, потом обновить поле B.
В варианте с UoW на время операции будет наложена shared блокировка и только на время submit-а — более тяжелая exclusive.
В случае, если действуем по вашему сценарию — сразу получаем exclusive и удерживаем ее на время операции.
И какой вариант после этого более легковесный?

S>Даже модификация одного объекта через "сохранение состояния" несёт в себе заметный оверхед.

S>А если мы модифицируем набор объектов, то сервер может вообще отпускать блокировки по мере выполнения запроса.

Очень интересно. Откуда же сервер узнает, что блокировку можно отпустить, что она более не понадобится?

S>Я уж не говорю о том, что то, что большинство Full-blown O/R Mapper-ов называют "Optimistic locking" — вообще фикция.


S>Возьмем классический пример: резервирование товара.

S>Катя забивает накладную на отгрузку. Затем Оля делает операцию "Зарезервировать накладную". В O/R мире это означает:
S>1. Загрузить все позиции накладной в кэш
S>2. Загрузить все позиции складских остатков, использованные в накладной, в кэш (тут обычно вмешивается Lazy Loading, просаживая эффективность до нуля, но мы сейчас не о нём, и представим, что хитрый программист уже оптимизировал код этого бизнес-метода так, что он поднимает нужные объекты в кэш одним запросом)
S>3. Пройтись по складским позициям и сделать StoreItem.Available-=OrderItem.Amount; StoreItem.Reserved + =OrderItem.Amount.
S>4. Если где-то Available получился отрицательным, то сделать откат транзакции
S>5. Иначе вызвать Context.SubmitChanges() или его аналог.
S>6. Аналог начинает шариться по списку dirty items и строить набор update statements. В эти statements, естеснно, входит проверка, не изменил ли кто-то еще наши storeItems в промежутке между 2 и 6. Если мы говорим об OLTP системе, то шансы на это весьма велики. В принципе, ничего страшного нет, потому что совершенно неважно, в каком порядке резервировать товар на складе (если только его хватает на всех, а это почти всегда так), но Блокировка Оптимистов показывает стальные зубы, и говорит, что на всякий случай нужно рестартовать всю транзакцию
S>7. Cамое классное — если Катя в последний момент исправляет количество заказанного товара в накладной. Блокировка Оли, будучи Оптимистичной, никак этого не замечает — в её commit нет изменений OrderItem, и сравнивать их не с чем. А в коммите Кати нет изменений StoreItem. В итоге мы имеем замечательную ситуацию: Катя думает, что зарезервировано 1000 банок майонеза, а на складе в резерв встало 500. Просто чудо, а не блокировка.

S>А теперь посмотрим, как бы это работало без Full Blown O/R mapper.

S>В старые добрые времена программист БД просто написал бы один запрос вида:
S>
S>update StoreItem set Available = Available - OrderItem.Amount, Reserved = Reserved + OrderItem.Amount
S>from StoreItem inner join OrderItem on StoreItem.ProductID = OrderItem.ProductId
S>where OrderItem.OrderID = @OrderId and StoreItem.Available >= OrderItem.Amount;
S>

S>Сервер бы сам проследил за целостностью транзакции, не давая Кате модифицировать накладную в процессе резервирования. (Обеспечение запрета модифицировать накладную после резервирования потребовало бы чуть больше приседаний, но в чистом Оптимистично Блокированном мире это вообще невозможно без лишних телодвижений).

Во-первых, вы допустили ошибку в коде.
Во-вторых, на самом деле все может быть сложнее: для каких-то категорий клиентов/товаров вполне может быть позволено заказывать в минуса, для каких-то категорий товаров должен гарантировано оставаться какой-то остаток на складах, если заказ крупный, то должно быть проверено, внесена ли предоплата и т.д. и т.п.. Я бы не хотел поддерживать код в котором все эти правила внесены в один update.

S>Фишка в том, что в этом подходе коду бизнес логики вообще неинтересно, сколько там товара на складе. Ему не нужно поднимать эти данные ни в какой кэш, ни в серверный, ни в клиентский. Это экономит трафик.


Фишка в том, что это не код, а фикция.

S>Кроме того, весь код транзакции исполняется максимально близко к данным. Это обеспечивает самое короткое время удержания блокировок, что существеннно улучшает пропускную способность.


Ты забыл добавить "если update — это единственная действие в бизнес-транзакции".

S>В итоге, невозможность конструировать такие запросы через Linq и вызывает недоумение у всего прогрессивного человечества.


А может зря оно себя таким уж прогрессивным считает?
Re[7]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 05.01.09 14:24
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Конечно же, на объектную модель тоже накладываются определенные ограничения. Но зачем целиком отказываться от удобств, предоставляемых ею?

G>Так никто не предлагает отказываться от удобств, как раз предлагают отказаться от неудобств объектной модели при работе с данными.

Я видимо не до конца понимаю, что имеется в виду.
Наследование, интерфейсы, методы, атрибуты — для меня это удобства, от которых я бы очень не хотел отказываться.

G>>>Кроме того ER модедль в программе позволяет оперировать только с нужными данными, а не тащить целый граф объектов из базы для изменения одного поля.

T>>Как EF, так и Linq2Sql поддерживают ленивую загрузку.
G>Неправда, EF не поддерживает ленивую зугрузку. Да и вообще ленивая загрузка — большое зло, в программе надо видеть где происходит обращение к БД.

Согласен, погорячился, но Linq2Sql поддержиает

G>>>При этом второй кусок гораздо более декларативен и позволяет внести изменения в коллекцию (таблицу в базе) без материализации самих записей.

T>>Вы уверены, что именно это является узким местом?
G>Более чем. Даже в случае изменения в одной записи можно получить заметный выйгрыш, а в слчуае обновления\удаления многих записей быстродействие увеличится в разы.

Не забывай добавлять "в простых (а потому нежизненных) сценарих". Все равно нужно будет делать валидацию/проверку прав/аудит, тут-то объект у вас в память и заползет.

T>>Пример надуманный.

G>Ну настолько же надуманный, как и весь SQL.

SQL — это язык для манипулирования данными. Объект доменной области же — сущность более сложная.

T>>Де-факто, прежде чем изменить что-то в базе понадобится еще сделать валидацию, поправить информацию о дате последнего изменения, изменить зависимые данные и так далее и тому подобное.

G>То что касается целостности данных должно находится в БД и все проверки и изменения должны осуществляться самой БД.

Ну приплыли.

G>То что касается бизнес-логики вполне может быть условием в самом запросе


До тех пор, пока бизнес-логика ограничивается простыми правилами.

G>или проверяться до обращения к данным.


Где? В каком слое приложения?
Re[8]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 05.01.09 19:43
Оценка: 58 (1)
Здравствуйте, Tissot, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>Конечно же, на объектную модель тоже накладываются определенные ограничения. Но зачем целиком отказываться от удобств, предоставляемых ею?

G>>Так никто не предлагает отказываться от удобств, как раз предлагают отказаться от неудобств объектной модели при работе с данными.

T>Я видимо не до конца понимаю, что имеется в виду.

T>Наследование, интерфейсы, методы, атрибуты — для меня это удобства, от которых я бы очень не хотел отказываться.
Не отказывайтесь. Но базовая модель для данных — ER (потому что БД так работает) и объектная модель должна при желании надстраиваться над ER, причем все "прелести" как ленивая загрузка должны быть опциональны и по-умолчанию выключены.

G>>>>Кроме того ER модедль в программе позволяет оперировать только с нужными данными, а не тащить целый граф объектов из базы для изменения одного поля.

T>>>Как EF, так и Linq2Sql поддерживают ленивую загрузку.
G>>Неправда, EF не поддерживает ленивую зугрузку. Да и вообще ленивая загрузка — большое зло, в программе надо видеть где происходит обращение к БД.
T>Согласен, погорячился, но Linq2Sql поддержиает
В Linq2SQL гораздо сложнее отключить ленивую загрузкую.

G>>>>При этом второй кусок гораздо более декларативен и позволяет внести изменения в коллекцию (таблицу в базе) без материализации самих записей.

T>>>Вы уверены, что именно это является узким местом?
G>>Более чем. Даже в случае изменения в одной записи можно получить заметный выйгрыш, а в слчуае обновления\удаления многих записей быстродействие увеличится в разы.

T>Не забывай добавлять "в простых (а потому нежизненных) сценарих". Все равно нужно будет делать валидацию/проверку прав/аудит, тут-то объект у вас в память и заползет.

Да ну? Как раз security можно создать дополнительными фильтрами выборки. В моих проектах так и делается, при выборке в память не тянутся объекты для которых доступа нету.
При записи все равно приходится вытягивать нужный объект(с теми же secutiry фильтрами). При наличии операторов update\delete теже фильтры перекочевали бы в соответствующие запросы и не было бы необходимости тянуть целый объект.

T>>>Пример надуманный.

G>>Ну настолько же надуманный, как и весь SQL.

T>SQL — это язык для манипулирования данными. Объект доменной области же — сущность более сложная.

И что? все равно в итоге все сводится к козданию SQL кода манипулирования данными. Но проблема SQL в том, что он не статически типизируемый в коде приложения.
Так вот и предлагается упростить этот путь. Причем таким образом можно добиться более эффективной работы.

T>>>Де-факто, прежде чем изменить что-то в базе понадобится еще сделать валидацию, поправить информацию о дате последнего изменения, изменить зависимые данные и так далее и тому подобное.

G>>То что касается целостности данных должно находится в БД и все проверки и изменения должны осуществляться самой БД.
T>Ну приплыли.
Ну не знаю как у вас, а у меня так работает. И отлично работает, по поводу lastModified вообще никто не парится.

G>>То что касается бизнес-логики вполне может быть условием в самом запросе

T>До тех пор, пока бизнес-логика ограничивается простыми правилами.
Сложные правила также могут быть выражены в запросах, которые выполняются в SQL, а при помощи Linq записаны в коде приложения.
Но пока все изменения объектов производятся в памяти, то такой подход неэффективен. Вам придется записать все изменения, запустить запросы, осуществляющие валидацию модели, при неуспешном результате откатить транзакцию. Транзакцию и код проверки для этого придется запускать вручную.

Если все изменения данных выполняются реляционными операторами и бизнес-правила выражены запросами, то все запросы можно выполнить в одной транзакции БД (при этом практически не тянуть в память объекты), при этом вопросами целостности и конкуретного доступа к данным будет заниматься БД.

G>>или проверяться до обращения к данным.

T>Где? В каком слое приложения?
В PL — проверка введенных данных и в BLL — проверка агрументов и параметров окружения.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.