Некоторые мысли о 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[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[14]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 19:13
Оценка: +6
Здравствуйте, Jakobz, Вы писали:
J>Ок. Если нужно залить несколько разных объектов кто будет заниматься сортировкой операций insert/update/delete?
Не нужно думать об этом в стиле "залить несколько разных объектов" и всё будет замечательно.

J>Я в другой ветке писал про это. Что если у нас два одинаковых объекты и мы поменяем только один?

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

J>Pessimistic — да, обеспечивает. На уровне одного соединения/транзакции. Как средствами СУБД обрабатывать классическую ситуацию: чувак открыл форму редактирования, ушел домой, а кому-то нужно что-то в ней этой же форме поправить?

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

Представь себе другую ситуацию — ты открыл форму оплаты за телефон пластиковой картой. Она, собственно, не собирается "редактировать" никакой объект — она описывает действие, а не результат. Действием будет перевод денег со счёта на счёт; в его результате изменится баланс. Если попробовать "редактировать" баланс счёта в той идеологии, которую предполагаешь ты, то возникает масса угловых сценариев — вроде того, как два человека вручную вычитают сумму транзакции из баланса, и происходит потеря изменений.
Ну, точнее, с учетом optmistic locking, тот, кто опоздал, получит "конфликт обновления" и будет вынужден вычитать сумму транзакции заново, до тех пор, пока не окажется достаточно шустрым для победы в гонке коммитов.
Но если трактовать транзакцию именно как действие, то совершенно неважно, ушел ли ты домой или нет — это никому не мешает производить другие транзакции с тем же счётом.

Фишка в том, что датасеты и прочие механизмы прочитать-изменить-записать посвящены именно проблеме прямого управления данными.
Для управления в стиле действий, которые как раз хорошо ложатся на update, insert, delete, приходится изобретать многочисленные приседания.
Особенно забавно то, что для простых транзакций, с изменением одиночных объектов, identity tracking и change tracking не очень-то нужны — ты и так знаешь, какой именно объект ты пытаешься изменить. Эти механизмы становятся критически нужны в тех случаях, когда ты согласованно изменяешь набор "объектов", причем такой набор, который заранее плохо определен.

Так вот юмор как раз в том, что это именно та ситуация, для которой и создавался SQL. И "прокладка", которая сначала хорошо помогала реализовывать чужеродный для СУБД сценарий "сохранения объекта", теперь начинает мешать — и к ней нужна еще одна прокладка в виде кэша, а к нему точные change трекеры и прочие костыли.

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

J>Update() в LINQ тоже с блокировками выполняется и в одной транзакции. Странно, зачем там optimistic concurency?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[30]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 17:36
Оценка: 2 (1) +4
Здравствуйте, Tissot, Вы писали:

T>Где-то еще — это где? Я предполагал, что у кастомера и так есть страна. Тогда получить валидацию можно так:

T>
T>ZipCodeValidationStrategyFacory.GetByCountryCode(this.CountryCode)
T>

Прекрасный пример. Давайте разберем его поподробнее.
1. Логика проверки зипкода инкапсулирована внутрь объекта "кастомер". Тебе это очень нравится, но на самом деле это означает, что у нас нет никакого способа узнать, валиден ли зип, не попробовав выполнить присваивание свойству. С точки зрения внешнего кода, кастомер — это чёрный ящик.
Возникают вопросы примерно такого рода:
а) как нам проверить валидность зипа прямо в UI, где недоступен экземпляр класса "кастомер"?
б) как нам получить осмысленный результат проверки, а не просто исключение и роллбэк? Ну, там, чтобы, к примеру, было сказано, где именно в индексе ошибка, и образец правильного заполнения?

2. Наша "сущность" начинает резко утяжеляться. Вот сейчас ей уже нужна по соседству табличка со всеми странами. Ну, то есть на самом деле надо будет еще и хранить историю правил формирования зип-кодов для всех стран.
Это еще уменьшает шансы "оторвать" ее от сервера приложений и обработать где-то еще.
Я уж не говорю про повторное использование в другой ситуации.

T>А теперь рассказывай, как ты будешь с этим бороться:


T>
T>update customer set zipCode = "любой невалидный zip";
T>

Очень просто. Такого кода в прикладном слое вовсе нет. Потому что модификация зип-кода проходит только через CustomerManager, который конечно же не забудет позвать все правила проверки пре-кондишнов. Это раз.

Два, в большом-большом количестве случаев лучше этот код разрешить. В частности, к примеру, потому, что далеко не всегда при создании кастомера есть информация про его зипкод. При таком подходе очень быстро окажется, что "ой, проверить стоимость остатков нельзя без проведения заказа, заказ нельзя ввести без кастомера, а кастомера нельзя завести без корректного зип-кода и ИНН". До свидания, бизнес сломался.
А если подумать головой, то окажется, что зип-код нужен только в тот момент, когда выполняется отгрузка товара. Если кастомер хочет заказать и заплатить, то нет никакой причины требовать от него валидность ненужного сейчас зип-кода.
В итоге, вместо вшитой в ZipCode { set ; } логики мы получаем Precondition для операции "отгрузить заказ", как я и говорил.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 01:47
Оценка: 2 (2) +2
Здравствуйте, alvas, Вы писали:

A>Планируется ли добавление в Nemerle insert, update и delete?


Кстати, это может оказаться той самой killer-feature, которая сподвигнет кого-то присмотреться к языку внимательнее.
Re[12]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.01.09 11:40
Оценка: 5 (1) +2
Здравствуйте, Tissot, Вы писали:

T>А я и не хамлю.

T>Пункт 4 не выполнен.
Я намеренно не стал приводить полный код. Пункт четыре достигается одной дополнительной строчкой. В реальной жизни, конечно же, бизнес-транзакция не сведется к одному update. Она сведется к небольшому количеству update, которые выполняются без передачи лишней информации за пределы СУБД.

T>Кстати, еще одно вспомнилось, что непонятно как поддеживать в Linq-е — рекурсивные запросы.

Есть много способов поддерживать рекурсивные запросы. Худший из них — выполнение рекурсии вне СУБД.

T>Дерзайте, я не против.

Это хорошо. Мне как раз показалось, что ты против.

T>Если что получится — хорошо, значит примем на вооружение еще один прием.

T>Не получится — тоже хорошо, значит я был прав.

T>Опять нифига не понятно. Чтение в Unit of Work в конечном итоге — это тот же SELECT. Тут или ты чего не договоариваешь, или .. на этом моя мысль заканчивается.

В Unit of Work чтение — это обращение к объектам. Причем выполняется оно в две фазы:
1. Подъем объектов в память (в этот момент работает select)
2. Обращение к свойствам объектов.
Как правило, операция №1 настолько дорога, что ее выполняют через кэш. Кэширование на корню убивает возможность автоматической блокировки прочитанных объектов. Поэтому для обеспечения целостности приходится делать дополнительные приседания. Например, вручную блокировать интересующие объекты.

Конечно, можно обойтись и без кэша. Но тогда ситуация будет достаточно малоприятной для unit of work из-за просада производительности.
Теоретически, можно было бы трассировать и операции №2, аналогично тому, как это делается для отслеживания модификаций. Но на практике я такого не встречал. Смею полагать, что тоже по соображениям производительности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
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[14]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.01.09 09:39
Оценка: 1 (1) +2
Здравствуйте, Tissot, Вы писали:

T>Ладно, сдаюсь, задолбало меня отвечать на ваше изменение условий. Вы сначала сделайте, что хотите, а потом уже и будет о чем говорить. А ток — одна сплошная риторика.

Я таких систем, в общем-то, написал в ассортименте. И с ORM-подходом тоже наелся по самое не хочу.

S>>А теперь расскажи нам, как это работает в случае unit of work. Какие блокировки накладываются в какой момент, и в какой они отпускаются. Учти еще, что характерное время ответа от веб-сервиса — это 200мс, а одиночный апдейт в базе выполнится примерно за 10мс.


T>Я про фому, а ты опять про ерему. В реальной жизни ты не добьешься непересечения под-задач по данным.

Я не виноват, что ты так плохо придумываешь задачи.

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

Это иллюзия. Понимаешь, это в случае unit of work и "тру-ООП" подхода у тебя модификации хаотически разбросаны по всему коду. И совершенно непонятно, сколько раз и что апдейтится, и нет ли между апдейтами тяжелой операции с вовлечением внешних ресурсов.

А если ты работаешь в реляционном подходе, то у тебя четко выделены все моменты, когда ты лезешь в базу. И там "просматривать" ничего не надо. Логика будет сильно структурирована: вот мы получаем остатки позиций на складе (с учетом всех политик безопасности и специфических для товарных позиций ограничений), вот мы сравниваем их с позициями заказа; вот мы обрабатываем случаи неполного комплекта и всё такое прочее. А вот собственно результирующий батч поехал в базу, и после его выполнения можно смело переходить к фазе рендера результатов.

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

Упрощается, и сильно упрощается.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 11:49
Оценка: 1 (1) +2
Здравствуйте, Jakobz, Вы писали:

J>Я не тебе отвечал вообще-то и тебя не задалбывал.


Ты Маугли кого хочешь достанешь (с) анекдот.

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

J>Задаете вопрос зачем identity tracking, я отвечаю.


Ну, и что ты отвечаешь то? Сам почитай...
Identity tracking нужен для модели с датаконтекстом. А зачем нужна эта модель и все ее прибамбасы?
Сто лет назад придумали SQL который оптимален для манипуляции данными с БД.
Таз зачем нужна модель которая пытается спрятать от нас то, что данные лежат в БД?

J>Записывать можно и без контекста и без трекинга. А можно — с контекстом и трекингом.


А зачем с ними то?

VD>>У тебя мозг уже работает только в условиях одной парадигмы. Объяснить тебе что-то невозможно, так как ты просто не хочешь воспринять наличие другой парадигмы.


J>Нет.


Уверяю тебя. Ты знаком хотя бы с одним функциональным языком? Чувствую, что нет.
Так вот попробуй изучить. Уверяю тебя, что крышу будет рвать не по детски. А меж тем ничего сложного там нет. Просто несоответствие межд тем как ты видишь мир вычислений и тем как ее представляет модель ФП.
Вот та же байда и здесь.

J>Просто у меня мозг работает ближе к практике.


В чем это заключается?

J>Я понимаю что вы хотите. Но мне непонятны детали. Давай поговорим про конкретику:


ОК

J>1. как должно выглядеть в коде то, о котором вы говорите? Возьмем, например, update. Видимо там должно быть выражение, которое поставить в where и какой-то набор выражений про то, что сделать со столбцами. При чем для каждого выражения для каждого столбца должен быть доступ к контексту всей строки. Приведи хоть примерчик в псевдокоде.


Мне прийдется тебе просто привести пример SQL-ного update-а.
Ну, скажем:
update set c.Name = "Новое имя" from c in customers where c.id = 123;

или
var cutomer1 = ...;
update set c.Name = "Новое имя" set c.Bonus = c.Bonus + 1; 
   from c in customers 
   where c is cutomer1;

что тоже самое, но id будет взят не явно из экземпляра cutomer1 в котором он хранится.

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

Если снова возникает вопрос, а как защититься от случайного переписывания данных, то это можно сделать так:
var cutomer1 = ...;
var oldName = cutomer1.SelectedData_Name; // данные когда-то полученные с сервера для свойства Name
update set c.Name = "Новое имя" set c.Bonus = c.Bonus + 1; 
   from c in customers 
   where c is cutomer1
     and c.Name == oldName; // старое


J>И как быть с update из другого select-а?


Точно так же:
var cutomer1 = ...;
var oldName = cutomer1.SelectedData_Name; // данные когда-то полученные с сервера для свойства Name
update set c.Bonus = c.Bonus + 1; 
   from c in customers 
   where (from o in orders where c.Total > 1000m select o.CustomerId)
   .Distinct().Contains(c.id)


J>2. очевидно что программу из одних select-ов и update-ов не напишешь.


Э... не очевидно конечно. Но наверно смысла в этом нет.

J>Между ними данные должны попадать в код и как-то обрабатываться. Например у нас есть три колонки a, b и c. Нам нужно сделать какие-то вычисления и положить результат в колонки d и e. Предположим что для этого задействуется большое количество C#-кода. И что переписать это в форме запроса в базу нельзя — например d и e запрашиваются у стороннего веб-сервиса.


Переписать это скорее всего будет можно. В конце концов нем никто не запрещает создать дотнетную функцию, описать ее как SQL-ую и вызвать ее в рамках одного запроса.

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

J>Как это все будет выглядеть? Отдельно будут объекты с полями a, b и c, полученые из базы и отдельно — объекты с d и e для сохранения, так?


Да. Первым запросом мы выберем нужные данные "from x in xs select a, b, c...". Затем обработаем их и запишем назад с помощью update.

J>Анонимные типы нельзя передавать между методами, поэтому про них забываем. Получается что для каждой нужной комбинации полей строки придется создавать свой объект?


Если надо обработать только b и d, то и передай своей функции их. Ты же сам сказал, что обработка возможна только в потребительском коде.

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

J>3. как быть, если в update что-то сложнее, чем встроеные в sql функции? Что должен сделать LINQ, если он не может выполнить на БД какой-нибудь гиперболический косинус? Тащить все в код, там перефигачивать и заливать назад?


Я бы создавал внешние функции и использовал бы их на сервере.

ЗЫ

Не знаю умеют ли сегодняшние Linq2SQL и EF работать с внешними функциями, но если даже не умеют, то следовал бы их этому научить.

У нас тут IT пишет свой LINQ-провайдер. Думаю, в нем мы реализуем все необходимое. А в Немерле прикрутим синтаксис. Шарп будет довольствоваться кодом без синтаксиса (с явной передачей лямбд в ФВП).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 22:33
Оценка: -2 :)
Здравствуйте, gandjustas, Вы писали:

T>>Не мог бы ты оставаясь в рамках этого примера описать, откуда возникнет "меньшее время" и "больший контроль"?


G>Если расчеты в п2 не зависят от апдейта в п1, то сначала выполняем расчеты (не ставим эксклюзивные блокировки), потом формируем 2 апдейта и выполняем их в БД.

G>Если расчеты в п2 зависят от апдейта в п1, то выделяем независимую часть расчетов из п2 и выполняем, потом выполняем апдейт, зависимую от апдейта часть расчетов (гораздо быстрее), мерджим с независимой, выполняем второй апдейт.

А можно не изменять условия задачи?
А то при таком подходе и я теорему Ферма на коленке за минут докажу.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 12:56
Оценка: -1 :))
Здравствуйте, Sinclair, Вы писали:

T>>Кстати, еще одно вспомнилось, что непонятно как поддеживать в Linq-е — рекурсивные запросы.

S>Есть много способов поддерживать рекурсивные запросы. Худший из них — выполнение рекурсии вне СУБД.

Конструктивнее. Давай лучшие в студию.

T>>Опять нифига не понятно. Чтение в Unit of Work в конечном итоге — это тот же SELECT. Тут или ты чего не договоариваешь, или .. на этом моя мысль заканчивается.

S>В Unit of Work чтение — это обращение к объектам. Причем выполняется оно в две фазы:
S>1. Подъем объектов в память (в этот момент работает select)
S>2. Обращение к свойствам объектов.
S>Как правило, операция №1 настолько дорога, что ее выполняют через кэш. Кэширование на корню убивает возможность автоматической блокировки прочитанных объектов. Поэтому для обеспечения целостности приходится делать дополнительные приседания. Например, вручную блокировать интересующие объекты.

Кэш — в топку.

S>Конечно, можно обойтись и без кэша. Но тогда ситуация будет достаточно малоприятной для unit of work из-за просада производительности.


Отлично. Осталось выяснить откуда взялся просад производительности.
Что такого сложного в том, чтобы сделать select и результат распихать по свойствам?
Re[28]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 11:15
Оценка: +3
Здравствуйте, Tissot, Вы писали:
T>Оттуда же откуда взялся у тебя свзязаный список.
Еще раз объясняю: чтобы упорядочить список кастомеров "в реале", не нужно ничего. Можно просто написать их на бумажке в нужном порядке.
В программировании нет концепции "пространственного расположения", поэтому нужно искусственно ввести в "описание кастомера" какие-то дополнительные данные.
Либо номер его позиции в списке, либо ссылку на следующего в списке.
Ни то ни другое не имеет отношения к предметной области. Это — артефакты моделирования. Точно так же, как и табличка для связи "многие-ко-многим" не соответствует никакому классу объектов предметной области.

T>Ну не надо Фаулера уж совсем за идиота считать. Понятно же, что анализ/моделирование присутствует всегда.

Пока что непонятно. Ты очень ловко манипулируешь понятием "domain model". В итоге, она моделирует всё, что угодно. Как у Лема про сепульки.
Так всё-таки, что именно моделирует domain model? К чему она должна быть близка?
Мне как-то не хочется пользоваться термином, определенным через самого себя.

T>Ест такие понятия. Только формулируются они не как "существительные", а как некоторые правила, ограничения.

И какие же правила в предметной области соответствуют DACL?

T>Для них нет "физического" представления в предметной области, но есть концептуальное.

Что такое "концептуальное представление"?

T>Ты очень правильно выделил "в таком". Но из того, что "в таком виде малопригодно" не следует, что ООП само по себе непригодно.

Никто и не протестует против ООП вообще. Просто в бизнесе полиморфизм оказывается применим не к данным, а к сервисам. Применять всю мощь ООП к данным — примерно то же самое, что одушевлять бухгалтерские проводки
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[35]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 12.01.09 20:54
Оценка: :)))
Здравствуйте, Sinclair, Вы писали:

Все, сдаюсь. Вы победили, черти языкастые.
Re: LINQ rulez ! , но это не только SQL
От: Silver_s Ниоткуда  
Дата: 14.03.09 11:41
Оценка: :)))
Мои размышления о LINQ.
Для вычислительных задач LINQ немеренно крутая штука. Никакие функциональные,декларативные языки теперь даром не нужны.
Под LINQ имею ввиду — содержимое Enumerable + лямбда выражения + Generics + автоматическое выведение типов
+yield+... + то что можно самостоятельно написать по подобию Enumerable (используя основную его концепцию).
Только это как-то долго доходило ... когда эти фичи появлялись казались мелочами. И даже от таких Generic казалось единственная польза это то что с ArrayList чуть попроще работать. А когда все эти фичи объединились, оказалось что в C# появилась новая концепция программирования, более высокоуровневая, объединение декларативного программирования и обычного в одном языке.

В проектах где много вычислительных задач со сложными структурами данных, отбрасывается огромное количество ненужной мышиной возни, по созданию каких-то бессмысленых промежуточных классиков, коллекций,функций, переменных, запихиванию и вытаскиванию из них данных туда-сюда...что-то типа такого.
В таких проектах много LINQ не бывает, чем его больше тем меньше объем кода, лучше читабельность, повторная используемость.
Хотя возможно преборы и бывают...

Если к примеру взять такую задачу(алгоритм), довольно распространенную при работе с графами.
Получение "компонент связности" графа. Т.е. грубо говоря, разделение графа на куски между которыми не было связей,
а внутри каждого куска связи есть (от любой вершины можно добраться до любой другой).
Сам по себе алгоритм простой — выбираем вершину и рекурсивно движемся по связанным вершинам помечая их числом (в уже помеченные не заходим чтобы не зациклится на петлях). Когда закончили обход, потом Выбираем другое число и еще не помеченную вершину и также метим рекурсивно. Когда непомеченых не осталось, все вершины помеченые одинаковым числом входят в одну компоненту связности.
Графы в программе представляют(если не считать матричное представление) либо списком ребер(связей) — одно ребро это пара вершин. Либо представляют в виде списка смежностей — для каждой вершины храним список связанных с ней.

Допустим функция получает список ребер (список пар вершин) и должна вернуть вершины сгруппированые по "компонентам связности".
Если смотреть такие алгоритмы в разной литературе по дискретноой математике, то там самая настоящая мышиная возня, на каком то языке паскале-си-подобном. На таких языках (такими средствами) самого алгоритма совсем чуть-чуть, основной объем кода это возня со структурами данных.
Этот алгоритм можно почти целиком сделать на LINQ и объем кода раз в 5 меньше и читабельность выше, и еще Generic вершины будут.(И вроде даже производительность сильно не подсаживает.)
Две небольшие статические функции. Одна публичная, другая рекурсивная:


//Нахождение "компонент связности" графа. Принимает список ребер графа.
// Возвращает список компонент, в компоненте список вершин.
//если ребра(связи) повторяются то тоже будет работать правильно.
public static List<List<TVertex>> FindConnectivityComponents<TVertex>(IEnumerable<Pair<TVertex, TVertex>> Links) 
    where TVertex: class
{
    Links = Links.Concat(    //добавляем обратные связи
        Links.Select(l => new Pair<TVertex, TVertex> { First = l.Second, Second= l.First })   
        ); 
    Dictionary<TVertex, Pair<TVertex, int>> markedVertexDict =   //ключ-вершина, значение-маркированая вершина
        Links.Select(l => l.First).Distinct()
        .Select(vertex => new Pair<TVertex, int> { First = vertex, Second = 0 })    //превращаем в маркированую
        .ToDictionary(markedVertex => markedVertex.First)
        ;
    var adjucentLists =   //ключ-маркированая вершина, значение-список примыкающих маркированых вершин 
        Links.ToLookup(l => markedVertexDict[l.First], l => markedVertexDict[l.Second]);

    int componentNum = 1;
    foreach (var vertex in markedVertexDict.Values)
        MarkConnectedVertexesRecursive(vertex, componentNum++, adjucentLists);
    return
        markedVertexDict.Values
        .GroupBy(v => v.Second, v => v.First) //(ключ-номер компоненты, значение-вершина)
        .Select(grouping => grouping.ToList())
        .ToList();
}
//Маркирует числом markWithNumber вершины начиная с startVertex, рекурсивно все связаные с ней.
private static void MarkConnectedVertexesRecursive<TVertex>(
    Pair<TVertex, int> startVertex,
    int markWithNumber,
    ILookup<Pair<TVertex, int>, Pair<TVertex, int>> graphAsAdjacentLists)
{
    if (startVertex.Second != 0) //уже прошлись по этой вершине
        return;
    startVertex.Second = markWithNumber;
    foreach (Pair<TVertex, int> linked in graphAsAdjacentLists[startVertex])
        MarkConnectedVertexesRecursive(linked, markWithNumber, graphAsAdjacentLists);
}





И еще примерно такая штука

public class Pair<T1, T2>
{
public T1 First;
public T2 Second;
}

Единственная неприятность безобразия наподобие такого ILookup<Pair<TVertex, int>, Pair<TVertex, int>> ,
надо какие-то фичи в языке что-ли сделать типа синонимов, хотя-бы на уровне компиляции а не рантайм,
чтобы код не засорять излишествами.

И еще хочется чтобы конструкторы имели Generic параметры и по ним выводился создаваемый класс.
например вместо new Pair<int,string>(1,"s") чтобы можно было бы написать new Pair(1,"s") и по конструктору
бы настроился созданный класс. Потому что вместо int,string могут стоять гигантские конструкции с Generic,
а класс Pair (или Triple) могут употребляться часто в разных целях. Анонимными типами их не всегда удается заменить.

И непонятно почему нельзя вызвать статическую функцию без указания Generic параметров класса, если эта функция не
использует Generic параметры класса. тогда можно было бы создать этот самый Pair через его статическую функцию,
с автоматическим выводом типов:
static BPair New<T1,T2>(T1 val1,T2 val2)
{
return new BPair<T1,T2>{First=val1,Second=val2};
}

А так приходится выносить такую функцию в отдельный класс New, чтобы создавать Pair и и другие классы так: New.Pair(1,"s");
Re[10]: Некоторые мысли о LINQ
От: IT Россия linq2db.com
Дата: 25.03.09 14:32
Оценка: +3
Здравствуйте, Jakobz, Вы писали:

J>Я имел ввиду identity объектов:

J>1. select * from Persons where person_id = 1
J>2. юзер выбирает список персон
J>3. select * from Persons
J>Первая персона у нас теперь в виде объектов в двух экземплярах — из первого и второго запроса.
J>Не запутаешься с этим? Ничего что "==" для объектов нельзя будет использовать? Или будет собственный велик?

Вот уже лет пять не испытываю с этим никаких проблем. Два экземпляра одной сущности могут мещать только в statefull архитектурах, которые являются проблемой сами по себе. А вместо "==", которое опять же в нормальном дизайне нафиг не нужно, можно с успехом использовать person1.ID == person2.ID.
Если нам не помогут, то мы тоже никого не пощадим.
Re[24]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 31.03.09 16:25
Оценка: 70 (2)
Здравствуйте, lomeo, Вы писали:

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


VD>>Конечно спорил! Ты прочти свои предыдущие сообщения.


L>Речь шла о Customer -> Customer, из которого ну никак ты не получишь SQL.

Да ну?


string GenerateSetClauseFromExpression<T>(Expression<Func<T, T>> expr)
{
    var parameter = expr.Parameters[0];
    var memberInit = expr.Body as MemberInitExpression;

    return String.Join(", ",
               memberInit.Bindings
               .OfType<MemberAssignment>()
               .Select(a => a.Member.Name + " = " + ExpressionToSql(a.Expression))
               .ToArray()
           );
}

Dictionary<ExpressionType, string> binaryOps = new Dictionary<ExpressionType, string>()
{
    {ExpressionType.Add, "+"},
    {ExpressionType.Subtract, "-"},
    {ExpressionType.Multiply, "*"},
    {ExpressionType.Divide, "/"},
};


string ExpressionToSql(Expression e)
{

    var constantExpression = e as ConstantExpression;
    if (constantExpression != null)
    {
        return ToSqlString(constantExpression.Value);
    }

    try
    {
        Expression<Func<object>> lambda = Expression.Lambda<Func<object>>(Expression.Convert(e, typeof(object)), new ParameterExpression[0]);
        return ToSqlString(lambda.Compile()());
    }
    catch (Exception)
    {

        var member = e as MemberExpression;
        if (member != null)
        {
            var param = member.Expression as ParameterExpression;
            if (param != null)
            {
                return (member.Member as System.Reflection.PropertyInfo).Name;
            }
        }

        var binary = e as BinaryExpression;
        return ExpressionToSql(binary.Left) + binaryOps[binary.NodeType] + ExpressionToSql(binary.Right);
    }

}

string ToSqlString(object o)
{
    if (o is string)
    {
        return "'" + o + "'";
    }
    else
    {
        return o.ToString();
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

static void Main(string[] args)
{
    var setClause = GenerateSetClauseFromExpression<Person>(p => new Person() { Name = "aaa", Age = p.Age + 1 });
    Console.WriteLine("update Persons set {0}", setClause);
}


Наколеночное решение за 15 минут.
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: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.01.09 02:02
Оценка: 4 (1) +1
Здравствуйте, VladD2, Вы писали:


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

VD>Единственное, что меня радует – это то, что Microsoft-таки показала, как интегрировать ER-подход с современными объектно-ориентированными языками с функциональным уклоном, и кто-то из посторонних сможет реализовать, казалось бы, такие напрашивающиеся для LINQ insert, update и delete. Жаль, что, в отличие от Nemerle, такие языки, как C# и VB, не позволяют расширить свой синтаксис чтобы бесшовно ввести эти операторы в язык. Но хотя бы в виде процедур, принимающих условия в виде деревьев выражений, их можно добавить в любой язык. Продаю идею .
А вот подоспел и ответ из Редмонда. Правда, неофициальный.
Как видишь, идеи манипулирования данными с помощью запросов находят широкий отклик среди передовой общественности.
Считаю, что Nemerle мог бы поддержать инициативу камрада Мэтта Уоррена путем добавления нативного linq-подобного синтаксиса, соответствующего IUpdatable<T>.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.03.09 11:50
Оценка: 4 (1) +1
Здравствуйте, Aen Sidhe, Вы писали:


AS>Я имел ввиду — как работать с БД без DataContext'ов? Код, который будет заниматься сохранением данных в РСУБД будет где? И как он будет работать? Я либо туплю, либо просто не знаю, но мне на ум только ActiveRecord приходит.

Ну обычный DML работает через Connection и ниче.
В принципе для более сложной системы DataContext будет чуть более сложной версией коннекшена.

Сейчас же объекты контекстов сочетают в себе еще и identity\change tracking, средства ленивой и отложенной загрузки, а также управление всем этим барахлом.
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[26]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 09:03
Оценка: 2 (1) +1
Здравствуйте, Tissot, Вы писали:
T>Зачем это ID в кастомере? Просто передавай в метод обработки список кастомеров.
Откуда возьмется "список"?

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

Об этом я и говорю. Вот эта "предметная область" — нифига не "предметная область". Это "модель предметной области", которая сделана по некоторым соображениям.
Имхо, Фаулер говорил именно о предметной области, а не об артефактах, вызванных моделированием.

T>Опять 25. Если для тебе данные — это сущность, то да, если для тебя (меня) сущность — это сущность domain model, то нет.

А ты попробуй всё-таки понять, что такое "domain model". Что именно там domain?

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

Как артефакт анализа. Простейшая штука — ID. В предметной области никаких суррогатных ключей нету. В данных почему-то появляются.
В предметной области нет никаких понятий типа "доступа", они появляются только после моделирования. Этакие "сущности второго порядка".

В развитом приложении, к примеру, правила валидации сами становятся "сущностями", хотя никакому объекту в предметной области они не соответствуют.

В итоге, применение ООП для моделирования "реального мира" в большинстве случаев совершенно бесполезно.

Вообще, напомню, что ООП появилось как попытка разработать удачную абстракцию для оконно-ориентированного GUI. Именно поэтому в ранних книгах по ООП так много примеров на тему pWindow->draw() или pFigure->draw().
Прошли годы, и оказалось, что даже для этих задач ООП в таком виде малопригодно.
Что окна удобнее собирать из готовых примитивов как агрегаты, а не наследовать друг от друга.
Что и геометрические фигуры не надо наследовать друг от друга, а достаточно иметь ровно один класс VectorPath, который рисуется ровно одним образом, а бытность его квадратом или треугольником — всего лишь предикат, а не имманентное свойство.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
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
От: 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[16]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 06.01.09 12:46
Оценка: +2
Здравствуйте, Tissot, Вы писали:


T>Ну в общем-то так и думал. Работал с таким — лучше чем ничего, но все равно недостаточно удобно. Если придумаете что-то более удобное — то честь вам и хвала.

Достаточно того, что это намного удобнее чем UoW, ORM и прочие приседания вокруг ОО.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[10]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 07.01.09 07:48
Оценка: +2
Здравствуйте, Tissot, Вы писали:

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


T>>>Не мог бы ты оставаясь в рамках этого примера описать, откуда возникнет "меньшее время" и "больший контроль"?


G>>Если расчеты в п2 не зависят от апдейта в п1, то сначала выполняем расчеты (не ставим эксклюзивные блокировки), потом формируем 2 апдейта и выполняем их в БД.

G>>Если расчеты в п2 зависят от апдейта в п1, то выделяем независимую часть расчетов из п2 и выполняем, потом выполняем апдейт, зависимую от апдейта часть расчетов (гораздо быстрее), мерджим с независимой, выполняем второй апдейт.

T>А можно не изменять условия задачи?

Никто не меняет условия, входные и выходные данные остаются. Вы почему-то пытаетесь доказать неправильность какого-то подхода через свое кривое решение. Если решение не кривое, то и подход оказывается вполне нормальным.

T>А то при таком подходе и я теорему Ферма на коленке за минут докажу.

Ну доказывайте.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 08:58
Оценка: -2
Здравствуйте, Sinclair, Вы писали:

S>И худший он именно из-за того, что быстрое звено (СУБД) вынуждено удерживать блокировки до тех пор, пока медленное звено (веб-сервис) не проснется и не ответит.

S>Более того, в предлагаемой схеме временная проблема с веб-сервисом (банальное падение роутера между ним и application tier) иожет привести к откату транзакции резервирования товара. Так делать не надо.

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


Ладно, сдаюсь, задолбало меня отвечать на ваше изменение условий. Вы сначала сделайте, что хотите, а потом уже и будет о чем говорить. А ток — одна сплошная риторика.

S>А теперь расскажи нам, как это работает в случае unit of work. Какие блокировки накладываются в какой момент, и в какой они отпускаются. Учти еще, что характерное время ответа от веб-сервиса — это 200мс, а одиночный апдейт в базе выполнится примерно за 10мс.


Я про фому, а ты опять про ерему. В реальной жизни ты не добьешься непересечения под-задач по данным. Хотя бы уже потому, что иначе тебе при каждом изменении нужно будет просматривать все использования изменяемого тобою кода. А с учетом того, что предполагается использовать возможности БД на полную катушку, это еще более усложняется.
Re[14]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 16:19
Оценка: +2
Здравствуйте, Tissot, Вы писали:

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


G>>>>Полиморфизм достигается не только вирткальными методами в классе.

T>>>Ну интерфейсы еще есть, конечно, но они тоже не являются частью er-модели.
G>>Вам наверное стоит разобраться что такое полиморфизм.
T>Не стоит, я знаю, что такое полиморфизм.
Видимо стоит, почитайте http://www.rsdn.ru/forum/message/2853873.aspx
Автор: Gaperton
Дата: 26.02.08


T>>>Сама реализация валидации может быть расположена и где-то вовне класса, а класс может просто делегировать вызов. Очень удобно, например на SubmitChanges проверять таким образом валидность измененных сущностей.

G>>Да уж... Валидацию сущностей надо задавать декларативно — атрибутами или во внешних конфигах. Смотрите Validation Application Block из enterprise library.

T>Не все проверки стоит делать атрибутами. Иногда это может оказаться overkil-ом.

"Иногда" это когда? Я только один такой сценарий представляю — когда программа пишется "на выброс".

G>>>>Методы в классах сущностей это ближе к предметной области?

T>>>Ну да.
G>>С чего это?
G>>Кроме того такие решения обычно нарушают SRP,

T>Нарушение SRP можно где угодно усмотреть, было бы желание. Оставишь исключительно данные в сущности — все равно будет нарушение SRP, т.к. класс берет на себя не только ответственность за хранение Name-а, но и LastUpdatedBy. Так что не нужно к этому принципу подходить параноидально, во всем надо знать меру.

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

G>>а преимуществ от них маловато, даже понимаемость кода страдает в таких условиях, за исключением самых простых случаев.

T>Я так не считаю.
Можете каким-нибудь аргументом подкрепись свое мнение, иначе нет смысла его писать.
Re[18]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 17:17
Оценка: +1 :)
Здравствуйте, Tissot, Вы писали:

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


T>>>Когда проверка очень специфична для сущности и реюз этой проверки не предполагается.

G>>Получается что часть проверок будет заданы атрибутами\конфигом, а часть в коде методов класса?
G>>Совсем фигня получается. Кроме того вся валидация может быть выполнена используя только публичный контракт класса сущности, еще один повод вынести её отдельно.
G>>Если подсистему валидации нормально продизанить, то получится что-то вроде validation app block.

T>Если ты внимательнее посмотришь validation app block, то увидишь, что в нем предусмотрен вариант для тех случаев, когда сущность сама себя валидирует.

Всегда все можно сделать неправильно, и оно при этом даже будет работать.

G>>>>Есть обязанность "хранить данные", вот объекты-сущности эти обязанности выполняют независимо от состава полей.

T>>>А данные — это набор атрибутов, следовательно обязанность "хранить данные" — это составная обязанность, которая может быть разбита на более мелкие.
G>>Это уже плод больного воображения.
T>Нет, это всего лишь SRP доведенный до конца.
Это бред.

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

T>>>Во всем надо знать меру.
G>>Ага, самоя хорошая мера называется SRP.
T>См. выше.
С каких пор абсурдные высказывания являются аргументом?
SRP придумали не для того чтобы начинающих программистов пугать.

G>>На моей первой работе был гениальный класс Queue (очередь), унаследованный от TStringList (на делфи). Содатели этого класса мотивировали удобством, хотя через интерфейс TStringList можно было нарушить работу класса очереди.

T>Неудачный пример.
Почему? Удобно же.
Re[22]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 08:58
Оценка: +2
Здравствуйте, Tissot, Вы писали:

T>Почему не нужен? Хранить данные — это ведь отдельная обязанность (с) gandjustas. Непоследовательно как-то получается.

В классе очереди хранение данных нам неинтересно. Поэтому такой обязанности вовсе нет.

Если бы речь шла о персистентной очереди, где вопрос хранения её состояния имел бы право на отдельное существование, то тогда да — то, что ты предлагаешь, примерно бы подошло. Но только public бы там надо было раздавать с осторожностью: первичен всё-таки контракт поведения очереди. А как там оно хранится — внутреннее дело QueueManager. Может быть, там вся очередь сериализуется в монолитный XML; может быть, там реляционная табличка; а может быть — там специально устроенная очередь на основе фич MS SQL Server. В зависимости от этого получаются совершенно разные наборы объектов: Queue, QueueItem, QueueHandle и так далее.

Глумиться над SRP — неумно. Лучше попытаться всё же понять, как опытные собаководы проводят границы ответственности, и почему это делается именно так.
А кривляния в нашем деле не помогают.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 11:34
Оценка: +2
Здравствуйте, Tissot, Вы писали:
T>В этом и предмет разногласия. Для domain model "нижележащие данные" — это всего лишь способ долговременного хранения сущностей.
Совершенно верно. Это и есть основная ошибка. "Сущность" сегодня одна, завтра — другая. А "нижележащие данные" о к примеру, переписи населения США 1891 года до сих пор лежат, как лежали. Они никак не изменятся.


T>Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

Вот именно! Замечательное свойство ортогональности исчезает, как только карточку начинают наделять сущностью. Чем отличается сущность от карточки? Правильно, наличием поведения. Ну так вот у карточки нет никакого поведения.
Искусственно внедрять в неё поведение можно, но от этого получаются негативные эффекты.

T>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.

Вот как раз контракт взаимодействия с хранилищем может запросто поменяться. Сегодня XML, завтра CSV, послезавтра — RDBMS. Сами данные при этом, естественно, останутся всё теми же.

T>Не только к умению группировать но и к сохранению инвариантов.

У данных почти что нет инвариантов. Я уже об этом писал.
Вот только что в нашем продукте напоролись: встроенная валидация хочет не более 8 символов для зипкода. В Иране — 10. Прощай, инвариант.
T>Если публичный контракт таков, что для реализации какого-то функционала реализацию можно разместить снаружи класса, то можно это оформить в виду сервисного класса. Но только в том случае, если сущность не может быть "поломана" извне.
Данные — это данные. Их никак не поломаешь. Даже null/not null — и то зачастую чрезмерно жесткие ограничения для статической формализации.
Очень немногие "инварианты" заслуживают встраивания в "сущность".
Как правило, в бизнесе вместо них есть пред- и пост-условия. Но они применимы не к "данным", а к "операции над данными". А операции над данными, как мы уже договорились, лежат снаружи — в некоем Manager или Service. Вот в нём да — нужно обеспечивать "неломаемость" операций.

Захочется поспорить — попробуй привести примеры "реализации функционала, который может поломать сущность, будучи размещенным извне".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[36]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 18:37
Оценка: +2
Здравствуйте, Tissot, Вы писали:

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

T>>>Пункты ортогональны, но в программную модель они лягут по другому
G>>По какой причние?
T>Потому что инвариант.


G>>Указанные пункты отлично ложатся на код с тойже степенью ортогональности.

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

Какие инварианты? В анализе инвариантов не было. Достаточно чтобы модель соответствовала бизнес-правилам до и после завершения бизнес-операций. Фактически необходима транзакционная целостность модели для бизнес-операций. Что происходит внутри транзакции с точки зрения анализа неважно.
Кроме того в бизнесе даже не все бизнес-правила являются строгими.
Например остатки в учетных системах важно проверять на конец отчетного периода, а не при каждой операции.

То что нужны инварианты в классах данных, которые вроде как обеспечивают целостность всей операции, это уже вы сами придумали. Даже у фаулера такого нету.
Re[34]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.01.09 08:00
Оценка: +2
Здравствуйте, Tissot, Вы писали:
T>Для меня предметная область и есть результат анализа.
Ок. А что тогда является предметом анализа?
T> Разве это не для всех так?! Тады ой.
Не, не для всех. Для большинства предметная область — это собственно прообраз, который мы анализируем. Не обязательно это будет именно "реальный мир", в том смысле, что, к примеру, бухгалтерия к реальному миру никакого отношения не имеет, но тем не менее она является полноценной предметной областью.

Отсюда понятно, что предметная область не может быть результатом анализа. Ты же не думаешь, что бухгалтерия — все эти планы счетов, проводки, актив/пассив и прочие понятия — возникает из небытия только тогда, когда архитектор 1с берется за дело?
Нет, она существует совершенно отдельно от софта.

T>Соответствует — пользователи, относящиеся к этому кастомеру.

Ну вот еще. Пока что нет повода генерализовывать пользователей "относящихся к кому-то" до группы пользователей вообще.


T>Годится. Программная архитектура — это то, что следует ЗА анализом, не перед.

Продолжаю непонимать, что же именнол следует "перед" анализом. Пока что все понятия, которые ты вводишь, у тебя являются результатом анализа.
Я насчитал уже три: "концептуальная модель", "предметная область", "программная архитектура".
Ты не мог бы расшифровать своё понимание этих понятий и их взаимосвязь? А также пояснить, к чему именно должна быть близка "доменная модель" как подвид "программной архитектуры".
Это я к тому, что, вообще говоря, любая архитектура будет близкой к соответствующему результату анализа.

А какая именно — зависит только от способа, которым анализ проводить. К примеру, если мы анализируем проблему с точки зрения ФП, то у нас модель предметной области будет содержать исключительно функции различных порядков. Если применить OOD, то получим объектную модель. Если применить реляционную алгебру, то получим ER-модель. Естественно, реализующая это архитектура будет максимально приближена к построенной модели.

S>>Пока что никаких инвариантов, невыразимых настройками банальной ER-модели, не прозвучало.

T>Где-то из подветок писал, что при закрытии кастомера должны быть закрыты соотвтствующие equipment-ы. Это вполне себе констрейнт.
Что характерно, он не является инвариантом . Это постусловие для некоторого действия. Причем замечу, что оно несводимо к ограничениям уровня объекта, т.к. включает в себя несколько объектов. Более того, это скорее наше определение операции "закрытия кастомера".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[35]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 12.01.09 09:07
Оценка: +1 :)
S>А какая именно — зависит только от способа, которым анализ проводить. К примеру, если мы анализируем проблему с точки зрения ФП, то у нас модель предметной области будет содержать исключительно функции различных порядков. Если применить OOD, то получим объектную модель. Если применить реляционную алгебру, то получим ER-модель. Естественно, реализующая это архитектура будет максимально приближена к построенной модели.

Комплексный подход конечно сложнее и запутанней, но результаты получаются имхо поинтереснее
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Re[10]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.09 14:28
Оценка: +2
Здравствуйте, Jakobz, Вы писали:

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


VD>>Не будет дурацкой схемы датаконтекстов не будет и проблем связанных с ней.

J>Хорошая логика. Типа "нет человека — нет проблем" Не будет датаконтекстов — не будет и удобств, которые они дают.
Самое интересное что это работает.

J>Собственно тебя никто и не заставляет юзать DataContext. Совсем от него отказаться нельзя, но можно же select-ить в ReadOnly, а апдейтить потом как угодно.

В том то и дело что заапдейтить без работы с объектами и datacontext нельзя.

VD>>Твое identity не более чем уникальный идентификатор. Хочешь сделай счетчик на сервере, хочешь используй GUID. Это сто лет назад решенная проблема.


J>Я имел ввиду identity объектов:

J>1. select * from Persons where person_id = 1
J>2. юзер выбирает список персон
J>3. select * from Persons
J>Первая персона у нас теперь в виде объектов в двух экземплярах — из первого и второго запроса.
J>Не запутаешься с этим? Ничего что "==" для объектов нельзя будет использовать? Или будет собственный велик?
В EF есть entitykey для этих целей.
И даже без него операцию == можно определить так чтобы она нормально работала (по ключам).


VD>>Просто ты привык к схемам тяжелых OR-маперов. Вот и боишься, что они вдруг исчезнут.

J>Не, я вообще не привык к комфорту. На проекте, на котором я уже пару лет занят — вообще датасеты и все руками. Но у нас специфика такая, что в основном с базой только на чтение работа идет.
На самом деле привычка больше в способе работы: считать->изменить->записать. Естественно между двумя обращениями может много чего произойти, вот и городят optimistic concurrency.
Если применить Command-query separation к работе с данными, то все операции можно будет разделить на два типа
1)выборка без побочных эффектов, identity map и unit of work не нужны, и никакой контекст не нужен.
2)операции, вызывающие изменения данных можно будет делать как отправку батча sql-команд на сервер, контекст тоже не нужен.
Re[12]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.03.09 18:34
Оценка: +2
Здравствуйте, Jakobz, Вы писали:

VD>>А в чем удобства то?


J>- identity tracking

J>- change tracking

Сами ради себя что ли?
Или это все ради удовольствия возиться с обработкой объектов в циклах?

Пойми все эти красивые слова "identity", "tracking", "change tracking" придуманы только ради того, чтобы программист думал что он работает не с данными взятыми из БД, а с объектой моделью которая сама собой (чудесным образом) сохраняет свое состояние.

Вот только ООП супротив придуманной 50 лет назад СУБД — это козьи потягушки. Запросы намного мощнее и безопаснее императивного кода.

Забудь про весь этот трекинг и жить станет проще и лучше.

J>Апдейть через другой DataContext. Или пиши своё — со множественными апдейтами.


В задницу твой DataContext.

VD>>И что? Это не проблема. Апдэйты ведь ведутся по тому самому person_id.


J>Какую из персон менять будешь? Не перепутаешь потом какую в базу потом запихивать? Не получится что обе-две в случайном порядке?


Да я не буду менять персон. Я поле поменяю. Причем то что изменил пользователь. Я тут ну никак не ошибусь.

J>Датаконтект предлагает реализацию оптимистических блокировок. И не мешает делать пессимистические. Разве кроме этих двух есть какие-то другие подходы?


В задницу твой датаконтект и то что он предлагает. Я без него могу намного эффективнее работать.

Записать данные одного измененного объекта не проблема. Группы — тоже. Код для этого пишется на коленке за 3 часа. Выполнить его в рамках одной транзакции — тоже элементарно. А вот когда тебе придется делать сложные массовые обновления данных (ну, там сумму по заказу в поле поместить или еще что), то сделать это запросом в сто раз проще будет.

VD>>А что там решать то? В коде апдэйта автоматом докидвать RowID = RowID?

J>Да. Еще обрабатывать ошибки и заворачивать их в удобоваримый формат — что случилось, наша версия строки, версия из базы и т.п.

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

VD>>А как решать проблемы создаваемые этим самым датаконтекстом? Что если оптимистическая блокировка по логике не подходит? Подстраиваться?


J>Отключать оптимистический контроль. Включать блокировку при запросе, если все проводится в одну транзакцию. Если не в одну транзакцию — наверное делать какой-то lock manager. Не вижу чтобы Linq to SQL здесь навязывала именно свое решение.


И держать блокировку все время работы клиента? Здорово! А нам все что было нужно — это сумировать данные по заказу и запихнуть их в поле "СуммаЗаказа". Глупо, не правда ли?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.09 21:49
Оценка: +2
Здравствуйте, Jakobz, Вы писали:

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


S>>Я тебя понимаю — я еще в долинковские времена наприседался с ORM, и самописанными в том числе, и все их прелести прекрасно осознаю. Linq — это шаг в правильную сторону, вот только надо бы шагнуть и второй ногой тоже. А то между ними как раз зависла суровая действительность, где вся мощь функциональной декомпозиции притянута вниз гирей two-way binding.


J>Я тоже понимаю о чем вы говорите. Но это всё очень далеко от практики.

J>Хорошие подходы: тащить код к данным, а не наоборот, писать на языке, удобным для работы со структурой данных, и т.п. Но они все как-то не совмещаются ни с SQL, ни с C#. Не сможешь ты прозрачно отобразить сколько-то сложный C#-код или какой-то DSL на нем, в полноценный SQL прямо на сервере.
Если хочется отображать императивный код на C#, то лучше и не пытаться. А если вполне функциональный Linq, то очень даже хорошо получается.
Сейчас Linq мапится в селекты очень хорошо, за исключением CTE и, кое-где уловия IN.

J>А если и сможешь — умрешь разбираться с проблемами производительности и блокировками.

Как раз с проблем с производительностью и блокировками будет меньше.

J>Поэтому модель "оцепил что нужно — обработал — положил назад" — очень даже жизнеспособна.

В отсуствии лучшего решения — конечно.
Re[7]: Некоторые мысли о LINQ
От: IT Россия linq2db.com
Дата: 27.03.09 15:57
Оценка: +2
Здравствуйте, Sergey T., Вы писали:

ST>Никакая база данных и никакой линк не сможет сформировать текст апдейт запроса так, чтобы база данных подхватила изменения локальных объектов. А это значит, что Апдейт в ЛИНКЕ

ST>мог бы выглядеть в нескольких вариантах:
ST> а) Типизированное выражение
ST>
ST>update c in collection set new { Id = c.Id, Name = c.ItemName} where c.Id == 12
ST>

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

Непонятно, если есть контекст. Если же выкинуть контекст не после операции, а вообще, то всё становится понятно и логично.
Если нам не помогут, то мы тоже никого не пощадим.
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 — проверка агрументов и параметров окружения.
Re[20]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 10:42
Оценка: 1 (1)
Здравствуйте, Tissot, Вы писали:

T>Классы customer, customercotainer, location, department, person

T>Помогло?
А чему в предметной области соответствует customercontainer?
Вообще, как правило структура данных не совпадает с устройством предметной области. Она иногда на неё похожа, но это иллюзорное сходство.
Простейший пример — есть список кастомеров. Надо понимать, во-первых, что элементами списка являются не кастомеры, а записи о кастомерах.
Во-вторых, что сам список кастомеров в "предметной области" может быть организован, к примеру, в виде Post-it бумажек, наклеенных на whiteboard.
И в этой "предметной области" есть куча придуманных правил, например "VIP расположены в верхнем левом углу", или "если есть конфликт заказов, то выигрывает тот, который расположен выше на доске".
Моделирование самой доски с листочками в программе может дать корректный результат, а может — и некорректный.
При этом в entity "customer" появятся какие-то атрибуты, которые не имеют никакого отношения ни к реальным покупателям, ни к доске, ни к бумажкам.
Этакие "артефакты модели". Задача "максимально приблизиться к предметной области" звучит хорошо, но работает плохо. Мне больше нравится задача "придумать максимально простую модель предметной области, которая покрывает максимальное количество пользовательских сценариев".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
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[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[12]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 06.01.09 12:39
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>За надом (понимать буквально)

То есть, очень хочется, но объяснить не можешь? )

T> Зачем отказываться от этого в domain model я не понимаю.

Потому что там это не нужно и даже вредно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[4]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 06.01.09 12:39
Оценка: +1
Здравствуйте, Tissot, Вы писали:

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

Я тебе больше скажу, SQL вообще мало отношения к реляционной алгебре имеет. Только работают все с SQL-ем, а не с реляцонной алгеброй в вакууме.
Ты что сказать-то хотел?

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

T>1) ER vs ObjectModel: мой выбор однозначно в пользу ObjectModel. Потому что она банально предоставляет больше возможностей.
Если бы это было так, то весь мир уже давно бы сидел на ООБД. Правда заключается в том, что большинство возможностей ОО подхода при работе с данными оказываются либо бесполезными, либо вообще вредными.

T> Кроме того, er может быть смоделирована через object model, обратное — неверно.

Приведи мне пример объектов, которые нельзя было бы смоделировать, через ER?

T>2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее.

Это в каких, например?

T> Единственный его недостаток — это когда нужно массово обновить большое количество объектов.

Если под "массово обновить большое количество объектов" понимается, что объектов больше одного, то согласен.
Проблема только в том, что таких случаев в реальной жизни подавляющее большинство, отсюда делаем совершенно закономерный вывод, что UoW конструкция бесполезная.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[8]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 06.01.09 12:39
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>В случае, если действуем по вашему сценарию — сразу получаем exclusive и удерживаем ее на время операции.

Это с какого перепуга?

T>И какой вариант после этого более легковесный?

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

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

Потому что ему доступна вся транзакция и он может ее оптимизировать так как ему удобно.

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

В том-то и дело, что теоретически этот update можно поддерживать легко и непринужденно, если делать это так же, как LINQ позволяет обращаться с select-ом.

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

Это твой основной аргумент? )

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

Бизнес-транзакция тут непричем. Бизнес-транзакция и транзакция БД — вещи совершенно разные и декларативный подход, при работе с данными дает гораздо больший контроль и над тем что происходит в бизнес-транзакциях и над тем, что происходит в БД.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[10]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.01.09 18:13
Оценка: +1
Здравствуйте, Tissot, Вы писали:


T>>>В варианте с UoW на время операции будет наложена shared блокировка и только на время submit-а — более тяжелая exclusive.

S>>А ничего, что в случае отката транзакции значение поля А, прочитанное кем-то во время "удержания shared блокировки", будет потеряно?

T>Я не совсем интонацию понял. Для меня вопрос звучит столь же нелепо, как и спрашивать — "а ничего, что при откате транзакции изменения потеряются".

Дело не в интонации. см. ниже.
S>>Если ничего, то можно разбить транзакцию на две, и не удерживать эксклюзивную блокировку во время тяжелых вычислений.
T>Нельзя, целостность будет потеряна.

T>Не улавливаю ход рассуждения, распиши подробнее.

Поясняю еще раз: в промежутке между первым апдейтом и вторым может вклиниться чтение из посторонней транзакции. Удержание эксклюзивной блокировки гарантирует отсутствие этого вклиненного чтение. Предлагаемый тобой вариант с наложением shared lock чреват фантомным чтением. Ты сам только что сказал, что нарушение целостности недопустимо. ЧТД.

T>Задание на дом. Перечитай свое же сообщение еще раз.

А вот хамить не надо.

T>Вручную педалить тяжело если вы остаетесь в рамках trabsaction script-а. Переходите на ооп подход и волосы становятся густыми и блестящими

ООП подход нужно применять с умом. Речь не о transaction script, а о современных техниках подготовки запросов.

T>Пока у них это не очень хорошо получается. Те средства декомпозиции запросов, что есть в SQL-е и в базах данных (WITH, view, функции) просто смешны и не выдерживают никакой критики.

Я еще раз напомню, что речь идет как раз о более современных средствах декомпозиции запроса, чем with. К тому же вы зря так пренебрежительно относитесь к view и функциям — они могут серьезно помочь, если их правильно готовить.

T>Как бороться со ложностью? Как это тестировать? и так далее.

Еще раз поясняю: единственный способ бороться со сложностью, придуманный прогрессивным человечеством — это декомпозиция. Да, возможности по декомпозиции, заложенные в SQL, не слишком мощны. Но вот Linq предлагает более совершенные средства, на которые я кратко намекнул.

T>ООП дает на эти вопросы более менее внятный ответ.

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

T>Не пойму, что тебе запрещает использовать танзакции-то? И полчишь "целостность, которая доступна в старинном SQL забесплатно".

Поясняю на пальцах: понятие транзакционной целостности, в частности включает в себя отслеживание того факта, что прочитанные в начале транзакции данные остаются актуальными и в ее конце. В частности, если я делаю модификацию позиций заказа, я должен вначале проверить, что сам заказ еще не отгружен. SQL достигает этого путем наложения блокировок даже при выполнении селект стейтмента. Unit of Work никак не отслеживает чтения, сделанные в процессе выполнения транзакции.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 23:10
Оценка: :)
Здравствуйте, VGn, Вы писали:

VGn>Всё зависит от логики валидации.

VGn>Если валидируется формат, то это можно сделать и на уровне отображения.
VGn>Если логическая нестыковка — то в бизнес-логике.
VGn>Если конфликт с существующими данными или конфликт транзакций, то только на базе.
VGn>Причём имхо это всё не жёсткие условия. Всё зависит от архитектуры системы.

Вопрос был не к тебе. По его словам проверка объектов должна быть в двух местах — PL + база.
Я как раз пытаюсь вытянуть его на то, что проверки в бизнесе все-таки нужны.
Re[10]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 07.01.09 05:38
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Потому что update

Если это один update, то там не может быть никаких длинных вычислений.

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

А ты чем занимаешься? Просто в эту игру можно играть в обе стороны

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

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

T>Ключевое слово выделено. А на практике?

А на практике этого еще не сделано, о чем и писал Влад.

T>А как еще назвать ситуацию, когда в качестве аргумента приводят код, который в жизни практически не встречается?

Задача стояла не показать тебе реальный код, а проиллюстрировать идею.

T>Приведенный код был слишком простым, чтобы на его примере увидить недостатки подхода "делаем все одним update-ом". Де-факто этот единственный update потребует как минимум проверку валидности, проверку безопасности, аудит действий и т.д. Если бы все эти сервисные операции были включены в пример, то его красота сразу бы куда-то улетучилась.

В том-то и дело, что не улетучилась бы, если использовать подход LINQ, в чем и был поинт оригинального сообщения.

T>Очень интересный тезис, но позволь в него не поверить.

Да байта ради.

T> Ну или по-крайней мере объясни откуда возьмется этот больший контроль.

Оттуда, что все делается явно, без Lazy Loading-ов, неявных кешей, траверсивных запросов и прочих ритуальных приседаний.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[8]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 07.01.09 05:38
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Я довольно регулярно слежу за тенденциями в этой сфере. И мне как-то последние годов несколько очень редко попадаются апологеты подхода "запихнем все в базу". Все больше как-то говорят за полноценную domain model.

"запихнем все в базу" и domain model — это ортогональные вещи, так что довольно странно слышать подобные заявления от человека, который "регулярно следит за тенденциями в этой сфере".

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

Да-да, мыши плакали, кололись, но продолжали жрать кактус.

T>В сухом остатке получаем, что подход с domain model более "проработан" чем иные.

T>Это тоже будешь считать более хлипким аргументом?
Безусловно, так как народ уже начинает понимать, какой это фуфел. Апофигеем того, что ты понимаешь под domain model был EJB, который, пользуясь твоим любимым аргументом, де-факто, считается провальным.

T>Не мог бы ты оставаясь в рамках этого примера описать, откуда возникнет "меньшее время" и "больший контроль"?

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

T>Что тебя так развеселило? Расскажи, вместе посмеемся.

Дешевые понты всегдя выглядят забавно.. )
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[12]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 07.01.09 13:59
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Я не меняю условия задачи.

Меняешь.

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

Вполне. Но во-первых это совсем не означает, что будет именно одна БД транзакция, а во-вторых никто не заставляет делать между этими изменениями тяжелые вычисления.

T>Не, так легко ты не отделаешься. Учебников мною прочитано предостаточно, но информации о том, чтобы СУБД отпускала блокировки до окончания танзакции, я слышу в первый раз.

Значит фигово читал. Это умеют делать все СУБД, в зависимости от уровня изоляции, а например MSSQL умеет вообще не накладывать блокировки при выполнении стейтмента в RC — оптимизация такая.
Вообще современные СУБД довольно продвинутые конструкции и наивно было бы полагать, что ты сумеешь справиться лучше.

T>Ну идея сама по себе была ясна и из первого поста

Складывается впечатление, что не очень.. )

T>Используйте ef

Что мне это даст, кроме возни с тремя моделями, вместо одной?

T>Кэш неявный только когда ты о нем не знаешь.

Тогда, когда у меня нет над ним явного контроля.

T>Изучайте получше инструмент, которым пользуетесь.

А я и не пользуюсь.. Я пользуюсь теми инструментами, которые делают то что надо мне.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 00:05
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>>>CR делает эти операции зависимыми, тогда сначала выполняется запрос (ниче не поделаешь, пользователю придется ждать), а потом сохранение данных.

T>>Даже если склад пустой? Чего упаковывать-то?
G>Если склад пустой, то оператор не сможет выбрать позиции для резервирования, транзакция не пойдет.

Резервируют не позиции, а заказ.
Re[12]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.01.09 06:08
Оценка: +1
Здравствуйте, Tissot, Вы писали:
T>CR (через полгода):
T>При резервировании заказа заказ должен сохранять в одном из полей номер запроса на упаковку (номер возвращается веб-сервисом).
Худший способ решения этой задачи — реализация данной бизнес-транзакции в виде одной транзакции уровня СУБД.
И худший он именно из-за того, что быстрое звено (СУБД) вынуждено удерживать блокировки до тех пор, пока медленное звено (веб-сервис) не проснется и не ответит.
Более того, в предлагаемой схеме временная проблема с веб-сервисом (банальное падение роутера между ним и application tier) иожет привести к откату транзакции резервирования товара. Так делать не надо.

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

А теперь расскажи нам, как это работает в случае unit of work. Какие блокировки накладываются в какой момент, и в какой они отпускаются. Учти еще, что характерное время ответа от веб-сервиса — это 200мс, а одиночный апдейт в базе выполнится примерно за 10мс.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 08.01.09 13:43
Оценка: -1
Здравствуйте, Tissot, Вы писали:

T>Можно подкрепить высказывание ссылочкой? Спасибо.

BOL =)

T> ORMapper в конечном итоге говорит и сервером на SQL, а значит все средства остаются в силе.

Классические ORM делают это настолько криво, что плохо становится и сиквелу и разработчику, так как по факту, ничего в силе не остается.

T>Отсутствие ленивой загрузки.

Угу, купи козу — продай козу. А что с остальными косяками делать?

T>Над чем у тебя нет явного контроля в том же LINQ2SQL-е. Он же тупой как пробка.

В этом его и прелесть. Если ты не понял, то L2S — это шаг в правильном направлении, но хочется большего, в этом и был поинт.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[12]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 08.01.09 13:43
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Ку так расскажи, а то все вокруг, да около. Или тоже секретная разработка?

"Лень фаулера цитировать" (с)

T>См. Фаулера, а лучше Evans-а.

Ну вот и смотри лучше в фаулера, даже у него domain model — лишь один из вариантов дизайна, и даже он не настаивает на его универсализме.

T>Ну если другие подходы не выдерживают критики, то приходится ограничиваться "серебрянной пулей"

Так где критика-то? Хотя в принципе, достаточно того, что некоторые другие подходы отлично выдерживают практику.

T>Я так не считаю.

Ну это сугубо твои проблемы.. Де-факто (с), его подавали именно под этим соусом.

T>А это вообще не суть важно. При использовании TransactionScope ты хоть каждый чих оборачивай в транзакцию. Коммит в базу все равно будет только после последнего самомго внешнего TransactionScope-а.

Да, представляю транзакции после такого получаются.. =) Самому не смешно? )
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[8]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 08.01.09 13:43
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>По поводу третьего — думаю, если взять общее число тех, кто знает о hibernte-е (или других мапперах) и имеет возможность его использовать, большинство его использует.

Думаю, что ты ошибаешься.. )

T>Наследование само по себе (без наличия виртуальных методов) ценности не несет.

Во-первых, несет, во-вторых, какие вообще методы ты хочешь видеть в данных и, наконец, в третих, оно таки отлично выражается в ER, что и требовалось доказать.

T>Многие-ко-многим выражается через два отношения один-ко-многим.

Тем не менее выражается.

T>С этим элементарно неудобно работать

Никаких фатальных неудобств с этим нет, а иногда это вообще оборачивается преимуществом.

T>Зато имеет к ООП.

Однако здесь речь идет не об ООП, а об ООП при работе с данными. И в применении к данным, методы и интерфейсы являются большой проблемой.
Дело в том, что срок жизни данных — сильно больше срока жизни типичного ООП-шного объекта, реализующего конкретное поведение в определенном сценарии. Более того, одни и те же данные хорошо бы использовать в разных объектах, но как только к данным прибивается гвоздями определенное поведение и структура с помощью методов и интерфейсов, эта возможность тут же теряется.
Именно по этому, навязать данным методы — дурная затея. Во-первых, меняя в десятый раз поведение данные нужно оставлять неизменными. Во-вторых, добавляя новое поведение, надо его просто добавлять, а не менять старое и не накручивать поверх старого, при этом стараясь оставить данные по прежнему неизменными.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[10]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 14:43
Оценка: +1
Здравствуйте, Tissot, Вы писали:

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


T>>>Наследование само по себе (без наличия виртуальных методов) ценности не несет.

IB>>Во-первых, несет, во-вторых,
T>Кукую?
Полиморфизм достигается не только вирткальными методами в классе.

IB>>какие вообще методы ты хочешь видеть в данных

T>Например, методы валидации. Или user-friendly ToString.
Валидация в entity-объектах? Ну это совсем моветон.

T>Пример можно показать, без абстрактных пассов руками в воздухе. По мне так чем объектная модель программы ближе к оной предметной области, тем лучше — проще понимать такой код.

Методы в классах сущностей это ближе к предметной области?
Re[12]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 15:54
Оценка: +1
Здравствуйте, Tissot, Вы писали:

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


T>>>>>Наследование само по себе (без наличия виртуальных методов) ценности не несет.

IB>>>>Во-первых, несет, во-вторых,
T>>>Кукую?
G>>Полиморфизм достигается не только вирткальными методами в классе.
T>Ну интерфейсы еще есть, конечно, но они тоже не являются частью er-модели.
Вам наверное стоит разобраться что такое полиморфизм.

T>>>Например, методы валидации. Или user-friendly ToString.

G>>Валидация в entity-объектах? Ну это совсем моветон.

T>Сама реализация валидации может быть расположена и где-то вовне класса, а класс может просто делегировать вызов. Очень удобно, например на SubmitChanges проверять таким образом валидность измененных сущностей.

Да уж... Валидацию сущностей надо задавать декларативно — атрибутами или во внешних конфигах. Смотрите Validation Application Block из enterprise library.

T>>>Пример можно показать, без абстрактных пассов руками в воздухе. По мне так чем объектная модель программы ближе к оной предметной области, тем лучше — проще понимать такой код.

G>>Методы в классах сущностей это ближе к предметной области?
T>Ну да.
С чего это?
Кроме того такие решения обычно нарушают SRP, а преимуществ от них маловато, даже понимаемость кода страдает в таких условиях, за исключением самых простых случаев.
Re[10]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 08.01.09 18:17
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Кукую?

Про полиморфизм тебе уже рассказали.

T>Например, методы валидации. Или user-friendly ToString.

Ужас какой.

T>Те способы выражения что я знаю, не очень-то приятные для использования.

Во-первых вопрос был не про приятности использования, а про сам факт выражения, а во-вторых, надо уметь готовить

T>Ну это как посмотреть. Кому-то может быть и удобно, мне — не очень.

Ну так это твои личные проблемы.

T>Пример можно показать, без абстрактных пассов руками в воздухе. По мне так чем объектная модель программы ближе к оной предметной области, тем лучше — проще понимать такой код.

Уже трижды говорилось, речь не про объектную модель, а про данные. Data != Object — это то, с чего начинаются все white papers про LINQ и это очень правильно.
Далее, ER на практике, оказывается гораздо ближе к предметной области чем модель данных.

T>По поводу неизменности данных я полностью согласен. А вот по поводу "добавлять, а не менять" — не совсем. Если требования поменялись, то код должен быть тоже поменян, зачем хранить в приложении тот код, который уже не актуален? Не понимаю.

И еще раз. Не код, а данные. Код должен быть поменян, а данные — нет.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[20]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 08.01.09 18:17
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Если идеи, то какая разница, кем она высказана?

Так где идея-то? Ты ее так и не высказал. А фаулер много чего наговорил, как весьма толкового, так и не очень. И очень уж у неофитов на его почве крышу рвет.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 22:03
Оценка: -1
Здравствуйте, IB, Вы писали:

T>>А я цитат и не прошу. Ссылочки будет вполне достаточно.

IB>Ну, считай, что я сослался на фаулера.

У меня есть эта книжка. Не мог бы ты назвать раздел в котором говорится об этом? Спасибо

T>>Очень даже настаивает, когда говорит о сложных приложениях.

IB>Цитату можно? А заодно определение сложных приложений.

Стр. 52. О том, что я не буду переписывать Фаулера, я уже писал.
Понятие сложности — вопрос сугубо субъективный, никто тебе формулы для вычисления сложности не даст, придется с этим смириться.

T>>Ладно, проехали. Нет никакой критики. Вы абсолютно правы.

IB>Ну, а что тогда вообще споришь? Просто потрепаться захотелось? )

По поводу перехода на личности я уже писал. См. выше по ветке.

T>>Нет, ничуть не смешно.

IB>Напрасно...

T>> Вложеные TransactionScope-ы реюзают в конечном итоге одну транзакцию, так что множественное число тут не очень уместно.

IB>То есть, больше одной транзакции не бывает?

Бывают. Вы можете открыть TransactionScope с опцией RequiresNew. Если вас все еще интересует как работает этот класс, посмотрите вот тут: http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx
Re[24]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 09:32
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>А почему в entity мне должно быть это итересно? она сама по себе сохранением-то и не занимается.

T>Почему ради того, чтобы следовать SRP я должен выставлять все члены наружу?
Ты слишком много думаешь об entity.

В нормальной системе entity моделируют нижележащие данные, которые и есть предметная область. То, что сами эти данные в свою очередь являются моделью чего-то еще, в этот момент несущественно.

У данных есть только одна обязанность — "быть". Способ сохранения данных ортогонален самим данным. То, что атрибут "зарплата" не может быть меньше нуля — ортогонально структуре "карточка сотрудника". Алгоритм капитализации ФИО ортогонален структуре "Карточка сотрудника".

Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.

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

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

T>Зато поднимают настроение

Заранее намекаю: злоупотребление некошерными методами подъема настроения на этом форуме чревато воспитательными мерами.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 10:51
Оценка: -1
Здравствуйте, IB, Вы писали:

T>>А это наверное ваша жена написала в ваше отсутствие?

T>>

T>>Во-вторых, добавляя новое поведение, надо его просто добавлять, а не менять старое

IB>А это тут причем? При изменении требований новое поведение должно добавляться без изменения старого, это для тебя новость?

Код должен быть поменян, а данные — нет.
(с) IB

Re[27]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:41
Оценка: -1
Здравствуйте, gandjustas, Вы писали:

T>>Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

G>Определитесь с терминологией. С точки зрения ER-моделирования есть сущности, которые группирую данные, у сущностей есть атрибуты — сами данные, сущности могут быть свзяаны между собой. Перенеся все это на ООП получаются классы и свойства, атрибуты сущностей — простые свойства, связи могут быть выражены сложными свойствами. Ортогональность валидации и способу хранения остается.
G>Может под "сущностью" вы имеете ввиду "объекты предметной области по фаулеру"?

Да, ты прав. Имелось в виду сущность из domain model.

S>>>Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.

T>>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.
G>Причем тут хранилище? Сущности ортогональны хранилищу.

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

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

G>Эти "инварианты" ортогональны сущности, поскольку могут меняться со временем.

Нет, не ортогональны. Инвариант не должно быть разрешено нарушать. Если вы оставляете все поля сущности открытыми, вы не сожете гарантировать сохранность инватиантов.
Re[24]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 11:46
Оценка: +1
Здравствуйте, Tissot, Вы писали:

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


T>>>Ну тогда еще проще — уменьшаем кол-во проходов цикла до минимума и комплексити падает.

G>>Ну покажите на вашем примере с кучей ифов как вы уменьшите Cyclomatic Complexity за счет таблицы.

T>Вот пример:

T>
T>код поскипан
T>


T>Померьте комплексити в таком коде, потом раскомментите первую строчку и померьте еще раз. Мне студия насчитала 9 и 13 соответственно.

В таком коде действительно сложность уменьшилась. Причем как формальный показатель CyclomaticComplexity, так и фактическая сложность чтения\сопровождения\расширения.

А если к вашему коду применить ООП, заменить enum классами (рефакторинг по фаулеру), то станет еще лучше.
Если писать хороший код, то таких примеров и возникать не будет.

Но вы вначала привели другой:
if (condition1())
  action1();
else if (condition2())
  action2();
...
else if (conditionN())
  actionN();

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

Вот если у вас предикат одинаковый, а параметры разные, то это можно свести к таблице или паттернам состояние\стратегия.
Re[24]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 11:51
Оценка: +1
Здравствуйте, Tissot, Вы писали:

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


T>>>Не, получилась вполне себе rich domain model

G>>И чем же она Rich?

G>>например location, чтобы быть локейшеном надо какие-то данные о местоположении содержать, этодо достаточно. Вполне себе ER-модель (сущность и атрибуты).


T>ER-содель — это когда только сущность и атрибуты. Появляются методы, она уже перестает быть ER.

По каким причинам они могут там появиться не нарушая SRP и другие принципы хорошего дизайна?

Например какие методы могут появиться у location, ну кроме переопределения Equals и ToString?
Re[28]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:17
Оценка: +1
Здравствуйте, Tissot, Вы писали:

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


T>>>Я не считаю, что сложность уменьшилась. Меньшее кол-во строчек еще не показатель.

G>>Еще как уменьшилась.
G>>1)Структурированность кода стала выше, в сами ифы стало невозможно дописывать
G>>2)Из-за сокращения объема кода он стал нашляднее, проще читать, следовательно меньше ошибок будет допущено, быстрее они будут выявлены.
G>>3)Стало невозможно допустить ошибку недописывания else перед новым if при добавлении условия

T>Но не забывай, что все это путем усложнения сруктуры класса — разные action-ы пришлось вынести в отдельные методы.

Это разве плохо? Обычно считается что разные методы (особенно небольшие) — это замечательно.

G>>Кроме того появилась дополнительная гибкость — появилась возможность формировать таблицу действий в run-time.

T>А оно надо?
А кто знает, может и надо. Любой код стоит рассматривать с точки зрения дальнейшиго расширения.

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

G>>Вы доказали что качество кода состоит не только из CyclomaticComplexity, а из многих составляющих. Но это и так известно.

T>Я показал, что один из коэффициентов, входящий MaintainabilyIndex вполне может быть обманут. А следовательно и сам index под подозрением.

Чем обманут? в приведенных примерах CyclomaticComplexity снижался, но снижения одного мараметра в маленьком куске кода на сложность проекта вообще не влияет. MaintainabilyIndex работает для больших кусков. Я об этом писал.

G>>>>Вот если у вас предикат одинаковый, а параметры разные, то это можно свести к таблице или паттернам состояние\стратегия.

T>>>И ты считаешь, что это проще? Вместе нескольких if-ов генерить интерфес стратегии + классы реализующие интерфейс.
G>>Если это код, подверженный частым изменениям, то проще. Иначе можно ограничиться таблицей.

T>Кому как, а по-моему это явный overdesign — когда простой if заменяется на непойми что.

Любой код стоит рассматривать с точки зрения дальнейшиго расширения.
А вы только АКПП Фаулера читали? Еще Рефакторинг почитайте, там один из первых примеров как раз такой.
Re[36]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 15:00
Оценка: +1
Здравствуйте, Tissot, Вы писали:

G>>>>Еще одна ситуация: когда кастомер в процессе создания и еще не имеет ссылки на сущность со страной, как валидировать его zipCode?

T>>>Я не знаю, зависит от бизнес-логики.
G>>Это как раз вопрос дизайна. На форуме "архитектура" было такое обсуждение. Варианты — плодить builder или data object. Но тогда возникает смысловое дублирование.

T>У нас у таких сущностей есть состояние Draft. В этом состоянии проверки не делаются, т.е. фактически она работает как data object. После завершения инициализации сущность переходит в состояние Ready (с валидацией). Переход обратно невозможен.


Моя плакать...
У меня для таких случаев ничего дополнительно делать не надо
Re[47]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 17:25
Оценка: -1
Здравствуйте, gandjustas, Вы писали:

T>>Зачем каждый раз? Ты же говорил, что у тебя ленивая загрузка.

G>Ленивая или нет, все равно надо каждый раз лезть в базу чтобы обеспечитьвалидность сущности. Работать будет очень медленно.

А чем же тогда ленивость?

T>>А нефик биндить сущности на контролы. А то тут скатиться до дельфевого подхода недалеко.

G>DataBinding плохой подход для UI?

Нет, DataBinding прямиком на сущности — плохой прием.
Re[32]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.01.09 08:30
Оценка: +1
Здравствуйте, Tissot, Вы писали:


T>Откуда CustomerManager и как он может помешать изменить Customer-а напрямую?

Как откуда? Это и есть класс, в котором сосредоточены методы управления кастомерами.
Помешать он сам конечно не может, в том смысле, что у админа-злодея всегда есть шанс полезть в базу напрямую.
А вот запретить из прикладного кода вызовы апдейт-стейтментов можно в том числе и при помощи FxCop.
Это если не хватает культуры программирования.
Нужно просто отделить случайные ошибки от преднамеренных действий.

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


T>Ну это скорее аргумент в пользу изменени логики валидации — она должна запускаться только при определенном статусе заказа.

Это приведет к тому, что в приложении вообще не будет повторно используемого кода. Потому что в логику валидации зашито слишком много подробностей про окружение. А всего-то надо было применить регекс в нужный момент.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[24]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 10.01.09 10:01
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Мне кажется, я уже упоминал, что обсуждается не мнение (и уж тем более не их авторство), а идеи.

Тебе не кажется, что идеи было бы не плохо изложить, прежде чем обсуждать?

T>Отвечать на ваши сообщения я больше не намерен.

Аминь.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[30]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 12:13
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Есть бизнес. Есть анализ этого бизнеса. Есть программы, нацеленные на облегчение ведения бизнеса.

T>Так вот, DDD относится к третьему этапу. Основной постулат DDD — это что модель, используемая в программе должна максимально соответствовать результату анализа.
Результаты анализа обычно составляют:
1)Описания сущностей и свзязей — ER модель
2)Описания бизнес-правил — валидация модели
3)Описания бизнес-процессов — действия, которые производятся над моделью
4)Описание ролей — ограничение доступа к процессам и их частям

Как из этого получаются объекты с поведением?
Re[18]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 16:51
Оценка: :)
Здравствуйте, IB, Вы писали:

T>>Опять хамишь. Ты что, без этого совсем не можешь?

IB>А как ты ждешь, чтобы на твое хамство отвечали?

Ладно, прощай повторно. Надеюсь, на этот раз окончательно
Re[6]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.03.09 11:59
Оценка: +1
Здравствуйте, Jakobz, Вы писали:

VD>>Это будет резко отличаться от подхода с датаконтекстом и с большой вероятностью приведет к проблемам.


J>Ну вот и непонятно как в подходе с датаконтекстом обрабатывать запросы типа "delete * from Blabla". Я не представляю как такое может жить вместе со всяким identity tracking.


Дык, мне сам этот подход и не нравится. Датоконтекст должен пойти в топку.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.03.09 18:14
Оценка: +1
Здравствуйте, Jakobz, Вы писали:

J>Я в другой ветке писал про это. Что если у нас два одинаковых объекты и мы поменяем только один?


У тебя какие-то невероятные проблемы с пониманием не используемых тобой техник.

Попробуй вдумчиво прочесть мои слова. ОК?

При использовании update/insert/delete объекты вообще не меняются. Они просто ипользуются для временного хранения данных считанных из БД.

При этом никого не трогает вопрос синхронизации объектов. Актуальные данные есть только в БД и только после фиксации транзакции.

Короче — это подход при котором объекты ничто данные все.

Понятно?

При этом нет никаких идетити, хренньтити и т.п. Есть только данные и их разработка.

Это аналогично обработки данных хранимых в файле. Ты считываешь данные из файла, превращаешь (временно) в объекты, преобразуешь данные и записываешь их обратно. Да, ты можешь считать данные два раза и изменить только одну копию. Но это твои проблемы. Твоя стратегия.

J>Pessimistic — да, обеспечивает. На уровне одного соединения/транзакции. Как средствами СУБД обрабатывать классическую ситуацию: чувак открыл форму редактирования, ушел домой, а кому-то нужно что-то в ней этой же форме поправить?


Это зависит от стратегии программы.
1. Программа может просто перезаписать изменения.
2. Программа может при обновлении записей использовать в качестве ключа RowID (изменяемый в случае изменения записи) или просто все значимые данные строки. Тогда в случае если строка была изменена во время редактирования БД выдаст сообщение об ошибке (такая строка не существует).

Ты что с БД без OR-маперов вообще не работал никогда?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Некоторые мысли о LINQ
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 25.03.09 19:15
Оценка: +1
Здравствуйте, Jakobz, Вы писали:

J>А что ты понимаешь под базвордом "statefull-архитектура"?


Это не баззворд. Stateless архитектура, когда все объекты живут исключительно в течение вызова метода, не требует никаких танцев с конкарренси за пределами БД.
... << RSDN@Home 1.2.0 alpha 4 rev. 1138 on Windows Vista 6.1.7000.0>>
AVK Blog
Re[11]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 19:57
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

J>>Откуда их станет меньше? Почему я не могу успешно управлять ими в LINQ to SQL?

S>Из-за отсутсивия "копий", которые могут быть изменены независимо.

Тут одна вешь, которую ты упускаешь, уходя всё дальше от темы: в большинстве случаев "отсоединение" сущностей просто необходимо.

Да, если у тебя есть детерменированная операция, db = f(db) — ты можешь ее записать в одной транзакции, и это будет правильно. Тебе ничего не нужно "отсоединять", мэппить в объекты, select-ить из базы чтобы сделать update и заниматься прочей чепухой.

Но, если у нас есть пользователь или другой медленный, недетерменированный, ввод-вывод, ты никак не уйдешь от отсоединенной модели с optimistic concurrency. Тебе нужно будет отсоединить данные от базы, хотя бы чтобы положить их в input на веб-форме. Те данные, которые на форме, уже будут копией информации из базы, без какой-либо гарантии актуальности.

Мы приходим к тому, что нужно эти данные как-то передать на эту форму и работать с ними из кода. Мы сейчас говорим о ООП-языке C#, где для хранения данных принято использовать объекты. Поэтому логично как посредника для передачи данных из БД использовать именно эти самые объекты. Причем и при получении из базы и при засовывании их назад. Можно применять и другие временные хранилища, например датасеты. Но, как показывает практика, в C# это неудобно. Хотя я не исключаю, что может быть и хорошая, удобная реализация такой концепции. У обычных объектов есть свои минусы, да, но с ними как правило удобнее.

И вот — с объектами есть проблемы, см. object-relation impedance mismatch. Но делать-то, в общем-то, с этим особо нечего. Варианты "перейти на другой язык" или "написать свои мегадатасеты" не будем рассматривать здесь, пожалуйста.

А потом полученые от того же пользователя данные нужно положить назад в базу. Логично юзать тот же формат данных, в каком эти данные были получены. И при засовывании нужно проверить — а не обновил ли кто эти данные до нас? Можно этого и не делать, но это не по-феншую, а зачастую этого требуют явно.

И вот именно эти задачи решает Linq to sql. Замечу — это не какой-то волшебный инструмент, который принес реляционную алгебру в ООП (как мне показалось именно этого хотел от него VladD2). Отнюдь, это не так. Linq to sql — это инструмент для решения описаных выше задач. И нужно учесть, что это — инструмент для работы именно с отсоединенной моделью.

Еще в Linq to sql есть DataContext, с которого начался спор. Эта штука частично решает/упрощает некоторые задачи и, в общем, могла бы "быть попроще". Но, на мой взгляд, сильного оверхеда она не приносит, а удобства у нее есть. Например, она сглаживает проблему с identity. И сама запоминает какие объекты менялись, чтобы потом нам не вспоминать что апдейтить. Я не вижу в этих удобствах ничего плохого. В любом случае от этих удобств никто не запрещает отказываться — на то ReadOnly и прочии фичи.

Почему я тут так подробно это расписываю? Потому что разговор ушел куда-то в полный астрал. Мы уже, вон, до Хаскеля дошли. Непонятно где Немерле только отстало
Re[12]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.09 20:17
Оценка: +1
Здравствуйте, Jakobz, Вы писали:

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


J>>>Откуда их станет меньше? Почему я не могу успешно управлять ими в LINQ to SQL?

S>>Из-за отсутсивия "копий", которые могут быть изменены независимо.

J>Тут одна вешь, которую ты упускаешь, уходя всё дальше от темы: в большинстве случаев "отсоединение" сущностей просто необходимо.

Там где необходимо "отсоединение" там контексты Linq2SQL, EF, сессии NHibernate тоже не справляются и надо "отсоедиенный" набор данных поддерживать руками.

J>Но, если у нас есть пользователь или другой медленный, недетерменированный, ввод-вывод, ты никак не уйдешь от отсоединенной модели с optimistic concurrency. Тебе нужно будет отсоединить данные от базы, хотя бы чтобы положить их в input на веб-форме. Те данные, которые на форме, уже будут копией информации из базы, без какой-либо гарантии актуальности.

В одном запросе мы считали из базы объекты, сгенерировали по ним форму. В следующем запросе получили данные с формы и выполнили запрос на изменение данных в БД.
Зачем здесь identity\change tracking контекста? Он хоть каким-то боком помогает?

J>И вот — с объектами есть проблемы, см. object-relation impedance mismatch. Но делать-то, в общем-то, с этим особо нечего. Варианты "перейти на другой язык" или "написать свои мегадатасеты" не будем рассматривать здесь, пожалуйста.

А это все и не поможет. Чем дальше разработчики пытаются уйти от работы с данными, тем больше проблем получается.
Большенство паттернов применяемых для работы с данными — это костыли.

J>А потом полученые от того же пользователя данные нужно положить назад в базу. Логично юзать тот же формат данных, в каком эти данные были получены. И при засовывании нужно проверить — а не обновил ли кто эти данные до нас? Можно этого и не делать, но это не по-феншую, а зачастую этого требуют явно.

И снова вопрос, чем нам identity\change tracking помогает в этом?

J>И вот именно эти задачи решает Linq to sql. Замечу — это не какой-то волшебный инструмент, который принес реляционную алгебру в ООП (как мне показалось именно этого хотел от него VladD2). Отнюдь, это не так. Linq to sql — это инструмент для решения описаных выше задач. И нужно учесть, что это — инструмент для работы именно с отсоединенной моделью.

Да ну? Напишите мне Linq2SQL запрос, который к БД не обращается.

J>Еще в Linq to sql есть DataContext, с которого начался спор. Эта штука частично решает/упрощает некоторые задачи и, в общем, могла бы "быть попроще". Но, на мой взгляд, сильного оверхеда она не приносит, а удобства у нее есть. Например, она сглаживает проблему с identity. И сама запоминает какие объекты менялись, чтобы потом нам не вспоминать что апдейтить. Я не вижу в этих удобствах ничего плохого. В любом случае от этих удобств никто не запрещает отказываться — на то ReadOnly и прочии фичи.

проблем с identity не будет если отказаться от идеи получать объекты, потом их изменять и записывать в том же контексте.
Re[12]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 20:44
Оценка: +1
Здравствуйте, Jakobz, Вы писали:

J>Тут одна вешь, которую ты упускаешь, уходя всё дальше от темы: в большинстве случаев "отсоединение" сущностей просто необходимо.


J>Да, если у тебя есть детерменированная операция, db = f(db) — ты можешь ее записать в одной транзакции, и это будет правильно. Тебе ничего не нужно "отсоединять", мэппить в объекты, select-ить из базы чтобы сделать update и заниматься прочей чепухой.


J>Но, если у нас есть пользователь или другой медленный, недетерменированный, ввод-вывод, ты никак не уйдешь от отсоединенной модели с optimistic concurrency. Тебе нужно будет отсоединить данные от базы, хотя бы чтобы положить их в input на веб-форме. Те данные, которые на форме, уже будут копией информации из базы, без какой-либо гарантии актуальности.

Воот. Я-то как раз ничего не упускаю. Сама по себе идея "положить данные в input" подразумевает, что ты управляешь конечным состоянием, а не действием.
Понимаешь? Действия — stateless.
А ты упускаешь то, что этих случаев — совсем не "большинство".
Возьми, к примеру, кассовый терминал. Там инпуты совершенно не содержат никакие "данные", которые нужно откуда-то отсоединять.
С другой стороны в ту же базу смотрит сотня разнообразных отчетов. И там объектам делать нечего — ты устанешь конструировать классы для этих объектов. Анонимные типы как-то спасают, ровно до тех пор, пока не появляются "пользовательские" отчеты, и как раз тут на передний план выбегают датасеты со своей хреновой типизацией.

Понятно, что это — крайний случай, база с "одной большой таблицей".
Но и во многих других интересных случаях то, о чем ты говоришь — это редактирование справочников. Пусть юз-кейзов про них будет 95, а юз-кейзов с "интересным" наполнением — всего пять.
Интересными я здесь называю всякие штуки типа "найти подходящие объекты, и нужным способом их согласованно изменить". Классический пример — резервирование товара на складах, с минимизацией холостого пробега машины доставки. Или там выбор подходящей комнаты для митинга и резервирование оборудования, связанного с ней. Или еще что-нибудь такое, где тебе сильно хочется применить change tracking. Во всех этих случаях лучше ничего ниоткуда не отсоединять — потому что обратное присоедининить трудно.

J>И вот — с объектами есть проблемы, см. object-relation impedance mismatch.

Этот мисмэтч происходит из-за того, что "не ту страну назвали гондурасом". Точнее, кто-то с какого-то перепугу решил сопоставить объекты отдельным записям в таблицах.
И вот тут-то всё и началось. Дело в том, что строки таблиц не ведут себя как объекты. Как объекты себя ведут реляции.
Вот как только ты начинаешь об этом задумываться, весь мисмэтч исчезает на глазах.
Вот у тебя есть объект Customers. Не Сustomer, а Customers.
Есть операция Where, которая может вернуть тебе объект CustomersWithNameVasya, который того же типа, что и Customers.
А есть операция Select, которая может вернуть тебе CustomersFirstName, который того же типа, что и Strings.
И так далее.

J>Но делать-то, в общем-то, с этим особо нечего.

Да-да-да. До изобретения Linq именно так и считалось. Что ничего интересного тут сделать нельзя, поэтому давайте ваши датасеты, и поехали.
Однако вопросы с select, where, order by, group by в общем-то решили положительно.

Но вот тут у парней появился выбор:
1. Трактовать результаты Linq-выражений в стиле сиквела: неизменяемыми "слепками", снятыми с настоящих данных.
2. Разрешить программистам думать, что результат запроса — это не один объект, а набор полноценных объектов с изменямым состоянием.
Первый путь потребовал бы ввести поддержку модификаций в том же SQL стиле (чего очень хочется мне, Владу, и еще нескольким отморозкам-любителям).
Второй путь потребовал бы ввести поддержку change tracking, identity map и прочей ерунды.
Выбрали второй. Но не нужно думать, что он такой единственный.

J>И вот именно эти задачи решает Linq to sql. Замечу — это не какой-то волшебный инструмент, который принес реляционную алгебру в ООП (как мне показалось именно этого хотел от него VladD2). Отнюдь, это не так. Linq to sql — это инструмент для решения описаных выше задач. И нужно учесть, что это — инструмент для работы именно с отсоединенной моделью.

Мы прекрасно понимаем, что такое Linq, как устроен Linq2Sql, и почему он так устроен. Мы просто с этим не согласны.
Я тебя понимаю — я еще в долинковские времена наприседался с ORM, и самописанными в том числе, и все их прелести прекрасно осознаю. Linq — это шаг в правильную сторону, вот только надо бы шагнуть и второй ногой тоже. А то между ними как раз зависла суровая действительность, где вся мощь функциональной декомпозиции притянута вниз гирей two-way binding.

J>Почему я тут так подробно это расписываю? Потому что разговор ушел куда-то в полный астрал. Мы уже, вон, до Хаскеля дошли. Непонятно где Немерле только отстало
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 21:01
Оценка: +1
Здравствуйте, Jakobz, Вы писали:
J>Просто ты упускаешь следующие моменты:
J>- сложные сценарии обработки данных сложно писать на SQL. Если бы это было не так — писали бы всю логику на хранимках и не парились бы.
Я ничего не упускаю. Сложность обработки данных на SQL связана с убогостью наличных средств декомпозиции.
J> И вот, чтобы обработать эти данные в C#, можно их таки вынуть, преобразовать в формат, понятный C#, обработать их, преобразовать обратно и положить.
Ты опять перескакиваешь через ступеньку.

Вот смотри, я делаю движение номер 1:
var q = from Customers c select c;

Пока ничего интересного не произошло. Но это как раз очень важно: эта строчка пока не означает, что мы "вытащили все данные миллионов кастомеров в C# и преобразовали их в формат, понятный C#"
Теперь я делаю движение номер 2:
if (minRegistrationDate.HasValue)
  q = from q c where c.RegistrationDate >= RegistrationDate.Value
      select c;

Потом я делаю движения номер 3, 4, 5, и так до 18ти.
На 19м я делаю return q.

Компилятор строго следит за тем, чтобы я нигде не накосячил. У меня нет шанса получить в запросе "AND AND". При этом никакие данные никуда не преобразуются. Я работаю с объектом запроса, а не с его результатом.
Вот такой трюк повторить в SQL — чистое самоубийство. Малейшее неровное движение — и в каком-то одном из 2^18 сценариев отчет падает с неустранимой ошибкой.
Что я получил? Я получил "сложный сценарий обработки данных, который сложно писать на SQL". Однако, мне совершенно не потребовалось обрабатывать на C# данные.
Данные должен обрабатывать специализированный сервер, у него это получится значительно лучше, чем у наколенной программы на C#. Сервер умеет применять злую магию индексов, разнообразные оптимизации. Программу на C# можно этому научить, но это еще сложнее, чем функции высшего порядка на T-SQL.

J>Да, не обязательно это делать. Можно работать напрямую на SQL, можно реализовывать какой-то реляционный DSL прямо в языке, и т.п. Но вот Linq to Sql, про который речь, это все-таки подход с преобразованием в объекты.

Ну... В какой-то мере да. Но мы его любим не за это
J>Т.е. это ORM, со всеми его минусами и плюсами.
J>- усложним твой пример с банкоматом. Пусть он показывает текуший счет. И мы считаем, что человек принимает решение о переводе денег, основываясь на текущем счете: из 20штук занять другу 5 — одно, из 6 занять 5 — другое, самому кушать нужно. И мы тут же приходим обратно к обработке оптимистической конкуренции в той или иной форме.
Ну почему обязательно "оптимистической". Вот, к примеру, популярные "Золотые Короны" предлагают вполне себе пессимистическую блокировку, аналогичную системам version control — делаешь себе "checkout" со счета на чиповую карту, и всё. Деньги у тебя, никто со счета их не спишет.

J> Не смотря на то, что "перевод денег" остается таким же атомарным действием. Пример можно сколь угодно усложнять. Главное тут то, что что-то из внешней среды принимает решение за конечное время, основываясь на потенциально устаревшей информации. Т.е. дело не в "концепции сохранения", проблема эта будет существовать при абсолютно любых условиях.

Вовсе даже не при любых. Вот, к примеру, наши форумы. Ты пишешь ответ мне. В это время кто-то другой пишет ответ мне на то же сообщение. Вы друг другу никак не мешаете — потому, что ты не пытаешься вручную увеличивать счетчик ответов.
Проблемы с "устарелостью информации" разрешимы только в замкнутой среде, как, к примеру, в том же SQL Server.
Там, если ты сделал select balance from account where id = 1 (при уровне изоляции serializable), то он умрёт, но не даст никому сделать так, чтобы эта информация "устарела".
Вот только удерживать эту транзакцию длительное время — дорого. Причем эта дорогостоящесть связана не с механикой конкретной блокировки — в оптимистической технике будет примерно то же самое, только стоимость возьмут не с тех, кто "позже прочитал", а с тех, кто "позже записал". Это размазывание состояния, а оно бесплатным не бывает.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.09 21:03
Оценка: +1
Здравствуйте, Jakobz, Вы писали:

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


J>>>Тут одна вешь, которую ты упускаешь, уходя всё дальше от темы: в большинстве случаев "отсоединение" сущностей просто необходимо.

G>>Там где необходимо "отсоединение" там контексты Linq2SQL, EF, сессии NHibernate тоже не справляются и надо "отсоедиенный" набор данных поддерживать руками.
J>Вполне справляются. Автоматически они это не делают, но лучше уж так, чем никак.
Они это никак не делают.
Контекст обычно жевет гораздо меньше, чем проходит времени от показу пользователю формы до ввода данных.

J>Еще раз:

J>- identity tracking. Позволяет имитировать отсутствие identity у объектов внутри контекста. Позволяет дозапрашивать данные и не думать о том, что у нас могут появиться два разных объекта с одним и тем же.
J>- change tracking. Позволяет не писать на каждый чих db.НеЗабудьПроапдейтитьПотом(myObject).

J>Оба два — для удобства.

J>Оба — не обязательно юзать, они отключаются
Только при откоючении обоих изменить данные становиться тяжко.
Я бы сказал что identity\change tracking — необходимые фичи современного ORM (хотя также необходима возможность их отключения для некоторых сценариев).
Но такой способ работать с данными — далеко не единственный, и не самый правильный.
Re[14]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 21:34
Оценка: +1
Здравствуйте, Jakobz, Вы писали:

J>Хорошие подходы: тащить код к данным, а не наоборот, писать на языке, удобным для работы со структурой данных, и т.п. Но они все как-то не совмещаются ни с SQL, ни с C#. Не сможешь ты прозрачно отобразить сколько-то сложный C#-код или какой-то DSL на нем, в полноценный SQL прямо на сервере.

Я не понимаю — неужели Linq2Sql недостаточно убедительно демонстрирует отображение C# в полноценный SQL с блэкджеком и шлюхами?
Никакого сомнения нет в том, что всё это возможно (с некоторыми нюансами).

J>А если и сможешь — умрешь разбираться с проблемами производительности и блокировками.

J>Поэтому модель "оцепил что нужно — обработал — положил назад" — очень даже жизнеспособна.
Всё как раз наоборот: проблемы производительности и блокировок — вторая натура "отсоединенной модели".
Ты еще учти, что в веб, к примеру, приложении, отсоединенные данные один хрен выбрасываются в гарбадж коллектор. Потому что следующий запрос будут обрабатывать совсем другие объекты, и другой датаконтекст.

J>Хотя, конечно, эта вся гетерогенность в виде совершенно разных SQL и C#-или-что-еще-там местами напрягает, да.


Лично меня напрягает только отсутствие полного контроля над событиями. В этом смысле EF всё-таки меньшее зло по сравнению с full blown ORM, но всё-таки дает некоторую излишнюю изоляцию от того, что происходит.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.03.09 08:51
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Да ну? Пока что я видел строго обратное явление: стейтлесс системы значительно сложнее масштабировать. В большинстве тривиальных случаев обработка "отсоединенных данных" приводит тупо к тому, что сиквел сервер по-прежнему делает тот же объем работы (в конце концов, у него главное — стоимость I/O, на его фоне закормить современный CPU задачка нетривиальная), но плюс к этому еще и сервер приложений нагревает воздух. А если сервер приложений случился стейтлес, тогда начинаются еще более интересные сценарии — банальный раунд робин не пойдет, нужно делать балансировку с client affinity, а она небесплатна; или таскать разделяемый кэш, что тоже небесплатно и так далее и так веселее. В итоге вместо линейного по затратам масштабирования получаем какой-то экспоненциальный рост стоимости решения.


Выделенное — наверное имелось ввиду стейтфул.
Re[19]: Некоторые мысли о LINQ
От: Aen Sidhe Россия Просто блог
Дата: 26.03.09 12:17
Оценка: :)
Здравствуйте, VladD2, Вы писали:

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


AS>>Я имел ввиду — как работать с БД без DataContext'ов? Код, который будет заниматься сохранением данных в РСУБД будет где? И как он будет работать? Я либо туплю, либо просто не знаю, но мне на ум только ActiveRecord приходит.


VD>А как раньше работали? SQL-я за глаза хватает. Раньше он в язык не вписывался, а теперь вписывается...


Раньше люди топорами брились. Не удобно.
С уважением, Анатолий Попов.
ICQ: 995-908
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[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[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[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
От: 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[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[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 05.01.09 21:24
Оценка:
Здравствуйте, gandjustas, Вы писали:

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

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

Может поподробней описать, что имеется в виду? В реляционной модели не поддерживаются такие понятия, как наследование, область видимости для данных, методы, меняющие состояние entity. Если все это привнести в нее, то это будет не реляционная, а вполне себе объектная модель.

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

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

Убираешь все relation-ы и ленивые поля и получаешь то, к чему ты так стремишься.

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

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

Тогда бы написание этих запросов превратилось в сущий ад. В лес такое счастье.

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

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

Аудит — это не только lastModified. Есть еще аудит удаленных объектов, хранение истории изменений и так далее. Тоже все это в запрос пихать?

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

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

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

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


Транзакцию и так придется запускать вручную. Операции затрагивающие одну единственную таблицу встречаются чрезвычайно редко.

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


А почему в случае UoW она не может заняться вопросами целостности и конкурентного дотупа?

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

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

PL — это что? страница, форма. А если у BLL несколько пользователей? Например, UI и веб-сервис?
Re[10]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 06.01.09 00:54
Оценка:
Здравствуйте, Tissot, Вы писали:

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


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

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

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


Подсказка: EDM в EF — практически ER описание, пригодное для использования в программе на .NET. Вполне поддерживается и наследование, и область видимости. Методы, меняющие состояние, вы вполне можете сделать через extensionы.
Вы вообще путаете суть и форму. Классы и объекты — это форма, суть в том что в случае EDM это описание сильно соответствует ER описанию.
С помощью Linq вы можете строить выборки данных с помощью синтаксиса классов и объектов не имея фактически объектов (их состояния) в памяти.


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

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

T>Тогда бы написание этих запросов превратилось в сущий ад. В лес такое счастье.

С появлением Linq написание выборок гораздо упростилось, сейчас многих уже и не заставишь вложенные циклы писать вместо использования Linq. С чего вы взяли что при расширении Linq операторами insert, update, delete написание запросов превратится в ад?
Пример (гипотетический)
var someQuery = from el in collection where ... select c;//такое уже есть
delete from c in collection where ... //Сложно?
update c in collection where ... set c.Prop1 = val1, c.Prop2 = val2 //Тоже не очень мудрено
insert into collection2 (someQuery) //любое выражение типа IEnumerable<T> в скобках

Где здесь ад? Большая часть уже сделана в Linq запросах, добавить осталось совсем немного.

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

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

T>Аудит — это не только lastModified.

Бывает.

T>Есть еще аудит удаленных объектов,

View + instead of delete триггер

T>хранение истории изменений и так далее.

триггеры

T>Тоже все это в запрос пихать?

Не стоит. Этим должна БД заниматься, причем прозрачно для пользователя.

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

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

T>Теоретически они могут быть туда записаны. А на практике правила зачастую настолько сложны, что что их даже в императивном варианте записать непросто.

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

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


T>Транзакцию и так придется запускать вручную. Операции затрагивающие одну единственную таблицу встречаются чрезвычайно редко.

Также как и вручную вызыыать SaveChanges. Только немного по-другому рабоать будет. В случае работы с объектами вы сначала получаете их из базы, производите операции (при этом пройти может бесконечно много времени), потом пишете в базу изменения.
В случае работы с запросами вы формируете запросы: создаете выборки без материализации записей, подставляете эти выборки в выражения insert\update\delete, в конце батча добавляете запросы, обеспечивающие валидацию, а потом запускаете батч на исполнение. О всем остальном заботится БД.

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

T>А почему в случае UoW она не может заняться вопросами целостности и конкурентного дотупа?
Синклер привел пример по этому поводу, прочитайте его повнимательнее.

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

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

T>PL — это что? страница, форма. А если у BLL несколько пользователей? Например, UI и веб-сервис?

Вы не умеете делать валидацию введенных данных?
Re[10]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 01:34
Оценка:
G>>Не отказывайтесь. Но базовая модель для данных — ER (потому что БД так работает) и объектная модель должна при желании надстраиваться над ER, причем все "прелести" как ленивая загрузка должны быть опциональны и по-умолчанию выключены.

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


А зачем?
SOA тоже хреново поддерживает ООП и интерфейсы, а в версии MS не поддерживает СПЕЦИАЛЬНО,
однако это не мешает ей быть лидирующей технологией для определённого круга задач.
Чем ER хуже?
Или у тебя есть супермолоток?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 01:50
Оценка:
Здравствуйте, gandjustas, Вы писали:

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


G>Подсказка: EDM в EF — практически ER описание, пригодное для использования в программе на .NET. Вполне поддерживается и наследование, и область видимости. Методы, меняющие состояние, вы вполне можете сделать через extensionы.

G>Вы вообще путаете суть и форму. Классы и объекты — это форма, суть в том что в случае EDM это описание сильно соответствует ER описанию.

Еще раз, в ER модели нет понятий наследования, области видимости, методов и т.д. Вы очень неудачно пользуетесь терминами, которые имеют вполне определенное значение. Посмотрите в википедии.

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


T>>Тогда бы написание этих запросов превратилось в сущий ад. В лес такое счастье.

G>С появлением Linq написание выборок гораздо упростилось, сейчас многих уже и не заставишь вложенные циклы писать вместо использования Linq. С чего вы взяли что при расширении Linq операторами insert, update, delete написание запросов превратится в ад?
G>Пример (гипотетический)
G>
G>var someQuery = from el in collection where ... select c;//такое уже есть
G>delete from c in collection where ... //Сложно?
G>update c in collection where ... set c.Prop1 = val1, c.Prop2 = val2 //Тоже не очень мудрено
G>insert into collection2 (someQuery) //любое выражение типа IEnumerable<T> в скобках
G>

G>Где здесь ад? Большая часть уже сделана в Linq запросах, добавить осталось совсем немного.

Ничего сложного, но где здесь security, валидация, аудит?

T>>>>Ну приплыли.

G>>>Ну не знаю как у вас, а у меня так работает. И отлично работает, по поводу lastModified вообще никто не парится.

T>>Аудит — это не только lastModified.

G>Бывает.

T>>Есть еще аудит удаленных объектов,

G>View + instead of delete триггер


T>>хранение истории изменений и так далее.

G>триггеры

T>>Тоже все это в запрос пихать?

G>Не стоит. Этим должна БД заниматься, причем прозрачно для пользователя.

Как понять в триггере, что запись изменил не sa, а "Васиий Петров"?
Что будем делать если нужны осмысленные записи в логе?
Как все это потом тестировать?

T>>Теоретически они могут быть туда записаны. А на практике правила зачастую настолько сложны, что что их даже в императивном варианте записать непросто.

G>В таком случае надо разбивать на более простые... ну как обычно.

Твоими бы устами ...

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


T>>Транзакцию и так придется запускать вручную. Операции затрагивающие одну единственную таблицу встречаются чрезвычайно редко.

G>Также как и вручную вызыыать SaveChanges. Только немного по-другому рабоать будет. В случае работы с объектами вы сначала получаете их из базы, производите операции (при этом пройти может бесконечно много времени), потом пишете в базу изменения.

Тогда я не понимаю, зачем вы писали "все запросы можно выполнить в одной транзакции БД"?
Зачем это подчеркивать, если и так в обоих случаях все будет работать аналогично?

G>В случае работы с запросами вы формируете запросы: создаете выборки без материализации записей, подставляете эти выборки в выражения insert\update\delete, в конце батча добавляете запросы, обеспечивающие валидацию, а потом запускаете батч на исполнение. О всем остальном заботится БД.


Хорошо, хотя бы на уровне псевдокода опиши как это будет выглядеть без материализации данных из базы для следующего сценария:
Если кастомер из категории VIP, то для него должно быть разрешено резервировать заказ на складе без проверок остатков.

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

T>>А почему в случае UoW она не может заняться вопросами целостности и конкурентного дотупа?
G>Синклер привел пример по этому поводу, прочитайте его повнимательнее.

Спасибо, я прочитал. И даже ответил.

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

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

T>>PL — это что? страница, форма. А если у BLL несколько пользователей? Например, UI и веб-сервис?

G>Вы не умеете делать валидацию введенных данных?

А речь не обо мне, а о вашей архитектуре. Где будет происходить валидация.
Предвидя ваш ответ, чуть усложним постановку: модуль A используется модулем B, модуль B создает новый объект в модуле A. Кто должен будет проверить валидность созданного объекта?
Re[12]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 06.01.09 02:40
Оценка:
Здравствуйте, Tissot, Вы писали:

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


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


G>>Подсказка: EDM в EF — практически ER описание, пригодное для использования в программе на .NET. Вполне поддерживается и наследование, и область видимости. Методы, меняющие состояние, вы вполне можете сделать через extensionы.

G>>Вы вообще путаете суть и форму. Классы и объекты — это форма, суть в том что в случае EDM это описание сильно соответствует ER описанию.

T>Еще раз, в ER модели нет понятий наследования, области видимости, методов и т.д. Вы очень неудачно пользуетесь терминами, которые имеют вполне определенное значение. Посмотрите в википедии.


Еще раз. Не путайте суть и форму. Форма будет одинаковая: классы, объекты, интерфесы, наследование. При ООП подходе у вас будет императивный код работы с объектами. При ER — декларативный код работы с сущностями.

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


T>>>Тогда бы написание этих запросов превратилось в сущий ад. В лес такое счастье.

G>>С появлением Linq написание выборок гораздо упростилось, сейчас многих уже и не заставишь вложенные циклы писать вместо использования Linq. С чего вы взяли что при расширении Linq операторами insert, update, delete написание запросов превратится в ад?
G>>Пример (гипотетический)
G>>
G>>var someQuery = from el in collection where ... select c;//такое уже есть
G>>delete from c in collection where ... //Сложно?
G>>update c in collection where ... set c.Prop1 = val1, c.Prop2 = val2 //Тоже не очень мудрено
G>>insert into collection2 (someQuery) //любое выражение типа IEnumerable<T> в скобках
G>>

G>>Где здесь ад? Большая часть уже сделана в Linq запросах, добавить осталось совсем немного.

T>Ничего сложного, но где здесь security, валидация, аудит?

Дополнительное выражение в where, или дополнительный запрос.
Или вы считаете что нельзя с помощью запросов выразить большенство операций?

T>Как понять в триггере, что запись изменил не sa, а "Васиий Петров"?

T>Что будем делать если нужны осмысленные записи в логе?
T>Как все это потом тестировать?
Для осмысленных записей в логе в БД есть таблица с пользователями.

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

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


T>>>Транзакцию и так придется запускать вручную. Операции затрагивающие одну единственную таблицу встречаются чрезвычайно редко.

G>>Также как и вручную вызыыать SaveChanges. Только немного по-другому рабоать будет. В случае работы с объектами вы сначала получаете их из базы, производите операции (при этом пройти может бесконечно много времени), потом пишете в базу изменения.

T>Тогда я не понимаю, зачем вы писали "все запросы можно выполнить в одной транзакции БД"?

T>Зачем это подчеркивать, если и так в обоих случаях все будет работать аналогично?
Вы не поняли. Действительно можно будет выполнить ВСЕ запросы в одной транзакции. При использовании ОРМ придется сделать выборку в одной транзакции, а потом коммит в другой. Можно явно объявить TransactionScope, но тогда её придется явно завершить после вызова SaveChanges.

G>>В случае работы с запросами вы формируете запросы: создаете выборки без материализации записей, подставляете эти выборки в выражения insert\update\delete, в конце батча добавляете запросы, обеспечивающие валидацию, а потом запускаете батч на исполнение. О всем остальном заботится БД.

T>Хорошо, хотя бы на уровне псевдокода опиши как это будет выглядеть без материализации данных из базы для следующего сценария:
T>Если кастомер из категории VIP, то для него должно быть разрешено резервировать заказ на складе без проверок остатков.

//Предположим что здесь запрос, выполняющий резервирование
//Выборка кастомера, материализация не требуется
var cust = from c in context.Customers 
           where c.Id == customerId
           where c.Category.Name == "VIP"
           select c;

//Теперь валидационный запрос, выполняется в тойже транзакции что и предыдущие
from ..... //Выборка зарезервированных позиций
where (условие остатки < 0) && !cust.Any()
select context.ThrowError() //context.ThrowError - функция в БД, которая кидает ошибку и откатывает транзакцию.


При материализации последнего запроса вылетит ошибка и транзакция будет откачена если остатки ушли в минус, а кастомер не VIP.

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

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

T>>>PL — это что? страница, форма. А если у BLL несколько пользователей? Например, UI и веб-сервис?

G>>Вы не умеете делать валидацию введенных данных?

T>А речь не обо мне, а о вашей архитектуре. Где будет происходить валидация.

T>Предвидя ваш ответ, чуть усложним постановку: модуль A используется модулем B, модуль B создает новый объект в модуле A. Кто должен будет проверить валидность созданного объекта?
Ниче не понял.. Циклические зависимости или как? По-русски опишите чего надо.
Я обычно валидацию на всех уровнях делаю: проверки значений полей ввода в интерфейсе, проверки параметром методов в BLL, валидация модели, констрейнты в БД.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 03:12
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Вы вообще путаете суть и форму. Классы и объекты — это форма, суть в том что в случае EDM это описание сильно соответствует ER описанию.


T>>Еще раз, в ER модели нет понятий наследования, области видимости, методов и т.д. Вы очень неудачно пользуетесь терминами, которые имеют вполне определенное значение. Посмотрите в википедии.


G>Еще раз. Не путайте суть и форму. Форма будет одинаковая: классы, объекты, интерфесы, наследование. При ООП подходе у вас будет императивный код работы с объектами. При ER — декларативный код работы с сущностями.


Ок. Я понял, под er вы подразумеваете не er-модель. Проехали.

T>>Ничего сложного, но где здесь security, валидация, аудит?

G>Дополнительное выражение в where, или дополнительный запрос.
G>Или вы считаете что нельзя с помощью запросов выразить большенство операций?

Можно. Но мне не известо ничего о том как бороться со сложностью в запросах. А они при предлагаемых методах будут сложными.

T>>Как понять в триггере, что запись изменил не sa, а "Васиий Петров"?

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

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

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


Такие тесты работать будут часами. Главное требование к юнит-тесту — это то, что он работает оч. быстро. Станет работать медленно, никто их запускать не будет. На себе проверено.

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


T>>>>Транзакцию и так придется запускать вручную. Операции затрагивающие одну единственную таблицу встречаются чрезвычайно редко.

G>>>Также как и вручную вызыыать SaveChanges. Только немного по-другому рабоать будет. В случае работы с объектами вы сначала получаете их из базы, производите операции (при этом пройти может бесконечно много времени), потом пишете в базу изменения.

T>>Тогда я не понимаю, зачем вы писали "все запросы можно выполнить в одной транзакции БД"?

T>>Зачем это подчеркивать, если и так в обоих случаях все будет работать аналогично?
G>Вы не поняли. Действительно можно будет выполнить ВСЕ запросы в одной транзакции. При использовании ОРМ придется сделать выборку в одной транзакции, а потом коммит в другой.

Это еще почему?

G>Можно явно объявить TransactionScope, но тогда её придется явно завершить после вызова SaveChanges.


Это сложно?

G>>>В случае работы с запросами вы формируете запросы: создаете выборки без материализации записей, подставляете эти выборки в выражения insert\update\delete, в конце батча добавляете запросы, обеспечивающие валидацию, а потом запускаете батч на исполнение. О всем остальном заботится БД.

T>>Хорошо, хотя бы на уровне псевдокода опиши как это будет выглядеть без материализации данных из базы для следующего сценария:
T>>Если кастомер из категории VIP, то для него должно быть разрешено резервировать заказ на складе без проверок остатков.

G>
G>//Предположим что здесь запрос, выполняющий резервирование
G>//Выборка кастомера, материализация не требуется
G>var cust = from c in context.Customers 
G>           where c.Id == customerId
G>           where c.Category.Name == "VIP"
G>           select c;

G>//Теперь валидационный запрос, выполняется в тойже транзакции что и предыдущие
G>from ..... //Выборка зарезервированных позиций
G>where (условие остатки < 0) && !cust.Any()
G>select context.ThrowError() //context.ThrowError - функция в БД, которая кидает ошибку и откатывает транзакцию.
G>


G>При материализации последнего запроса вылетит ошибка и транзакция будет откачена если остатки ушли в минус, а кастомер не VIP.


То есть сначала мы пишем в базу, а потом валидируем? Оригинально
Это точно ты говорил, что материализация плохо отражается на перформансе?

T>>>>PL — это что? страница, форма. А если у BLL несколько пользователей? Например, UI и веб-сервис?

G>>>Вы не умеете делать валидацию введенных данных?

T>>А речь не обо мне, а о вашей архитектуре. Где будет происходить валидация.

T>>Предвидя ваш ответ, чуть усложним постановку: модуль A используется модулем B, модуль B создает новый объект в модуле A. Кто должен будет проверить валидность созданного объекта?
G>Ниче не понял.. Циклические зависимости или как? По-русски опишите чего надо.

Пусть система состоит из 2-х подсистем: работа с кастомерами, база знаний.
Есть кастомер. При регистрации его в системе должен создаться соответствующий раздел в базе знаний.
Где (кем) будет проверяться, что созданный раздел создан корректно?

G>Я обычно валидацию на всех уровнях делаю: проверки значений полей ввода в интерфейсе, проверки параметром методов в BLL, валидация модели, констрейнты в БД.


Два сообщения назад валидации модели еще не было. Прогресс налицо!

P.S. На самом деле то, что вы описываете, до боли напоминает transaction script как он назван у Фаулера. Единственное отличие, которое я вижу — это его типизированность. В той же книжке описывается почему с ростом сложности приложения с transaction script-ом становится сложно жить. Рекомендую глянуть, если еще не смотрели.
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 03:15
Оценка:
Здравствуйте, VGn, Вы писали:

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


VGn>А зачем?


За надом (понимать буквально)

VGn>SOA тоже хреново поддерживает ООП и интерфейсы, а в версии MS не поддерживает СПЕЦИАЛЬНО,

VGn>однако это не мешает ей быть лидирующей технологией для определённого круга задач.
VGn>Чем ER хуже?

Причину отсутствия этого в SOA вполне можно понять. Зачем отказываться от этого в domain model я не понимаю.
Re[8]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.01.09 07:43
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Вот как раз в случае UoW удержание будет меньше.

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

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

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



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

T>Во-первых, вы допустили ошибку в коде.

Где?
T>Во-вторых, на самом деле все может быть сложнее: для каких-то категорий клиентов/товаров вполне может быть позволено заказывать в минуса, для каких-то категорий товаров должен гарантировано оставаться какой-то остаток на складах, если заказ крупный, то должно быть проверено, внесена ли предоплата и т.д. и т.п.. Я бы не хотел поддерживать код в котором все эти правила внесены в один update.
Именно облегчения поддержки такого кода мы и ждем от Linq. Потому, что вручную педалить все эти вещи — очень тяжело, и мы хотим контроль компилятора. Вот select стейтменты линк готовит прекрасно. Можно иметь произвольно сложную логику по динамическому формированию предикатов и всё еще получать статический контроль корректности.

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

Это смелое утверждение.
T>Ты забыл добавить "если update — это единственная действие в бизнес-транзакции".
Ну, вообще-то подавляющее большинство "бизнес-операций" сводятся к очень ограниченному набору insert/update/delete. Особенно если проектировать приложение, держа это в уме.
Просто средства и фреймворки всегда навязывают своё мышление. "Реляционный" программист всегда старается свести задачу к манипуляции над реляциями. Как раз такого типа, как я показал. Вот ты привел примеры дополнительных бизнес-правил. "ООПшный" программист постарается избавиться от if-ов, которые проверяют "не нужно ли запасти ненулевой остаток для данной категории товара", и "нужна ли предоплата для данного размера заказа", путём выноса их в виртуальные методы некоторой иерархии классов. А реляционщик попробует свести всё это небольшому количеству массовых апдейтов.
То есть построит отдельную view "минимально допустимый остаток товара на складе" и приджойнит ее к запросу. И так далее.

Я еще раз подчеркиваю, что основное ограничение unit of work — в том, что он следит исключительно за изменениями, сделанными в транзакции. Он ничего не знает о том, какие причины привели к этим изменениям. Это означает, в частности, что для обеспечения элементарной транзакционной целостности, которая доступна в старинном SQL забесплатно, нужно делать специальные приседания.

T>А может зря оно себя таким уж прогрессивным считает?

Видишь ли, в чем дело. Это человечество разрабатывало ORM системы еще до первого коммита в репозиторий Hibernate и выхода Фаулеровского "P of EAA".
И был накоплен некоторый опыт взаимодействия с самыми разными архитектурами систем. Linq — это самое передовое достижение мысли в области работы с реляционными данными, но и у него есть недостатки.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.01.09 07:57
Оценка:
Здравствуйте, Tissot, Вы писали:
T>Можно. Но мне не известо ничего о том как бороться со сложностью в запросах. А они при предлагаемых методах будут сложными.
Это ключевой момент в данной дискуссии.
Поясняю на пальцах: Linq и есть способ борьбы со сложностью в запросах.
Потому, что вместо кропотливого построения многоэтажных where, можно разбить процесс построения запроса на несколько частей:
storeItems = GetStoreItems(order);
storeItems = AddQuantityCheck(storeItems);
storeItems = AddSecurityCheck(storeItems);

Каждая из них по отдельности проста. А Linq обеспечивает корректную склейку этих частей.
Более того, их можно применять динамически:
storeItems = GetStoreItems(order);
if (customer.Status != CustomerStatus.VIP)
  storeItems = AddQuantityCheck(storeItems);
storeItems = AddSecurityCheck(storeItems);

Вот примерно так и борются со сложностью SQL запросов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 11:00
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Более того, их можно применять динамически:

S>
S>storeItems = GetStoreItems(order);
S>if (customer.Status != CustomerStatus.VIP)
S>  storeItems = AddQuantityCheck(storeItems);
S>storeItems = AddSecurityCheck(storeItems);
S>

S>Вот примерно так и борются со сложностью SQL запросов.

Ну в общем-то так и думал. Работал с таким — лучше чем ничего, но все равно недостаточно удобно. Если придумаете что-то более удобное — то честь вам и хвала.
Re[14]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 06.01.09 11:15
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>Вы вообще путаете суть и форму. Классы и объекты — это форма, суть в том что в случае EDM это описание сильно соответствует ER описанию.

T>>>Еще раз, в ER модели нет понятий наследования, области видимости, методов и т.д. Вы очень неудачно пользуетесь терминами, которые имеют вполне определенное значение. Посмотрите в википедии.
G>>Еще раз. Не путайте суть и форму. Форма будет одинаковая: классы, объекты, интерфесы, наследование. При ООП подходе у вас будет императивный код работы с объектами. При ER — декларативный код работы с сущностями.
T>Ок. Я понял, под er вы подразумеваете не er-модель. Проехали.
А что вы подразумеваете под ER моделью в программе?

T>>>Ничего сложного, но где здесь security, валидация, аудит?

G>>Дополнительное выражение в where, или дополнительный запрос.
G>>Или вы считаете что нельзя с помощью запросов выразить большенство операций?
T>Можно. Но мне не известо ничего о том как бороться со сложностью в запросах. А они при предлагаемых методах будут сложными.
Известно. Linq в текущей реализации позоволяет последовательно строить выборку, накладывая дополнительные ограничения.
В коде выглядит как фильрация коллекции с разными условиями, только самой коллекции нету.

T>>>Как понять в триггере, что запись изменил не sa, а "Васиий Петров"?

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

T>То есть каждому пользователю давать свой логин в базе? Ты в курсе, что так делать не рекомендуют?

Нет, есть таблица, хранящая логины и другие сведения о пользователях. В логах можно ссылкаться на эту таблицу.

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

T>Такие тесты работать будут часами. Главное требование к юнит-тесту — это то, что он работает оч. быстро. Станет работать медленно, никто их запускать не будет. На себе проверено.
Вам не потребуется эти тесты запускать в совокупноти с unit-тестами приложения. Аудит в БД полностью ортогонален бизнес-логике в коде приложения.

G>>Вы не поняли. Действительно можно будет выполнить ВСЕ запросы в одной транзакции. При использовании ОРМ придется сделать выборку в одной транзакции, а потом коммит в другой.

T>Это еще почему?
Потому что реализация такая. Linq2SQL и EF так работают.

G>>Можно явно объявить TransactionScope, но тогда её придется явно завершить после вызова SaveChanges.

T>Это сложно?
Это сложнее чем ОДИН раз явно обявить транзакцию при использовании запросов.

G>>>>В случае работы с запросами вы формируете запросы: создаете выборки без материализации записей, подставляете эти выборки в выражения insert\update\delete, в конце батча добавляете запросы, обеспечивающие валидацию, а потом запускаете батч на исполнение. О всем остальном заботится БД.

T>>>Хорошо, хотя бы на уровне псевдокода опиши как это будет выглядеть без материализации данных из базы для следующего сценария:
T>>>Если кастомер из категории VIP, то для него должно быть разрешено резервировать заказ на складе без проверок остатков.

G>>
G>>//Предположим что здесь запрос, выполняющий резервирование
G>>//Выборка кастомера, материализация не требуется
G>>var cust = from c in context.Customers 
G>>           where c.Id == customerId
G>>           where c.Category.Name == "VIP"
G>>           select c;

G>>//Теперь валидационный запрос, выполняется в тойже транзакции что и предыдущие
G>>from ..... //Выборка зарезервированных позиций
G>>where (условие остатки < 0) && !cust.Any()
G>>select context.ThrowError() //context.ThrowError - функция в БД, которая кидает ошибку и откатывает транзакцию.
G>>


G>>При материализации последнего запроса вылетит ошибка и транзакция будет откачена если остатки ушли в минус, а кастомер не VIP.


T>То есть сначала мы пишем в базу, а потом валидируем? Оригинально

При таком подходе ВСЯ работа с данными происходит в БД, это нормально.

T>Это точно ты говорил, что материализация плохо отражается на перформансе?

Это так и есть.

T>Пусть система состоит из 2-х подсистем: работа с кастомерами, база знаний.

T>Есть кастомер. При регистрации его в системе должен создаться соответствующий раздел в базе знаний.
T>Где (кем) будет проверяться, что созданный раздел создан корректно?
Наверное тем кто создает раздел. К чему это все?

G>>Я обычно валидацию на всех уровнях делаю: проверки значений полей ввода в интерфейсе, проверки параметром методов в BLL, валидация модели, констрейнты в БД.

T>Два сообщения назад валидации модели еще не было. Прогресс налицо!
Два сообщения назад я говорил о валидации, не касающейся данных в базе.

T>P.S. На самом деле то, что вы описываете, до боли напоминает transaction script как он назван у Фаулера. Единственное отличие, которое я вижу — это его типизированность. В той же книжке описывается почему с ростом сложности приложения с transaction script-ом становится сложно жить. Рекомендую глянуть, если еще не смотрели.

Я уже форуме "архитектура" про фаулера отписал. Повторюсь здесь.
Концептуальная разница между transaction script и dimain model состоит в том как вы хотите вызывать методы бизнес-логики
Так
entity.Operation(params)

или так
service.Operation(entity, params)

Второй подход гораздо лучше по многим причинам.

А фаулер какю-то неправильную траву курит.
Re[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 11:24
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Вот как раз в случае UoW удержание будет меньше.

S>Непонятно, за счёт чего.

См. ниже.

T>>Рассмотри сценарий чуть посложнее, чем "обновить поле". Например в результате какой-то операции сначала нам понадобилось обновить у сustome-а поле A, потом провести какие-то достаточно длительные вычисления, потом обновить поле B.

S>Я такой сценарий представляю себе с большим трудом.

А ты представь.

T>>В варианте с UoW на время операции будет наложена shared блокировка и только на время submit-а — более тяжелая exclusive.

S>А ничего, что в случае отката транзакции значение поля А, прочитанное кем-то во время "удержания shared блокировки", будет потеряно?

Я не совсем интонацию понял. Для меня вопрос звучит столь же нелепо, как и спрашивать — "а ничего, что при откате транзакции изменения потеряются".

S>Если ничего, то можно разбить транзакцию на две, и не удерживать эксклюзивную блокировку во время тяжелых вычислений.


Нельзя, целостность будет потеряна.

S>А если такое нарушение целостности недопустимо, то UoW нужно срочно выбросить.


Не улавливаю ход рассуждения, распиши подробнее.

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

T>>Во-первых, вы допустили ошибку в коде.

S>Где?

Задание на дом. Перечитай свое же сообщение еще раз.

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

S>Именно облегчения поддержки такого кода мы и ждем от Linq. Потому, что вручную педалить все эти вещи — очень тяжело, и мы хотим контроль компилятора. Вот select стейтменты линк готовит прекрасно. Можно иметь произвольно сложную логику по динамическому формированию предикатов и всё еще получать статический контроль корректности.

Вручную педалить тяжело если вы остаетесь в рамках trabsaction script-а. Переходите на ооп подход и волосы становятся густыми и блестящими

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

S>Это смелое утверждение.
T>>Ты забыл добавить "если update — это единственная действие в бизнес-транзакции".
S>Ну, вообще-то подавляющее большинство "бизнес-операций" сводятся к очень ограниченному набору insert/update/delete. Особенно если проектировать приложение, держа это в уме.
S>Просто средства и фреймворки всегда навязывают своё мышление. "Реляционный" программист всегда старается свести задачу к манипуляции над реляциями. Как раз такого типа, как я показал. Вот ты привел примеры дополнительных бизнес-правил. "ООПшный" программист постарается избавиться от if-ов, которые проверяют "не нужно ли запасти ненулевой остаток для данной категории товара", и "нужна ли предоплата для данного размера заказа", путём выноса их в виртуальные методы некоторой иерархии классов.

Совершенно верно.

S>А реляционщик попробует свести всё это небольшому количеству массовых апдейтов.


Пока у них это не очень хорошо получается. Те средства декомпозиции запросов, что есть в SQL-е и в базах данных (WITH, view, функции) просто смешны и не выдерживают никакой критики.

S>То есть построит отдельную view "минимально допустимый остаток товара на складе" и приджойнит ее к запросу. И так далее.


Как бороться со ложностью? Как это тестировать? и так далее.
ООП дает на эти вопросы более менее внятный ответ.

S>Я еще раз подчеркиваю, что основное ограничение unit of work — в том, что он следит исключительно за изменениями, сделанными в транзакции. Он ничего не знает о том, какие причины привели к этим изменениям. Это означает, в частности, что для обеспечения элементарной транзакционной целостности, которая доступна в старинном SQL забесплатно, нужно делать специальные приседания.


Не пойму, что тебе запрещает использовать танзакции-то? И полчишь "целостность, которая доступна в старинном SQL забесплатно".

T>>А может зря оно себя таким уж прогрессивным считает?

S>Видишь ли, в чем дело. Это человечество разрабатывало ORM системы еще до первого коммита в репозиторий Hibernate и выхода Фаулеровского "P of EAA".
S>И был накоплен некоторый опыт взаимодействия с самыми разными архитектурами систем. Linq — это самое передовое достижение мысли в области работы с реляционными данными, но и у него есть недостатки.

Все новое всегда кажется лучшим и более передовым. Linq-у не так много лет, чтобы успеть обкатать его в достаточной мере и почувствовать на собственной шкуре все недостатки, которых он конечно же не лишен.
Подходу же с linq-like insert-ами — и того меньше лет (0). Поэтому говорить о его достоинствах несколько рановато.
Re[6]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 06.01.09 12:39
Оценка:
Здравствуйте, Tissot, Вы писали:

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

Во-первых, де-факто стандарт — это очень сильное преувеличение. А во-вторых, стандартность подхода довольно хлипкий аргумент.

T>Почему вариант с update/insert будет иметь меньшее кол-во блокировок?

Он будет держать их меньшее время и блокировки будут поддаваться большему контролю.

T>Мне доводилось работать с корпоративными приложениями, в том числе с достаточно крупными (Axapta).



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

Это ты про себя сейчас? ) Не надо, не продолжай.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 14:19
Оценка:
Здравствуйте, IB, Вы писали:

T>>В случае, если действуем по вашему сценарию — сразу получаем exclusive и удерживаем ее на время операции.

IB>Это с какого перепуга?

Потому что update

T>>И какой вариант после этого более легковесный?

IB>конечно сиквельный, так как все тяжелые операции будут сделаны еще до первого обращения к базе, без каких либо блокировок.

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

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

IB>Потому что ему доступна вся транзакция и он может ее оптимизировать так как ему удобно.

Я не знал, что если в батче содержится несколько стейтментов, то сервер анализирует весь батч целиком. Всегда был уверен, что он выполняет стейтмент за стейтментом.
Если у вас другая информация, не мог бы ты подилиться источником оной?

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

IB>В том-то и дело, что теоретически этот update можно поддерживать легко и непринужденно, если делать это так же, как LINQ позволяет обращаться с select-ом.

Ключевое слово выделено. А на практике?

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

IB>Это твой основной аргумент? )

А как еще назвать ситуацию, когда в качестве аргумента приводят код, который в жизни практически не встречается?

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

IB>Бизнес-транзакция тут непричем.

Я в курсе. Под бизнес-транзакцией в данном случае я имел в виду некоторое действие производимое с системой атомарное с точки зрения пользователя. Не смог подобрать более подходящего названия.
Приведенный код был слишком простым, чтобы на его примере увидить недостатки подхода "делаем все одним update-ом". Де-факто этот единственный update потребует как минимум проверку валидности, проверку безопасности, аудит действий и т.д. Если бы все эти сервисные операции были включены в пример, то его красота сразу бы куда-то улетучилась.

IB>Бизнес-транзакция и транзакция БД — вещи совершенно разные и декларативный подход, при работе с данными дает гораздо больший контроль и над тем что происходит в бизнес-транзакциях и над тем, что происходит в БД.


Очень интересный тезис, но позволь в него не поверить. Ну или по-крайней мере объясни откуда возьмется этот больший контроль.
Re[7]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 14:28
Оценка:
Здравствуйте, IB, Вы писали:

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

IB>Во-первых, де-факто стандарт — это очень сильное преувеличение.

Я довольно регулярно слежу за тенденциями в этой сфере. И мне как-то последние годов несколько очень редко попадаются апологеты подхода "запихнем все в базу". Все больше как-то говорят за полноценную domain model.
Но не исключаю, что я что-то упустил. Буду благодарен, если подкинешь ссылочек.

IB>А во-вторых, стандартность подхода довольно хлипкий аргумент.


Стандартность означает распространенность, распространенность означает что большинство граблей уже найдено и найдены способы как с ними бороться.
В сухом остатке получаем, что подход с domain model более "проработан" чем иные.
Это тоже будешь считать более хлипким аргументом?

T>>Почему вариант с update/insert будет иметь меньшее кол-во блокировок?

IB>Он будет держать их меньшее время и блокировки будут поддаваться большему контролю.

Я же привел пример:
1. делаем update 1 поля
2. долго что-то считаем
3. делаем следующий update

Не мог бы ты оставаясь в рамках этого примера описать, откуда возникнет "меньшее время" и "больший контроль"?

T>>Мне доводилось работать с корпоративными приложениями, в том числе с достаточно крупными (Axapta).

IB>

Что тебя так развеселило? Расскажи, вместе посмеемся.
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 14:29
Оценка:
Здравствуйте, IB, Вы писали:

T>>Ну в общем-то так и думал. Работал с таким — лучше чем ничего, но все равно недостаточно удобно. Если придумаете что-то более удобное — то честь вам и хвала.

IB>Достаточно того, что это намного удобнее чем UoW, ORM и прочие приседания вокруг ОО.

Спасибо за развернутый и аргуметированный ответ. Вы раскрыли мне глаза.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 14:53
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Еще раз. Не путайте суть и форму. Форма будет одинаковая: классы, объекты, интерфесы, наследование. При ООП подходе у вас будет императивный код работы с объектами. При ER — декларативный код работы с сущностями.

T>>Ок. Я понял, под er вы подразумеваете не er-модель. Проехали.
G>А что вы подразумеваете под ER моделью в программе?

Под ER-моделью я, как ни странно, понимаю ER-модель

G>>>Или вы считаете что нельзя с помощью запросов выразить большенство операций?

T>>Можно. Но мне не известо ничего о том как бороться со сложностью в запросах. А они при предлагаемых методах будут сложными.
G>Известно. Linq в текущей реализации позоволяет последовательно строить выборку, накладывая дополнительные ограничения.
G>В коде выглядит как фильрация коллекции с разными условиями, только самой коллекции нету.

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

T>>То есть каждому пользователю давать свой логин в базе? Ты в курсе, что так делать не рекомендуют?

G>Нет, есть таблица, хранящая логины и другие сведения о пользователях. В логах можно ссылкаться на эту таблицу.

А как определить текущего пользователя?

T>>Такие тесты работать будут часами. Главное требование к юнит-тесту — это то, что он работает оч. быстро. Станет работать медленно, никто их запускать не будет. На себе проверено.

G>Вам не потребуется эти тесты запускать в совокупноти с unit-тестами приложения. Аудит в БД полностью ортогонален бизнес-логике в коде приложения.

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

G>>>Вы не поняли. Действительно можно будет выполнить ВСЕ запросы в одной транзакции. При использовании ОРМ придется сделать выборку в одной транзакции, а потом коммит в другой.

T>>Это еще почему?
G>Потому что реализация такая. Linq2SQL и EF так работают.

Открывай TransactionScope и будет одна транзакция. Или я опять что-то не понимаю?

G>>>Можно явно объявить TransactionScope, но тогда её придется явно завершить после вызова SaveChanges.

T>>Это сложно?
G>Это сложнее чем ОДИН раз явно обявить транзакцию при использовании запросов.

Все равно не вкуриваю. Код с TransactionScope — правтически один-в-один с приводимым тобой кодом. В чем отличие-то?

G>>>При материализации последнего запроса вылетит ошибка и транзакция будет откачена если остатки ушли в минус, а кастомер не VIP.


T>>То есть сначала мы пишем в базу, а потом валидируем? Оригинально

G>При таком подходе ВСЯ работа с данными происходит в БД, это нормально.

БД — это всегда узкое место. Если есть возможность делать проверки в бизнесе, они болжны быть сделаны в бизнесе. Неужели эти банальности нужно повторять?

T>>Это точно ты говорил, что материализация плохо отражается на перформансе?

G>Это так и есть.

И как это сочетается с тем, что валидацию ты возлагаешь на базу, когда ее можно сделать в бизнесе, что дешевле?

T>>Пусть система состоит из 2-х подсистем: работа с кастомерами, база знаний.

T>>Есть кастомер. При регистрации его в системе должен создаться соответствующий раздел в базе знаний.
T>>Где (кем) будет проверяться, что созданный раздел создан корректно?
G>Наверное тем кто создает раздел. К чему это все?

То есть нужно полагаться на то, что никто не напортачит и сделает все правильно, так?


T>>P.S. На самом деле то, что вы описываете, до боли напоминает transaction script как он назван у Фаулера. Единственное отличие, которое я вижу — это его типизированность. В той же книжке описывается почему с ростом сложности приложения с transaction script-ом становится сложно жить. Рекомендую глянуть, если еще не смотрели.

G>Я уже форуме "архитектура" про фаулера отписал. Повторюсь здесь.
G>Концептуальная разница между transaction script и dimain model состоит в том как вы хотите вызывать методы бизнес-логики
G>Так
G>
G>entity.Operation(params)
G>

G>или так
G>
G>service.Operation(entity, params)
G>

G>Второй подход гораздо лучше по многим причинам.

Сервисы не отрицают domain model, а дополняют ее.
Развитая доменная модель позволяет защитить целостность данных в доменной модели и сделать код более читаемым, близким к предметной области.

G>А фаулер какю-то неправильную траву курит.


Да они там все такие :

Жена звонит мужу на мобильный:
— Алло, ты где?
— Я в машине, на садовом.
— Ты там осторожнее, по телевизору показывают — там какой-то придурок
по встречной полосе едет!!!
— Ты не поверишь, их здесь сотни!!!

Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 14:55
Оценка:
Здравствуйте, IB, Вы писали:

T>>За надом (понимать буквально)

IB>То есть, очень хочется, но объяснить не можешь? )

Да чего там объяснять-то? Влом Фаулера переписывать.

T>> Зачем отказываться от этого в domain model я не понимаю.

IB>Потому что там это не нужно и даже вредно.

Ну нет, так нет.
Re[5]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 15:03
Оценка:
Здравствуйте, IB, Вы писали:

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

IB>Я тебе больше скажу, SQL вообще мало отношения к реляционной алгебре имеет. Только работают все с SQL-ем, а не с реляцонной алгеброй в вакууме.
IB>Ты что сказать-то хотел?

Меня несколько смутило, что insert-ы, да update-ы относят к реляционным операторам. Теперь ясно что имелось в виду другое. Проехали.

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

T>>1) ER vs ObjectModel: мой выбор однозначно в пользу ObjectModel. Потому что она банально предоставляет больше возможностей.
IB>Если бы это было так, то весь мир уже давно бы сидел на ООБД. Правда заключается в том, что большинство возможностей ОО подхода при работе с данными оказываются либо бесполезными, либо вообще вредными.

Раз уж мы аппелируем к большинству, то это большинство какраз-таки пользуется разными Hibernate-ами вовсю.

T>> Кроме того, er может быть смоделирована через object model, обратное — неверно.

IB>Приведи мне пример объектов, которые нельзя было бы смоделировать, через ER?

Наследование. Отношения многие ко многим. Методы. Интерфейсы.

T>>2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее.

IB>Это в каких, например?

См. Фаулера. Перепечатывать цитаты я не буду.

T>> Единственный его недостаток — это когда нужно массово обновить большое количество объектов.

IB>Если под "массово обновить большое количество объектов" понимается, что объектов больше одного, то согласен.

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

IB>Проблема только в том, что таких случаев в реальной жизни подавляющее большинство, отсюда делаем совершенно закономерный вывод, что UoW конструкция бесполезная.


В моей "реальной жизни" такого рода массовое обновление встречается не так уж и часто, так что пусть живет.
Re[8]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 15:26
Оценка:
T>>>Мне доводилось работать с корпоративными приложениями, в том числе с достаточно крупными (Axapta).
IB>>

T>Что тебя так развеселило? Расскажи, вместе посмеемся.


присоединяюсь

Вообще похоже, что спор возник на пустом месте, точнее в разных координатах.
Крупные системы — это действительно Крупные системы.
Не AXAPTA, не 1С, не sharepoint.
Тебе не известны проблемы масштабных систем, поэтому спорить нет смысла.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[6]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 15:26
Оценка:
T>>>2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее.
IB>>Это в каких, например?

T>См. Фаулера. Перепечатывать цитаты я не буду.


Ещё что-нибудь читал?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[7]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 15:30
Оценка:
Здравствуйте, VGn, Вы писали:

T>>См. Фаулера. Перепечатывать цитаты я не буду.


VGn>Ещё что-нибудь читал?


Думаю основное из того, что издавалось на русском языке + многое из того что издавалось на английском я читал.
Если интересуют какие-то конкретные книги, готов ответить.
Re[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 15:33
Оценка:
Здравствуйте, VGn, Вы писали:

VGn> Вообще похоже, что спор возник на пустом месте, точнее в разных координатах.

VGn> Крупные системы — это действительно Крупные системы.
VGn> Не AXAPTA, не 1С, не sharepoint.
VGn> Тебе не известны проблемы масштабных систем, поэтому спорить нет смысла.

А почему Axapta не является крупной системой?
Я знаю что в России есть предприятия на которых она используется на наскольких тысячах рабочих мест + бизнес логика там весьма не простая.
Ты считаешь это не крупная система?
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 18:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Задание на дом. Перечитай свое же сообщение еще раз.

S>А вот хамить не надо.

А я и не хамлю.
Пункт 4 не выполнен.

T>>Как бороться со ложностью? Как это тестировать? и так далее.

S>Еще раз поясняю: единственный способ бороться со сложностью, придуманный прогрессивным человечеством — это декомпозиция. Да, возможности по декомпозиции, заложенные в SQL, не слишком мощны. Но вот Linq предлагает более совершенные средства, на которые я кратко намекнул.

Кстати, еще одно вспомнилось, что непонятно как поддеживать в Linq-е — рекурсивные запросы.

T>>ООП дает на эти вопросы более менее внятный ответ.

S>Мне не нравится вариант ответа, который обеспечивает плохую изоляцию транзакций и низкое быстродействие. Я перфекционист, мне нужна комната с видом на море.

Дерзайте, я не против.
Если что получится — хорошо, значит примем на вооружение еще один прием.
Не получится — тоже хорошо, значит я был прав.

T>>Не пойму, что тебе запрещает использовать танзакции-то? И полчишь "целостность, которая доступна в старинном SQL забесплатно".

S>Поясняю на пальцах: понятие транзакционной целостности, в частности включает в себя отслеживание того факта, что прочитанные в начале транзакции данные остаются актуальными и в ее конце. В частности, если я делаю модификацию позиций заказа, я должен вначале проверить, что сам заказ еще не отгружен. SQL достигает этого путем наложения блокировок даже при выполнении селект стейтмента. Unit of Work никак не отслеживает чтения, сделанные в процессе выполнения транзакции.

Опять нифига не понятно. Чтение в Unit of Work в конечном итоге — это тот же SELECT. Тут или ты чего не договоариваешь, или .. на этом моя мысль заканчивается.
Re[8]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 20:00
Оценка:
VGn>>Ещё что-нибудь читал?

T>Думаю основное из того, что издавалось на русском языке + многое из того что издавалось на английском я читал.

T>Если интересуют какие-то конкретные книги, готов ответить.

На протяжении всего обсуждения было несколько твоих отсылок только к одной (как я понял) книге Фаулера. Причём той, ценность которой мне лично не очевидна.
Я имею в виду Patterns of Enterprise Application Architecture, содержание которой в общем нареканий не вызывает. Сомнительно только слово Enterprise.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[10]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 20:00
Оценка:
T>А почему Axapta не является крупной системой?
T>Я знаю что в России есть предприятия на которых она используется на наскольких тысячах рабочих мест + бизнес логика там весьма не простая.
T>Ты считаешь это не крупная система?

С точки зрения структуры предприятия и масштабов бизнеса, Axapta лучше всего подходит компаниям:
* численностью до 10 000 сотрудников;
* с оборотом — от 10 до 800 млн. долларов;
* с потребностью в автоматизации от 25 до 500 рабочих мест одновременных пользователей (на практике существуют инсталляции до 1000 рабочих мест, тестовые инсталляции до 3600);
* имеющим специфические и сложные бизнес процессы;
* предприятиям с распределенной структурой, холдингам, дистрибьюторским компаниям, производственным предприятиям, компаниям, работающим в сфере услуг и др.


Я работал над системой, автоматизирующей 30 000 рабочих мест. Сейчас — 3000-10000 (в зависимости от филлиала, коих около десятка).
Всё познаётся в сравнении.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 20:56
Оценка:
Здравствуйте, VGn, Вы писали:

T>>А почему Axapta не является крупной системой?

T>>Я знаю что в России есть предприятия на которых она используется на наскольких тысячах рабочих мест + бизнес логика там весьма не простая.
T>>Ты считаешь это не крупная система?

VGn>

VGn>С точки зрения структуры предприятия и масштабов бизнеса, Axapta лучше всего подходит компаниям:
VGn> * численностью до 10 000 сотрудников;
VGn> * с оборотом — от 10 до 800 млн. долларов;
VGn> * с потребностью в автоматизации от 25 до 500 рабочих мест одновременных пользователей (на практике существуют инсталляции до 1000 рабочих мест, тестовые инсталляции до 3600);
VGn> * имеющим специфические и сложные бизнес процессы;
VGn> * предприятиям с распределенной структурой, холдингам, дистрибьюторским компаниям, производственным предприятиям, компаниям, работающим в сфере услуг и др.


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

VGn>Я работал над системой, автоматизирующей 30 000 рабочих мест. Сейчас — 3000-10000 (в зависимости от филлиала, коих около десятка).


Само количество абсолютно ничего не говорит. Сложности бизнес-логики тоже важна.
Re[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 21:01
Оценка:
Здравствуйте, VGn, Вы писали:

VGn>На протяжении всего обсуждения было несколько твоих отсылок только к одной (как я понял) книге Фаулера. Причём той, ценность которой мне лично не очевидна.

VGn>Я имею в виду Patterns of Enterprise Application Architecture, содержание которой в общем нареканий не вызывает. Сомнительно только слово Enterprise.

Я не знаю аналогов Фаулеру, в котором бы в такой же степени покрывались бы вопросы разработки корпоративных приложений.
Если есть что-то подобное на слуху, было бы интересно узнать.
Re[12]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 21:22
Оценка:
T>Тем не менее есть преценденты внедрения на несколько тысяч мест. Внедрял Корус-Консалтинг. Какой-то трубный завод на урале, кажется.

1С тоже пытаются внедрять в больших корпорациях. И что? Она после этого становится масштабируемой?

VGn>>Я работал над системой, автоматизирующей 30 000 рабочих мест. Сейчас — 3000-10000 (в зависимости от филлиала, коих около десятка).


T>Само количество абсолютно ничего не говорит. Сложности бизнес-логики тоже важна.


А вот на этом я и сам хотел сделать упор
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[10]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 21:22
Оценка:
T>Я не знаю аналогов Фаулеру, в котором бы в такой же степени покрывались бы вопросы разработки корпоративных приложений.
T>Если есть что-то подобное на слуху, было бы интересно узнать.

Как-то даже сложно с аналогами. Потому что как раз о корпоративных приложениях я там ничего не нашёл.
Трудно назвать корпоративным приложение, в котором смешиваются воедино уровень доступа к данным, Domain уровень, уровень сервисной бизнес-логики и ещё всего помаленьку.
А для ваших настольных систем — это вполне себе как раз. Только Enterprise тут ни при чём.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[16]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 06.01.09 21:49
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>Еще раз. Не путайте суть и форму. Форма будет одинаковая: классы, объекты, интерфесы, наследование. При ООП подходе у вас будет императивный код работы с объектами. При ER — декларативный код работы с сущностями.

T>>>Ок. Я понял, под er вы подразумеваете не er-модель. Проехали.
G>>А что вы подразумеваете под ER моделью в программе?

T>Под ER-моделью я, как ни странно, понимаю ER-модель

Круто. А как это использовать в программе?
Вы вообще представляете то о чем спор ведете?

T>Ясно. Я использовал такой подход в простых сценариях, когда при определенных условиях нужно было применять дополнительное условие.

T>Но такой подход не всегда применим. В частности, в проекте на котором я сейчас работаю настройки безопасноти (привелегии) хранятся во внешней базе.
Ну это надуманные проблемы. Всегда есть view, linked servers и прочее. Только далеко не все могут нормальную интеграцию баз сдеать на уровне БД. Гораздо проще сделать в коде приложения, а потом рассказывать что это "непрстой сценарий" и прочее.


T>>>То есть каждому пользователю давать свой логин в базе? Ты в курсе, что так делать не рекомендуют?

G>>Нет, есть таблица, хранящая логины и другие сведения о пользователях. В логах можно ссылкаться на эту таблицу.

T>А как определить текущего пользователя?

Разве вы в программе в кажом месте не можете определить текущего пользователя (логин\id\что_нибудь_еще)?

T>>>Такие тесты работать будут часами. Главное требование к юнит-тесту — это то, что он работает оч. быстро. Станет работать медленно, никто их запускать не будет. На себе проверено.

G>>Вам не потребуется эти тесты запускать в совокупноти с unit-тестами приложения. Аудит в БД полностью ортогонален бизнес-логике в коде приложения.

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

Тесты базы будут запускаться при разработке БД. С тестированием кода приложения они не связаны. Пусть build-система на сервере гоняет такие тесты хоть каждые 5 минут, каждому разработчику делать тоже самое необязательно.

G>>>>Вы не поняли. Действительно можно будет выполнить ВСЕ запросы в одной транзакции. При использовании ОРМ придется сделать выборку в одной транзакции, а потом коммит в другой.

T>>>Это еще почему?
G>>Потому что реализация такая. Linq2SQL и EF так работают.
T>Открывай TransactionScope и будет одна транзакция. Или я опять что-то не понимаю?
См ниже.

G>>>>Можно явно объявить TransactionScope, но тогда её придется явно завершить после вызова SaveChanges.

T>>>Это сложно?
G>>Это сложнее чем ОДИН раз явно обявить транзакцию при использовании запросов.
T>Все равно не вкуриваю. Код с TransactionScope — правтически один-в-один с приводимым тобой кодом. В чем отличие-то?

С запросами, теоретически
using (context.Batch())
{
  var q = from ...
  update ...
  delete ...
}//Непосредственное выполнение начинается здесь


Без запросов, как сейчас
using(var ts = new TransactionScope())
{
  var q = from ...
  foreach(var e in q) //Материализация запросва, блокировка удерживается
  {
    //Какие-то действия
  }  

  //Две строчки надо еще не перепутать
  context.SaveChanges(); //Сохранение изменений
  ts.Commit();
}

Во втором блоке 2 строчки нужно выполнить.

G>>>>При материализации последнего запроса вылетит ошибка и транзакция будет откачена если остатки ушли в минус, а кастомер не VIP.


T>>>То есть сначала мы пишем в базу, а потом валидируем? Оригинально

G>>При таком подходе ВСЯ работа с данными происходит в БД, это нормально.

T>БД — это всегда узкое место. Если есть возможность делать проверки в бизнесе, они болжны быть сделаны в бизнесе. Неужели эти банальности нужно повторять?

Эти "банальности" еще нужно доказать.
Сама по себе БД — не узкое место, узкое мето — передача данных от БД к приложению и назад. Именно эту передачу и предлагают сократить.
Кстати при работе с embedded базами данных "правила игры" меняются.

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

Вы обработку бизнес-логики распараллеливаете?

T>>>Это точно ты говорил, что материализация плохо отражается на перформансе?

G>>Это так и есть.
T>И как это сочетается с тем, что валидацию ты возлагаешь на базу, когда ее можно сделать в бизнесе, что дешевле?
Что значит "дешевле"?
При правильном подходе возлагать работу с данными на БД даст огромный прирос производительности.
Сравните например например выполнение запроса типа "увеличить скидку всем VIP кастомерам скиду на все заказы прошлого года на 3 процента" с выполнением тогоже самого с помощью ORM.

T>>>P.S. На самом деле то, что вы описываете, до боли напоминает transaction script как он назван у Фаулера. Единственное отличие, которое я вижу — это его типизированность. В той же книжке описывается почему с ростом сложности приложения с transaction script-ом становится сложно жить. Рекомендую глянуть, если еще не смотрели.

G>>Я уже форуме "архитектура" про фаулера отписал. Повторюсь здесь.
G>>Концептуальная разница между transaction script и dimain model состоит в том как вы хотите вызывать методы бизнес-логики
G>>Так
G>>
G>>entity.Operation(params)
G>>

G>>или так
G>>
G>>service.Operation(entity, params)
G>>

G>>Второй подход гораздо лучше по многим причинам.

T>Сервисы не отрицают domain model, а дополняют ее.

T>Развитая доменная модель позволяет защитить целостность данных в доменной модели и сделать код более читаемым, близким к предметной области.

Звучит как молитва какая-то.

G>>А фаулер какю-то неправильную траву курит.


T>Да они там все такие :

Да вот не все. App Arch Guide 2.0 почитайте.
Re[8]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 06.01.09 22:04
Оценка:
Здравствуйте, Tissot, Вы писали:

T>>>Почему вариант с update/insert будет иметь меньшее кол-во блокировок?

IB>>Он будет держать их меньшее время и блокировки будут поддаваться большему контролю.

T>Я же привел пример:

T>1. делаем update 1 поля
T>2. долго что-то считаем
T>3. делаем следующий update

T>Не мог бы ты оставаясь в рамках этого примера описать, откуда возникнет "меньшее время" и "больший контроль"?


Если расчеты в п2 не зависят от апдейта в п1, то сначала выполняем расчеты (не ставим эксклюзивные блокировки), потом формируем 2 апдейта и выполняем их в БД.
Если расчеты в п2 зависят от апдейта в п1, то выделяем независимую часть расчетов из п2 и выполняем, потом выполняем апдейт, зависимую от апдейта часть расчетов (гораздо быстрее), мерджим с независимой, выполняем второй апдейт.
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 22:27
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Под ER-моделью я, как ни странно, понимаю ER-модель

G>Круто. А как это использовать в программе?

Собственно ER модель мапится в объектную очень легко. Практически один в один.

G>Вы вообще представляете то о чем спор ведете?


Пока что я пытаюсь выяснить что вы имели в виду под ER-моделью. Пока что выяснилось, что ваша ER-модель != ER-модели как ее представлет википедия.

T>>Ясно. Я использовал такой подход в простых сценариях, когда при определенных условиях нужно было применять дополнительное условие.

T>>Но такой подход не всегда применим. В частности, в проекте на котором я сейчас работаю настройки безопасноти (привелегии) хранятся во внешней базе.
G>Ну это надуманные проблемы. Всегда есть view, linked servers и прочее. Только далеко не все могут нормальную интеграцию баз сдеать на уровне БД. Гораздо проще сделать в коде приложения, а потом рассказывать что это "непрстой сценарий" и прочее.

И как view и linked servers ты собрался вписать в LINQ-подход?

T>>>>То есть каждому пользователю давать свой логин в базе? Ты в курсе, что так делать не рекомендуют?

G>>>Нет, есть таблица, хранящая логины и другие сведения о пользователях. В логах можно ссылкаться на эту таблицу.

T>>А как определить текущего пользователя?

G>Разве вы в программе в кажом месте не можете определить текущего пользователя (логин\id\что_нибудь_еще)?

В программе — могу. А вот как это сделать это в триггере для меня не ясно. Если вы знаете, буду благодарен если просвятите.

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

G>Тесты базы будут запускаться при разработке БД. С тестированием кода приложения они не связаны. Пусть build-система на сервере гоняет такие тесты хоть каждые 5 минут, каждому разработчику делать тоже самое необязательно.

Э, нет, так не пойдет. Код не должен выкладываться в репозитарий если он не прошел тесты.

G>>>>>Вы не поняли. Действительно можно будет выполнить ВСЕ запросы в одной транзакции. При использовании ОРМ придется сделать выборку в одной транзакции, а потом коммит в другой.

T>>>>Это еще почему?
G>>>Потому что реализация такая. Linq2SQL и EF так работают.
T>>Открывай TransactionScope и будет одна транзакция. Или я опять что-то не понимаю?
G>См ниже.

G>>>>>Можно явно объявить TransactionScope, но тогда её придется явно завершить после вызова SaveChanges.

T>>>>Это сложно?
G>>>Это сложнее чем ОДИН раз явно обявить транзакцию при использовании запросов.
T>>Все равно не вкуриваю. Код с TransactionScope — правтически один-в-один с приводимым тобой кодом. В чем отличие-то?

G>С запросами, теоретически

G>
G>using (context.Batch())
G>{
G>  var q = from ...
G>  update ...
G>  delete ...
G>}//Непосредственное выполнение начинается здесь
G>


G>Без запросов, как сейчас

G>
G>using(var ts = new TransactionScope())
G>{
G>  var q = from ...
G>  foreach(var e in q) //Материализация запросва, блокировка удерживается
G>  {
G>    //Какие-то действия
G>  }  

G>  //Две строчки надо еще не перепутать
G>  context.SaveChanges(); //Сохранение изменений
G>  ts.Commit();
G>}
G>

G>Во втором блоке 2 строчки нужно выполнить.

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

T>>БД — это всегда узкое место. Если есть возможность делать проверки в бизнесе, они болжны быть сделаны в бизнесе. Неужели эти банальности нужно повторять?

G>Эти "банальности" еще нужно доказать.
G>Сама по себе БД — не узкое место, узкое мето — передача данных от БД к приложению и назад. Именно эту передачу и предлагают сократить.

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

G>Содержание бизнес-логики в коде приложения выгодно не с точки зрения перформанса, а с точки зрения стоимости поддрежки. Но при работе с запросами логика остается в коде приложения, меняется только место исполнения.

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

А где я предлагал кэшировать/управлять блокировками/управлять конкурентным доступом в приложении?

G>Вы обработку бизнес-логики распараллеливаете?


В каком-то смысле да, есть некий самописный типа-воркфлоу. Но он к работе с базой не относится.

G>>>Это так и есть.

T>>И как это сочетается с тем, что валидацию ты возлагаешь на базу, когда ее можно сделать в бизнесе, что дешевле?
G>Что значит "дешевле"?

Быстрее, будет потреблять меньше ресурсов,

G>При правильном подходе возлагать работу с данными на БД даст огромный прирос производительности.


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

G>Сравните например например выполнение запроса типа "увеличить скидку всем VIP кастомерам скиду на все заказы прошлого года на 3 процента" с выполнением тогоже самого с помощью ORM.


Про массовые update-ы я писал. Тут все ясно, согласен на все 100.

T>>Сервисы не отрицают domain model, а дополняют ее.

T>>Развитая доменная модель позволяет защитить целостность данных в доменной модели и сделать код более читаемым, близким к предметной области.

G>Звучит как молитва какая-то.


Воздастся каждому по вере его.

G>>>А фаулер какю-то неправильную траву курит.

T>>Да они там все такие :
G>Да вот не все. App Arch Guide 2.0 почитайте.

Спасибо, почитаю.
Читал предыдущую версию. Неужели что-то коренным образом изменилось?
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 22:31
Оценка:
Здравствуйте, VGn, Вы писали:

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


VGn>1С тоже пытаются внедрять в больших корпорациях. И что? Она после этого становится масштабируемой?


Я не знаю как сейчас, но на тот момент (где-то 5 лет назад) 1С на такое кол-во пользователей даже и не пытались внедрить.

VGn>>>Я работал над системой, автоматизирующей 30 000 рабочих мест. Сейчас — 3000-10000 (в зависимости от филлиала, коих около десятка).


T>>Само количество абсолютно ничего не говорит. Сложности бизнес-логики тоже важна.


VGn>А вот на этом я и сам хотел сделать упор


А вы прямым текстом говорите, что хотите сказать.
Если вы считаете, что Axapta — простой продукт, то хотелось бы мне посмотреть на то, что является по вашему мнению сложным.
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 22:36
Оценка:
Здравствуйте, VGn, Вы писали:

VGn>Как-то даже сложно с аналогами. Потому что как раз о корпоративных приложениях я там ничего не нашёл.

VGn>Трудно назвать корпоративным приложение, в котором смешиваются воедино уровень доступа к данным, Domain уровень, уровень сервисной бизнес-логики и ещё всего помаленьку.

У вас какой-то неправильный Фаулер. У моего такого смешения не наблюдается.

VGn>А для ваших настольных систем — это вполне себе как раз. Только Enterprise тут ни при чём.


Ваш ход сударь. Какие подходы рулять в тру-Enterprise приложениях?
Пожалуйста с сылочками на что-то большее чем блог Ивана Ивановича Иванова.
Re[18]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 23:06
Оценка:
T>Нет, ты не предлагаешь сократить передечу в базу. В твоем сценарии данные сначала пишутся в базу, а потом валидируются. То есть даже невалидные данные ты передаешь. И где тут сокращение?

Всё зависит от логики валидации.
Если валидируется формат, то это можно сделать и на уровне отображения.
Если логическая нестыковка — то в бизнес-логике.
Если конфликт с существующими данными или конфликт транзакций, то только на базе.
Причём имхо это всё не жёсткие условия. Всё зависит от архитектуры системы.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[12]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 06.01.09 23:23
Оценка:
T>У вас какой-то неправильный Фаулер. У моего такого смешения не наблюдается.
Я делал вывод по примерам кода в книге. К сожалению читал это очень давно и специально для вас рыть больше не охота.

VGn>>А для ваших настольных систем — это вполне себе как раз. Только Enterprise тут ни при чём.


T>Ваш ход сударь. Какие подходы рулять в тру-Enterprise приложениях?


Обычные подходы. Многозвенность. Многослойность. Может быть больший упор на сервисы.
Долгоживущие объекты не приветствуются. Запросы возвращают минимально-необходимые наборы данных. Избыточность функциональности не приветствуется. Модульность и расширяемость — наше всё.
В общем всё также, только строже и с упором на масштабируемость.

T>Пожалуйста с сылочками на что-то большее чем блог Ивана Ивановича Иванова.


Не получится. Обычно такие вещи конфиденциальны.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 06.01.09 23:37
Оценка:
Здравствуйте, VGn, Вы писали:

T>>У вас какой-то неправильный Фаулер. У моего такого смешения не наблюдается.

VGn>Я делал вывод по примерам кода в книге.

Зря, если бы читали, то таких выводов бы не делали.

VGn>К сожалению читал это очень давно и специально для вас рыть больше не охота.


Почему-то не удивлен.

VGn>>>А для ваших настольных систем — это вполне себе как раз. Только Enterprise тут ни при чём.


T>>Ваш ход сударь. Какие подходы рулять в тру-Enterprise приложениях?


VGn>Обычные подходы. Многозвенность. Многослойность. Может быть больший упор на сервисы.

VGn>Долгоживущие объекты не приветствуются. Запросы возвращают минимально-необходимые наборы данных. Избыточность функциональности не приветствуется. Модульность и расширяемость — наше всё.

В общем-то никаких принципиальных отличий от Фаулера при первом просмотре и нет.

VGn>В общем всё также, только строже и с упором на масштабируемость.


T>>Пожалуйста с сылочками на что-то большее чем блог Ивана Ивановича Иванова.


VGn>Не получится. Обычно такие вещи конфиденциальны.


Re[14]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 07.01.09 00:17
Оценка:
T>>>У вас какой-то неправильный Фаулер. У моего такого смешения не наблюдается.
VGn>>Я делал вывод по примерам кода в книге.
T>Зря, если бы читали, то таких выводов бы не делали.

Читал. Просто примеры вызвали более явное отторжение.

VGn>>В общем всё также, только строже и с упором на масштабируемость.

T>>>Пожалуйста с сылочками на что-то большее чем блог Ивана Ивановича Иванова.
VGn>>Не получится. Обычно такие вещи конфиденциальны.
T>

По вопросу примеров корпоративного кода это практически стандартный ответ на форуме.
Да и смотреть там в общем и нечего: архитектуру по коду не понять, тем более что на уровне кода абсолютно все достаточно здоровые корпоративные системы, которые я видел, написаны через жопу (конечно я не имею в виду свой собственный код и код своей команды )
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[14]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 07.01.09 05:38
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Да чего там объяснять-то? Влом Фаулера переписывать.

Ты на Фаулера не кивай. У тебя свои-то мысли есть? =)
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[6]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 07.01.09 05:38
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Меня несколько смутило, что insert-ы, да update-ы относят к реляционным операторам. Теперь ясно что имелось в виду другое. Проехали.

То есть, просто искал к чему бы придраться. ок, проехали.. =)

T>Раз уж мы аппелируем к большинству, то это большинство какраз-таки пользуется разными Hibernate-ами вовсю.

Во-первых H — это не OOBD, во-вторых, H можно использовать очень по разному ну и, наконец, в третих, "большинство" — это тоже сильное преувеличение.

T>Наследование. Отношения многие ко многим.

Это все отлично выражается в ER, стыдно не знасть.

T>Методы. Интерфейсы.

А это вообще никакого отношения к данным не имеет.

T>См. Фаулера. Перепечатывать цитаты я не буду.

Ты на фаулера не кивай, с ним уже разобрались. У тебя свои-то мысли есть?

T>Большое количество однородных объектов. В качества примера можно привести например миграцию данных с одной схемы базы на другую.

Тогда ты фигню сказал. UoW сливает везде, где обьектов больше одного.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[18]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 07.01.09 05:38
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Спасибо за развернутый и аргуметированный ответ.

Я стараюсь соответствовать оппоненту..

T>Вы раскрыли мне глаза.

Всегда пожалуйста, заходите еще..
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[18]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 07.01.09 08:12
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Под ER-моделью я, как ни странно, понимаю ER-модель

G>>Круто. А как это использовать в программе?
T>Собственно ER модель мапится в объектную очень легко. Практически один в один.
Ну вот и я о томже. Обекты — форма, ER — суть. При маппинге ER на объекты у вас не появятся виртуальные методы и все такое, то есть не будет полновесного ООП.

G>>Вы вообще представляете то о чем спор ведете?

T>Пока что я пытаюсь выяснить что вы имели в виду под ER-моделью. Пока что выяснилось, что ваша ER-модель != ER-модели как ее представлет википедия.
Да, я имею ввиду использование этой модели в программе.

T>>>Ясно. Я использовал такой подход в простых сценариях, когда при определенных условиях нужно было применять дополнительное условие.

T>>>Но такой подход не всегда применим. В частности, в проекте на котором я сейчас работаю настройки безопасноти (привелегии) хранятся во внешней базе.
G>>Ну это надуманные проблемы. Всегда есть view, linked servers и прочее. Только далеко не все могут нормальную интеграцию баз сдеать на уровне БД. Гораздо проще сделать в коде приложения, а потом рассказывать что это "непрстой сценарий" и прочее.

T>И как view и linked servers ты собрался вписать в LINQ-подход?

Никак, это все делается на уровне БД. А Linq2SQL\EF уже работает с таблицами и вьюхами в одной БД.

T>>>>>То есть каждому пользователю давать свой логин в базе? Ты в курсе, что так делать не рекомендуют?

G>>>>Нет, есть таблица, хранящая логины и другие сведения о пользователях. В логах можно ссылкаться на эту таблицу.

T>>>А как определить текущего пользователя?

G>>Разве вы в программе в кажом месте не можете определить текущего пользователя (логин\id\что_нибудь_еще)?

T>В программе — могу. А вот как это сделать это в триггере для меня не ясно. Если вы знаете, буду благодарен если просвятите.

Я бы с таком случае сделал в таблицах поля Owner и LastModifiedBy. Триггеры из них достанут нужную инфу.

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

G>>Тесты базы будут запускаться при разработке БД. С тестированием кода приложения они не связаны. Пусть build-система на сервере гоняет такие тесты хоть каждые 5 минут, каждому разработчику делать тоже самое необязательно.

T>Э, нет, так не пойдет. Код не должен выкладываться в репозитарий если он не прошел тесты.

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


T>>>БД — это всегда узкое место. Если есть возможность делать проверки в бизнесе, они болжны быть сделаны в бизнесе. Неужели эти банальности нужно повторять?

G>>Эти "банальности" еще нужно доказать.
G>>Сама по себе БД — не узкое место, узкое мето — передача данных от БД к приложению и назад. Именно эту передачу и предлагают сократить.

T>Нет, ты не предлагаешь сократить передечу в базу. В твоем сценарии данные сначала пишутся в базу, а потом валидируются. То есть даже невалидные данные ты передаешь. И где тут сокращение?

Сокращения в том что данные из базы вообще не тянутся в приложение.

G>>Содержание бизнес-логики в коде приложения выгодно не с точки зрения перформанса, а с точки зрения стоимости поддрежки. Но при работе с запросами логика остается в коде приложения, меняется только место исполнения.

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

T>А где я предлагал кэшировать/управлять блокировками/управлять конкурентным доступом в приложении?

А вы UoW не предлагали? В нем часто заключается и кеширование, и управление блокировками.


G>>>>Это так и есть.

T>>>И как это сочетается с тем, что валидацию ты возлагаешь на базу, когда ее можно сделать в бизнесе, что дешевле?
G>>Что значит "дешевле"?
T>Быстрее, будет потреблять меньше ресурсов,
Именно все делать в базе окажется дешевле.

G>>При правильном подходе возлагать работу с данными на БД даст огромный прирос производительности.

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

G>>Сравните например например выполнение запроса типа "увеличить скидку всем VIP кастомерам скиду на все заказы прошлого года на 3 процента" с выполнением тогоже самого с помощью ORM.

T>Про массовые update-ы я писал. Тут все ясно, согласен на все 100.
Даже в случае одного такого апдейта простой запрос выполнится быстрее.

T>Спасибо, почитаю.

T>Читал предыдущую версию. Неужели что-то коренным образом изменилось?
Там изначально меньша каши чем у фаулера.
Re[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 12:51
Оценка:
Здравствуйте, IB, Вы писали:

T>>Я довольно регулярно слежу за тенденциями в этой сфере. И мне как-то последние годов несколько очень редко попадаются апологеты подхода "запихнем все в базу". Все больше как-то говорят за полноценную domain model.

IB>"запихнем все в базу" и domain model — это ортогональные вещи, так что довольно странно слышать подобные заявления от человека, который "регулярно следит за тенденциями в этой сфере".

Да ну? Как это они могут выть ортогональными, если вопрос по сути является вопросом о том, куда помещать бизнес-логику. Тут уж либо он в базах/запросах, либо в domain model.

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

IB>Да-да, мыши плакали, кололись, но продолжали жрать кактус.

А в это время другие мыши пробуют все вокруг, не подозревая даже о том, что кто-то им от души подсыпал крысиного яда. Удачи.

T>>В сухом остатке получаем, что подход с domain model более "проработан" чем иные.

T>>Это тоже будешь считать более хлипким аргументом?
IB>Безусловно, так как народ уже начинает понимать, какой это фуфел.

Мне не уловить ход твоих мыслей. Как из проработанности следует что это является фуфелом?

IB>Апофигеем того, что ты понимаешь под domain model был EJB, который, пользуясь твоим любимым аргументом, де-факто, считается провальным.


Не, EJB был оверкилом, он как раз сильно ограничивал возможности использования ООП.

T>>Не мог бы ты оставаясь в рамках этого примера описать, откуда возникнет "меньшее время" и "больший контроль"?

IB>Почему это я должен оставаться в рамках твоего примера, если ты не хочешь? В реальной жизни, никто не занимается длинными вычислениями между двумя update-ами, все тяжелые вещи делаются заранее или задача вообще решается иным способом.

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

T>>Что тебя так развеселило? Расскажи, вместе посмеемся.

IB>Дешевые понты всегдя выглядят забавно.. )

Я правильно тебя понимаю, что ты не считаешь упомянутую мною Axapta крупным приложением? А что по твоему мнению ты относишь к числу таковых?
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 13:09
Оценка:
Здравствуйте, IB, Вы писали:

T>>Потому что update

IB>Если это один update, то там не может быть никаких длинных вычислений.

update не один. смотри выше постановку задачи.

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

IB>А ты чем занимаешься? Просто в эту игру можно играть в обе стороны

Я не меняю условия задачи. Вариант, когда в одной бизнес-операции выполняются несколько update-ов одной сущности считаю вполне жизненным.

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

IB>Выполняет, конечно последовательно, но информации ему хватает, за подробностями к учебникам по СУБД.

Не, так легко ты не отделаешься. Учебников мною прочитано предостаточно, но информации о том, чтобы СУБД отпускала блокировки до окончания танзакции, я слышу в первый раз.

T>>Ключевое слово выделено. А на практике?

IB>А на практике этого еще не сделано, о чем и писал Влад.

ok

T>>А как еще назвать ситуацию, когда в качестве аргумента приводят код, который в жизни практически не встречается?

IB>Задача стояла не показать тебе реальный код, а проиллюстрировать идею.

Ну идея сама по себе была ясна и из первого поста

T>>Приведенный код был слишком простым, чтобы на его примере увидить недостатки подхода "делаем все одним update-ом". Де-факто этот единственный update потребует как минимум проверку валидности, проверку безопасности, аудит действий и т.д. Если бы все эти сервисные операции были включены в пример, то его красота сразу бы куда-то улетучилась.

IB>В том-то и дело, что не улетучилась бы, если использовать подход LINQ, в чем и был поинт оригинального сообщения.

Делайте, посмотрим. Если на добавление LINQ-а у разработчиков Nemerle ушло (по их заявлениям) совсем не много времени, то добавить insert-ы с update-ами будет не намного сложнее.

T>> Ну или по-крайней мере объясни откуда возьмется этот больший контроль.

IB>Оттуда, что все делается явно, без Lazy Loading-ов,

Используйте ef

IB>неявных кешей,


Кэш неявный только когда ты о нем не знаешь. Изучайте получше инструмент, которым пользуетесь.

IB>траверсивных запросов и прочих ритуальных приседаний.


Траверсивных?
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 13:30
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Если расчеты в п2 не зависят от апдейта в п1, то сначала выполняем расчеты (не ставим эксклюзивные блокировки), потом формируем 2 апдейта и выполняем их в БД.

G>>>Если расчеты в п2 зависят от апдейта в п1, то выделяем независимую часть расчетов из п2 и выполняем, потом выполняем апдейт, зависимую от апдейта часть расчетов (гораздо быстрее), мерджим с независимой, выполняем второй апдейт.

T>>А можно не изменять условия задачи?

G>Никто не меняет условия, входные и выходные данные остаются. Вы почему-то пытаетесь доказать неправильность какого-то подхода через свое кривое решение. Если решение не кривое, то и подход оказывается вполне нормальным.

Это решение не кривое, а вполне себе жизненное. В сколь-нибудь крупном приложении никогда не бывает такого, что все связи видны и прозрачны.
Сегодня у тебя была какая-то одна задача, которую ты вполне успешно разбил на независимые (в том числе по данным) подзадачи и успешно решил, через полгода тебе или твоему коллеге приходит minor change request, в которым просят изменить что-то в логике первоначальной задачи. Это изменение будут затрагивать одну из подзадач первоначальной задачи. Но получится так, что в результате подзадачи перестанут быть независимыми по данным. У тебя будет два выхода, либо все отрефакторить во имя "правильного" подхода, либо внести изменения по месту и смириться с тем, что независимость по данным потеряна. Первый вариант гарантированно займет больше времени. Ваши действия, сударь?

Мне даже пример пришел в голову, все с тем же резервированием по накладной.

Первоначальная постановка:
По нажатию на кнопочку "Резерв." в форме заказа зарезервировать остатки на складе и послать во внешнюю систему (веб-сервис) запрос на упаковку.
Решение: задача разбивается на 2 более мелких: 1) изменить остатки 2) послать запрос на упаковку.

CR (через полгода):
При резервировании заказа заказ должен сохранять в одном из полей номер запроса на упаковку (номер возвращается веб-сервисом).
Re[19]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 13:55
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Ну это надуманные проблемы. Всегда есть view, linked servers и прочее. Только далеко не все могут нормальную интеграцию баз сдеать на уровне БД. Гораздо проще сделать в коде приложения, а потом рассказывать что это "непрстой сценарий" и прочее.


T>>И как view и linked servers ты собрался вписать в LINQ-подход?

G>Никак, это все делается на уровне БД. А Linq2SQL\EF уже работает с таблицами и вьюхами в одной БД.

Деталей, побольше деталей.
Я так понимаю, ты предлагаешь насоздавать в основной базе кучу вьюх, которые будут которые фактически будут таблицами в другой базе (security)? После этого, ты переносишь эти вьюхи в LINQ2SQL дизайнер и работаешь с ними стандартными способами, которые предоставляет LINQ? Я правильно тебя понял? Ничего не упустил?

Если это так, то имхо, это просто ужасный вариант.
Если предполагается использовать security базу в более чем одной подсистеме, то: такой подход порождает дублирование всех security-таблиц. Эти типы будут несовместимы меж собой. Нельзя будет написать для этих типов общий код. При внесении изменений в security-подсистему, эти изменения нужно будет нетривиальным способом переносить во все места, где она используется.

G>>>Разве вы в программе в кажом месте не можете определить текущего пользователя (логин\id\что_нибудь_еще)?


T>>В программе — могу. А вот как это сделать это в триггере для меня не ясно. Если вы знаете, буду благодарен если просвятите.

G>Я бы с таком случае сделал в таблицах поля Owner и LastModifiedBy. Триггеры из них достанут нужную инфу.

Эти поля тебе придется не забывать прописывать при всех изменениях. А если речь идет об удалении, то и вовсе — сначала обновить поле LastModifiedBy и только потом делать delete. В случае LINQ2SQL это вообще можно сделать прозрачно для польователя.

T>>Э, нет, так не пойдет. Код не должен выкладываться в репозитарий если он не прошел тесты.

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

Ответ неверный. Тесты должны запускаться всегда.

T>>Нет, ты не предлагаешь сократить передечу в базу. В твоем сценарии данные сначала пишутся в базу, а потом валидируются. То есть даже невалидные данные ты передаешь. И где тут сокращение?

G>Сокращения в том что данные из базы вообще не тянутся в приложение.

Зато они пишутся в базу. И далеко не факт, что это дешевле.

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


T>>А где я предлагал кэшировать/управлять блокировками/управлять конкурентным доступом в приложении?

G>А вы UoW не предлагали? В нем часто заключается и кеширование, и управление блокировками.

UoW не кэширует запросы, а только объекты, про управление блокировками вообще в первый раз слышу (или ты про optimistic locking?).
Что там насчет конкурентного доступа?

G>>>>>Это так и есть.

T>>>>И как это сочетается с тем, что валидацию ты возлагаешь на базу, когда ее можно сделать в бизнесе, что дешевле?
G>>>Что значит "дешевле"?
T>>Быстрее, будет потреблять меньше ресурсов,
G>Именно все делать в базе окажется дешевле.

Уверяю тебя, это далеко не вегда так. Проверить string.IsNullOrEmpty(customer.Name) да порядка три будет быстрее, чем запись customer.Name в базу.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 13:56
Оценка:
Здравствуйте, IB, Вы писали:

T>>Да чего там объяснять-то? Влом Фаулера переписывать.

IB>Ты на Фаулера не кивай. У тебя свои-то мысли есть? =)

По данному вопросу наши мысли совпадают
Re[10]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 07.01.09 13:59
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Да ну?

Ну да.

T> Как это они могут выть ортогональными, если вопрос по сути является вопросом о том, куда помещать бизнес-логику.

Это с чего это ты взял? Куда помещать бизнес-логику совершенно не зависит от того, используешь ты domain model или нет. И помимо domain model существует множество других подходов к архитектуре, где логика может быть как в БД, так и вне ее. Стыдно такое не знать, человеку регулярно следящему за тенденциями. =)

T>Тут уж либо он в базах/запросах, либо в domain model.

Так, ты что под domain model понимаешь?

T>А в это время другие мыши пробуют все вокруг, не подозревая даже о том, что кто-то им от души подсыпал крысиного яда. Удачи.

Что-то я не заметил, что ты все вокруг пробуешь, ты, похоже, где-то серебряную пулю откопал.. )

T>Мне не уловить ход твоих мыслей. Как из проработанности следует что это является фуфелом?

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

T>Не, EJB был оверкилом, он как раз сильно ограничивал возможности использования ООП.

Он то, как раз, был пожалуй самым "ООП" шным, в том виде, как принято понимать ООП. Ну и наелись в результате..

T>В реальной жизни ты разбиваешь задачи на долее мелкие и дашь их разным людям и не факт, что исполнитель второй задачи будет знать, что те данные, которые он меняет, были изменены чуть выше по коду первым исполнителем.

То есть, у тебя один разработчик пишет начало транзакции, а другой ее коммитит?

T>Я правильно тебя понимаю, что ты не считаешь упомянутую мною Axapta крупным приложением? А что по твоему мнению ты относишь к числу таковых?

Я не считаю Аксапту ни крупным приложением, ни образцом правильно спроектированного приложения, и ее упоминание вообще ни как не относится к теме данного разговора, если ты сам не учавствовал именно в разработке самой Аксапты, причем в роли человека принимающего ключевые решения в архитектуре.
А-то, так я тоже могу заявить, что мы с Антоном(Sinclair) уже много лет носим гордое звание Microsoft MVP в компетенции Solution Architect, и только на этом основании давить тебя своим авторитетом и опытом. Но очевидно, что ни к какому конструктиву это не приведет.
Поэтому такого рода аргументацию я и называю дешевыми понтами.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[16]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 07.01.09 14:00
Оценка:
Здравствуйте, Tissot, Вы писали:

T>По данному вопросу наши мысли совпадают

Просто у тебя свои не получается сформулировать.. Ок, понятно, но что же ты тогда спорить полез? =)
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[7]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 14:06
Оценка:
Здравствуйте, IB, Вы писали:

T>>Раз уж мы аппелируем к большинству, то это большинство какраз-таки пользуется разными Hibernate-ами вовсю.

IB>Во-первых H — это не OOBD, во-вторых, H можно использовать очень по разному ну и, наконец, в третих, "большинство" — это тоже сильное преувеличение.

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

T>>Наследование. Отношения многие ко многим.

IB>Это все отлично выражается в ER, стыдно не знасть.

Наследование само по себе (без наличия виртуальных методов) ценности не несет.
Многие-ко-многим выражается через два отношения один-ко-многим. С этим элементарно неудобно работать

T>>Методы. Интерфейсы.

IB>А это вообще никакого отношения к данным не имеет.

Зато имеет к ООП.

T>>Большое количество однородных объектов. В качества примера можно привести например миграцию данных с одной схемы базы на другую.

IB>Тогда ты фигню сказал. UoW сливает везде, где обьектов больше одного.

Чушь.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 14:11
Оценка:
Здравствуйте, IB, Вы писали:

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

IB>Вполне. Но во-первых это совсем не означает, что будет именно одна БД транзакция, а во-вторых никто не заставляет делать между этими изменениями тяжелые вычисления.

Я привел пример в другой ветке.

T>>Не, так легко ты не отделаешься. Учебников мною прочитано предостаточно, но информации о том, чтобы СУБД отпускала блокировки до окончания танзакции, я слышу в первый раз.

IB>Значит фигово читал. Это умеют делать все СУБД, в зависимости от уровня изоляции, а например MSSQL умеет вообще не накладывать блокировки при выполнении стейтмента в RC — оптимизация такая.

Можно подкрепить высказывание ссылочкой? Спасибо.

IB>Вообще современные СУБД довольно продвинутые конструкции и наивно было бы полагать, что ты сумеешь справиться лучше.


Я и не собираюсь справляться лучше. ORMapper в конечном итоге говорит и сервером на SQL, а значит все средства остаются в силе.

T>>Ну идея сама по себе была ясна и из первого поста

IB>Складывается впечатление, что не очень.. )

Ясна.

T>>Используйте ef

IB>Что мне это даст, кроме возни с тремя моделями, вместо одной?

Отсутствие ленивой загрузки.

T>>Кэш неявный только когда ты о нем не знаешь.

IB>Тогда, когда у меня нет над ним явного контроля.

Над чем у тебя нет явного контроля в том же LINQ2SQL-е. Он же тупой как пробка. Не над чем там контроль держать.
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 14:44
Оценка:
Здравствуйте, IB, Вы писали:

T>> Как это они могут выть ортогональными, если вопрос по сути является вопросом о том, куда помещать бизнес-логику.

IB>Это с чего это ты взял? Куда помещать бизнес-логику совершенно не зависит от того, используешь ты domain model или нет. И помимо domain model существует множество других подходов к архитектуре, где логика может быть как в БД, так и вне ее. Стыдно такое не знать, человеку регулярно следящему за тенденциями. =)

Ку так расскажи, а то все вокруг, да около. Или тоже секретная разработка?

T>>Тут уж либо он в базах/запросах, либо в domain model.

IB>Так, ты что под domain model понимаешь?

См. Фаулера, а лучше Evans-а.

T>>А в это время другие мыши пробуют все вокруг, не подозревая даже о том, что кто-то им от души подсыпал крысиного яда. Удачи.

IB>Что-то я не заметил, что ты все вокруг пробуешь, ты, похоже, где-то серебряную пулю откопал.. )

Ну если другие подходы не выдерживают критики, то приходится ограничиваться "серебрянной пулей"

T>>Не, EJB был оверкилом, он как раз сильно ограничивал возможности использования ООП.

IB>Он то, как раз, был пожалуй самым "ООП" шным, в том виде, как принято понимать ООП. Ну и наелись в результате..

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

T>>В реальной жизни ты разбиваешь задачи на долее мелкие и дашь их разным людям и не факт, что исполнитель второй задачи будет знать, что те данные, которые он меняет, были изменены чуть выше по коду первым исполнителем.

IB>То есть, у тебя один разработчик пишет начало транзакции, а другой ее коммитит?

А это вообще не суть важно. При использовании TransactionScope ты хоть каждый чих оборачивай в транзакцию. Коммит в базу все равно будет только после последнего самомго внешнего TransactionScope-а.

T>>Я правильно тебя понимаю, что ты не считаешь упомянутую мною Axapta крупным приложением? А что по твоему мнению ты относишь к числу таковых?

IB>Я не считаю Аксапту ни крупным приложением, ни образцом правильно спроектированного приложения, и ее упоминание вообще ни как не относится к теме данного разговора, если ты сам не учавствовал именно в разработке самой Аксапты, причем в роли человека принимающего ключевые решения в архитектуре.

Отлично. С удовольствием выслушаю от тебя какие приложения ты считаешь крупными.
По поводу упоминания Аксапты — поднимись выше по ветке и посмотри в каком контексте я ее упомянул.

IB>А-то, так я тоже могу заявить, что мы с Антоном(Sinclair) уже много лет носим гордое звание Microsoft MVP в компетенции Solution Architect, и только на этом основании давить тебя своим авторитетом и опытом. Но очевидно, что ни к какому конструктиву это не приведет.


Фига-се! Риспект и уважуха.

IB>Поэтому такого рода аргументацию я и называю дешевыми понтами.


Не было никаких понтов, честно-честно. Это был просто пример того, с чем я работал.
На тех проектах в качестве средств агрегации и анализа использовались не голый SQL, а OLAP-кубы. В этом весь поинт и был.
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 14:46
Оценка:
Здравствуйте, IB, Вы писали:

T>>По данному вопросу наши мысли совпадают

IB>Просто у тебя свои не получается сформулировать.. Ок, понятно, но что же ты тогда спорить полез? =)

Ведите себя прилично, не надо переходить на личности.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 14:55
Оценка:
Здравствуйте, VGn, Вы писали:

T>>Зря, если бы читали, то таких выводов бы не делали.


VGn>Читал. Просто примеры вызвали более явное отторжение.


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

VGn>По вопросу примеров корпоративного кода это практически стандартный ответ на форуме.

VGn>Да и смотреть там в общем и нечего: архитектуру по коду не понять, тем более что на уровне кода абсолютно все достаточно здоровые корпоративные системы, которые я видел, написаны через жопу (конечно я не имею в виду свой собственный код и код своей команды )

Кода не надо. Это неинтересно. Лучше какие-нибудь статьи про правильную по вашему мнению архитектуру.
Re[16]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 07.01.09 15:51
Оценка:
T>Кода не надо. Это неинтересно. Лучше какие-нибудь статьи про правильную по вашему мнению архитектуру.

Серебряной пули нет. Архитектура хороша тогда, когда она доказано хороша для вашего проекта. Просто нужно более ответственно относиться к декомпозиции бизнес-логики по уровням ответственности и более осторожно относиться ко всяческим прокси (Не наступайте на грабли MS. Они за вас шишку уже получили.)
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[8]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 07.01.09 16:26
Оценка:
T>>>Методы. Интерфейсы.
IB>>А это вообще никакого отношения к данным не имеет.
T>Зато имеет к ООП.

Значит всё-таки ООП — твой супермолоток?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[12]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 07.01.09 18:44
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>Если расчеты в п2 не зависят от апдейта в п1, то сначала выполняем расчеты (не ставим эксклюзивные блокировки), потом формируем 2 апдейта и выполняем их в БД.

G>>>>Если расчеты в п2 зависят от апдейта в п1, то выделяем независимую часть расчетов из п2 и выполняем, потом выполняем апдейт, зависимую от апдейта часть расчетов (гораздо быстрее), мерджим с независимой, выполняем второй апдейт.

T>>>А можно не изменять условия задачи?

G>>Никто не меняет условия, входные и выходные данные остаются. Вы почему-то пытаетесь доказать неправильность какого-то подхода через свое кривое решение. Если решение не кривое, то и подход оказывается вполне нормальным.

T>Это решение не кривое, а вполне себе жизненное. В сколь-нибудь крупном приложении никогда не бывает такого, что все связи видны и прозрачны.

Это такая отмазка не анализировать задачу и сделать все самым тупоголовым способом?

T>Сегодня у тебя была какая-то одна задача, которую ты вполне успешно разбил на независимые (в том числе по данным) подзадачи и успешно решил, через полгода тебе или твоему коллеге приходит minor change request, в которым просят изменить что-то в логике первоначальной задачи. Это изменение будут затрагивать одну из подзадач первоначальной задачи. Но получится так, что в результате подзадачи перестанут быть независимыми по данным. У тебя будет два выхода, либо все отрефакторить во имя "правильного" подхода, либо внести изменения по месту и смириться с тем, что независимость по данным потеряна. Первый вариант гарантированно займет больше времени. Ваши действия, сударь?

Ничего не понял, но ваши слова тронули меня до глубины души.

T>Мне даже пример пришел в голову, все с тем же резервированием по накладной.


T>Первоначальная постановка:

T>По нажатию на кнопочку "Резерв." в форме заказа зарезервировать остатки на складе и послать во внешнюю систему (веб-сервис) запрос на упаковку.
T>Решение: задача разбивается на 2 более мелких: 1) изменить остатки 2) послать запрос на упаковку.

T>CR (через полгода):

T>При резервировании заказа заказ должен сохранять в одном из полей номер запроса на упаковку (номер возвращается веб-сервисом).

Так это бизнес-транзация, к системным транзакциям, блокировкам и целостности данных отношения не имеет.

Варианты
1)В первоначальной задаче операция изменения остатков не зависит от результата выполнения запроса. Операции запускаются параллельно.
CR делает эти операции зависимыми, тогда сначала выполняется запрос (ниче не поделаешь, пользователю придется ждать), а потом сохранение данных.
Так как изменнеие остатков выполняется несколькими операциями insert и update, то это вполне можно сделать в одном батче без предварительного чтения и без длительного удержания блокировок.

2)В первоначальной задаче операция изменения остатков и выполнение запроса составляют бизнес-транзакцию. Тогда изначально будет сначала выполняться запрос, а потом изменнеие остатков. Для реализации CR в таком случае требуется только модифицировать запросы.
Re[20]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 07.01.09 19:07
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>Ну это надуманные проблемы. Всегда есть view, linked servers и прочее. Только далеко не все могут нормальную интеграцию баз сдеать на уровне БД. Гораздо проще сделать в коде приложения, а потом рассказывать что это "непрстой сценарий" и прочее.


T>>>И как view и linked servers ты собрался вписать в LINQ-подход?

G>>Никак, это все делается на уровне БД. А Linq2SQL\EF уже работает с таблицами и вьюхами в одной БД.

T>Деталей, побольше деталей.

T>Я так понимаю, ты предлагаешь насоздавать в основной базе кучу вьюх, которые будут которые фактически будут таблицами в другой базе (security)? После этого, ты переносишь эти вьюхи в LINQ2SQL дизайнер и работаешь с ними стандартными способами, которые предоставляет LINQ? Я правильно тебя понял? Ничего не упустил?
Именно как. Все детали вы уже назвали.

T>Если это так, то имхо, это просто ужасный вариант.

T>Если предполагается использовать security базу в более чем одной подсистеме, то: такой подход порождает дублирование всех security-таблиц.
Какой ужас... один скрипт в БД и все. Причем всегда одинаковый.

T>Эти типы будут несовместимы меж собой. Нельзя будет написать для этих типов общий код.

Какие типы? Вы вообще о чем?

T>При внесении изменений в security-подсистему, эти изменения нужно будет нетривиальным способом переносить во все места, где она используется.


Ну если у вас код выглядит так
var q = from ...
q = q.AddSecurityCheck(user);

то придется поменять в одном месте.
А проверяется наличие таких вызовов тестами.


G>>>>Разве вы в программе в кажом месте не можете определить текущего пользователя (логин\id\что_нибудь_еще)?


T>>>В программе — могу. А вот как это сделать это в триггере для меня не ясно. Если вы знаете, буду благодарен если просвятите.

G>>Я бы с таком случае сделал в таблицах поля Owner и LastModifiedBy. Триггеры из них достанут нужную инфу.
T>Эти поля тебе придется не забывать прописывать при всех изменениях. А если речь идет об удалении, то и вовсе — сначала обновить поле LastModifiedBy и только потом делать delete. В случае LINQ2SQL это вообще можно сделать прозрачно для польователя.
Только у вас будет 2 round-tripа до сервера.

Кстати только что дошло: при использовании запросов для изменнеий данных в БД, можно будет перехватывать процесс формирования батча и дописывать туда необходимые команды (например аудит и прочее). Как триггеры, только в BLL и без дополнительных запросов в базе, все делается в одном батче.

T>>>Э, нет, так не пойдет. Код не должен выкладываться в репозитарий если он не прошел тесты.

G>>Если вы не делаете изменений в базе, то можете не перезапускать тесты БД. Ничего там сломаться не может.
T>Ответ неверный. Тесты должны запускаться всегда.
Все тесты всегда запускаются build-системой, она железная, ей пофигу. Разработчики пусть запускают unit-тесты кода.

T>>>Нет, ты не предлагаешь сократить передечу в базу. В твоем сценарии данные сначала пишутся в базу, а потом валидируются. То есть даже невалидные данные ты передаешь. И где тут сокращение?

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

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


T>>>А где я предлагал кэшировать/управлять блокировками/управлять конкурентным доступом в приложении?

G>>А вы UoW не предлагали? В нем часто заключается и кеширование, и управление блокировками.
T>UoW не кэширует запросы, а только объекты, про управление блокировками вообще в первый раз слышу (или ты про optimistic locking?).
Вот именно про него. Но никакой optimistic locking не поддерживает предикатные блокировки и блокировки таблиц, поэтому фантомы вполне возможны.

G>>>>>>Это так и есть.

T>>>>>И как это сочетается с тем, что валидацию ты возлагаешь на базу, когда ее можно сделать в бизнесе, что дешевле?
G>>>>Что значит "дешевле"?
T>>>Быстрее, будет потреблять меньше ресурсов,
G>>Именно все делать в базе окажется дешевле.

T>Уверяю тебя, это далеко не вегда так. Проверить string.IsNullOrEmpty(customer.Name) да порядка три будет быстрее, чем запись customer.Name в базу.

Неверно. Вам как минимум придется прочитать из базы кастомера, чтобы проверить ему этот Name. Кроме того большенство элементарных проверок будут сделаны в PL, поэтому накладных расходов на такие проверки нету, да и база сама делает такую проверку на not null поля.
Re[21]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 21:29
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Если это так, то имхо, это просто ужасный вариант.

T>>Если предполагается использовать security базу в более чем одной подсистеме, то: такой подход порождает дублирование всех security-таблиц.
G>Какой ужас... один скрипт в БД и все. Причем всегда одинаковый.

Я имел в виду типы LINQ2SQL entity-ей или EF, если вы его используете.

T>>Эти типы будут несовместимы меж собой. Нельзя будет написать для этих типов общий код.

G>Какие типы? Вы вообще о чем?

Я имел в виду типы LINQ2SQL entity-ей или EF, если вы его используете.

T>>При внесении изменений в security-подсистему, эти изменения нужно будет нетривиальным способом переносить во все места, где она используется.


G>Ну если у вас код выглядит так

G>
G>var q = from ...
G>q = q.AddSecurityCheck(user);
G>

G>то придется поменять в одном месте.
G>А проверяется наличие таких вызовов тестами.

Вот реализация AddSecurityCheck как раз и поменяется.

G>>>Я бы с таком случае сделал в таблицах поля Owner и LastModifiedBy. Триггеры из них достанут нужную инфу.

T>>Эти поля тебе придется не забывать прописывать при всех изменениях. А если речь идет об удалении, то и вовсе — сначала обновить поле LastModifiedBy и только потом делать delete. В случае LINQ2SQL это вообще можно сделать прозрачно для польователя.
G>Только у вас будет 2 round-tripа до сервера.

Нет, для lastUpdated будет 1 раундтрип. Для удаления — да, два.

G>Кстати только что дошло: при использовании запросов для изменнеий данных в БД, можно будет перехватывать процесс формирования батча и дописывать туда необходимые команды (например аудит и прочее). Как триггеры, только в BLL и без дополнительных запросов в базе, все делается в одном батче.


Не получится. Если у тебя delete customer where type = 'vip', то либо в аудит-лог у тебя попадет только одна запись, либо ... Кажется второго варианта и нет.

T>>>>Нет, ты не предлагаешь сократить передечу в базу. В твоем сценарии данные сначала пишутся в базу, а потом валидируются. То есть даже невалидные данные ты передаешь. И где тут сокращение?

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

Если валидация не прошла, то не придется.

T>>>>А где я предлагал кэшировать/управлять блокировками/управлять конкурентным доступом в приложении?

G>>>А вы UoW не предлагали? В нем часто заключается и кеширование, и управление блокировками.
T>>UoW не кэширует запросы, а только объекты, про управление блокировками вообще в первый раз слышу (или ты про optimistic locking?).
G>Вот именно про него. Но никакой optimistic locking не поддерживает предикатные блокировки и блокировки таблиц, поэтому фантомы вполне возможны.

Понятно.

T>>Уверяю тебя, это далеко не вегда так. Проверить string.IsNullOrEmpty(customer.Name) да порядка три будет быстрее, чем запись customer.Name в базу.

G>Неверно. Вам как минимум придется прочитать из базы кастомера, чтобы проверить ему этот Name.

Не всегда. Если кастомер новый, то не надо, т.к. его там нет.

G>Кроме того большенство элементарных проверок будут сделаны в PL, поэтому накладных расходов на такие проверки нету, да и база сама делает такую проверку на not null поля.


Нельзя полагаться, на то, что проверки сделаны в PL, его элементарно может не быть.
Re[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 21:30
Оценка:
Здравствуйте, VGn, Вы писали:

T>>>>Методы. Интерфейсы.

IB>>>А это вообще никакого отношения к данным не имеет.
T>>Зато имеет к ООП.

VGn>Значит всё-таки ООП — твой супермолоток?


Нет, это удобный инструмент, не более того.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 07.01.09 21:35
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Сегодня у тебя была какая-то одна задача, которую ты вполне успешно разбил на независимые (в том числе по данным) подзадачи и успешно решил, через полгода тебе или твоему коллеге приходит minor change request, в которым просят изменить что-то в логике первоначальной задачи. Это изменение будут затрагивать одну из подзадач первоначальной задачи. Но получится так, что в результате подзадачи перестанут быть независимыми по данным. У тебя будет два выхода, либо все отрефакторить во имя "правильного" подхода, либо внести изменения по месту и смириться с тем, что независимость по данным потеряна. Первый вариант гарантированно займет больше времени. Ваши действия, сударь?

G>Ничего не понял, но ваши слова тронули меня до глубины души.

Перечитай еще, чай не рокет-сайнс.

T>>Мне даже пример пришел в голову, все с тем же резервированием по накладной.


T>>Первоначальная постановка:

T>>По нажатию на кнопочку "Резерв." в форме заказа зарезервировать остатки на складе и послать во внешнюю систему (веб-сервис) запрос на упаковку.
T>>Решение: задача разбивается на 2 более мелких: 1) изменить остатки 2) послать запрос на упаковку.

T>>CR (через полгода):

T>>При резервировании заказа заказ должен сохранять в одном из полей номер запроса на упаковку (номер возвращается веб-сервисом).

G>Так это бизнес-транзация, к системным транзакциям, блокировкам и целостности данных отношения не имеет.


G>Варианты

G>1)В первоначальной задаче операция изменения остатков не зависит от результата выполнения запроса. Операции запускаются параллельно.

Не верное предположение. Если отгружать нечего, то и упаковывать нечего.

G>CR делает эти операции зависимыми, тогда сначала выполняется запрос (ниче не поделаешь, пользователю придется ждать), а потом сохранение данных.


Даже если склад пустой? Чего упаковывать-то?

G>Так как изменнеие остатков выполняется несколькими операциями insert и update, то это вполне можно сделать в одном батче без предварительного чтения и без длительного удержания блокировок.


G>2)В первоначальной задаче операция изменения остатков и выполнение запроса составляют бизнес-транзакцию. Тогда изначально будет сначала выполняться запрос, а потом изменнеие остатков. Для реализации CR в таком случае требуется только модифицировать запросы.


См. выше.
Re[22]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 07.01.09 23:40
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Если это так, то имхо, это просто ужасный вариант.

T>>>Если предполагается использовать security базу в более чем одной подсистеме, то: такой подход порождает дублирование всех security-таблиц.
G>>Какой ужас... один скрипт в БД и все. Причем всегда одинаковый.
T>Я имел в виду типы LINQ2SQL entity-ей или EF, если вы его используете.

Update Model From Database решает.

T>>>Эти типы будут несовместимы меж собой. Нельзя будет написать для этих типов общий код.

G>>Какие типы? Вы вообще о чем?
T>Я имел в виду типы LINQ2SQL entity-ей или EF, если вы его используете.
Какой общий код?


T>>>При внесении изменений в security-подсистему, эти изменения нужно будет нетривиальным способом переносить во все места, где она используется.


G>>Ну если у вас код выглядит так

G>>
G>>var q = from ...
G>>q = q.AddSecurityCheck(user);
G>>

G>>то придется поменять в одном месте.
G>>А проверяется наличие таких вызовов тестами.

T>Вот реализация AddSecurityCheck как раз и поменяется.

Ну да, реализацию одного метода.

T>Не получится. Если у тебя delete customer where type = 'vip', то либо в аудит-лог у тебя попадет только одна запись, либо ... Кажется второго варианта и нет.

Можно цеплять дополнительную команду к батчу. Тогда и триггеры не нужны.

T>>>>>Нет, ты не предлагаешь сократить передечу в базу. В твоем сценарии данные сначала пишутся в базу, а потом валидируются. То есть даже невалидные данные ты передаешь. И где тут сокращение?

G>>>>Сокращения в том что данные из базы вообще не тянутся в приложение.
T>>>Зато они пишутся в базу. И далеко не факт, что это дешевле.
G>>А вам все равно придется писать в базу вы от этого никуда не денетесь.
T>Если валидация не прошла, то не придется.
И как часто она не проходит?


T>>>Уверяю тебя, это далеко не вегда так. Проверить string.IsNullOrEmpty(customer.Name) да порядка три будет быстрее, чем запись customer.Name в базу.

G>>Неверно. Вам как минимум придется прочитать из базы кастомера, чтобы проверить ему этот Name.
T>Не всегда. Если кастомер новый, то не надо, т.к. его там нет.
Такая проверка будет в UI (веб), в PL, и в базе (автоматически за счет not null поля). Дополнительных запросов и не понадобится.
Приведите пример поадекватнее, который нельзя проверить ни в UI, ни в PL, ни в базе с помощью простого check constraint, а только валидацией модели.

G>>Кроме того большенство элементарных проверок будут сделаны в PL, поэтому накладных расходов на такие проверки нету, да и база сама делает такую проверку на not null поля.

T>Нельзя полагаться, на то, что проверки сделаны в PL, его элементарно может не быть.
Именно поэтому проверки делаются везде. Но откинет неправльный результат самая первая, поэтому на базу нагрузки не будет.
Re[14]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 07.01.09 23:51
Оценка:
Здравствуйте, Tissot, Вы писали:

T>>>Мне даже пример пришел в голову, все с тем же резервированием по накладной.


T>>>Первоначальная постановка:

T>>>По нажатию на кнопочку "Резерв." в форме заказа зарезервировать остатки на складе и послать во внешнюю систему (веб-сервис) запрос на упаковку.
T>>>Решение: задача разбивается на 2 более мелких: 1) изменить остатки 2) послать запрос на упаковку.

T>>>CR (через полгода):

T>>>При резервировании заказа заказ должен сохранять в одном из полей номер запроса на упаковку (номер возвращается веб-сервисом).

G>>Варианты

G>>1)В первоначальной задаче операция изменения остатков не зависит от результата выполнения запроса. Операции запускаются параллельно.
T>Не верное предположение. Если отгружать нечего, то и упаковывать нечего.
См. ниже.

G>>CR делает эти операции зависимыми, тогда сначала выполняется запрос (ниче не поделаешь, пользователю придется ждать), а потом сохранение данных.

T>Даже если склад пустой? Чего упаковывать-то?
Если склад пустой, то оператор не сможет выбрать позиции для резервирования, транзакция не пойдет.

G>>Так как изменнеие остатков выполняется несколькими операциями insert и update, то это вполне можно сделать в одном батче без предварительного чтения и без длительного удержания блокировок.


G>>2)В первоначальной задаче операция изменения остатков и выполнение запроса составляют бизнес-транзакцию. Тогда изначально будет сначала выполняться запрос, а потом изменнеие остатков. Для реализации CR в таком случае требуется только модифицировать запросы.
Re[16]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 00:11
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>CR делает эти операции зависимыми, тогда сначала выполняется запрос (ниче не поделаешь, пользователю придется ждать), а потом сохранение данных.

T>>>Даже если склад пустой? Чего упаковывать-то?
G>>Если склад пустой, то оператор не сможет выбрать позиции для резервирования, транзакция не пойдет.

T>Резервируют не позиции, а заказ.

Тут уже показывайте схему данных, формализованный бизнес-процесс, как работает сервис и какие тербования предьявляются к программе.
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 00:26
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>>>Если предполагается использовать security базу в более чем одной подсистеме, то: такой подход порождает дублирование всех security-таблиц.

G>>>Какой ужас... один скрипт в БД и все. Причем всегда одинаковый.
T>>Я имел в виду типы LINQ2SQL entity-ей или EF, если вы его используете.

G>Update Model From Database решает.


Автомитизированное дублирование — это все равно дублирование. К тому же в LINQ2SQL-е нет никакого update model.

T>>>>Эти типы будут несовместимы меж собой. Нельзя будет написать для этих типов общий код.

G>>>Какие типы? Вы вообще о чем?
T>>Я имел в виду типы LINQ2SQL entity-ей или EF, если вы его используете.
G>Какой общий код?

Какие-нить хелперы.

T>>Вот реализация AddSecurityCheck как раз и поменяется.

G>Ну да, реализацию одного метода.

Везде где этот метод есть.

T>>Не получится. Если у тебя delete customer where type = 'vip', то либо в аудит-лог у тебя попадет только одна запись, либо ... Кажется второго варианта и нет.

G>Можно цеплять дополнительную команду к батчу. Тогда и триггеры не нужны.

Конечно можно. Моя цель лишь показать, что все не так тривиально, как тут пытаются представить.

T>>>>Зато они пишутся в базу. И далеко не факт, что это дешевле.

G>>>А вам все равно придется писать в базу вы от этого никуда не денетесь.
T>>Если валидация не прошла, то не придется.
G>И как часто она не проходит?

Если в проентах, — то 100 — x, где x — процент, когда она проходит

T>>>>Уверяю тебя, это далеко не вегда так. Проверить string.IsNullOrEmpty(customer.Name) да порядка три будет быстрее, чем запись customer.Name в базу.

G>>>Неверно. Вам как минимум придется прочитать из базы кастомера, чтобы проверить ему этот Name.
T>>Не всегда. Если кастомер новый, то не надо, т.к. его там нет.
G>Такая проверка будет в UI (веб), в PL, и в базе (автоматически за счет not null поля). Дополнительных запросов и не понадобится.
G>Приведите пример поадекватнее, который нельзя проверить ни в UI, ни в PL, ни в базе с помощью простого check constraint, а только валидацией модели.

Я уже приводил пример, когда при регистрации кастомера нужно создать раздел в базе знаний. Ни UI, ни PL тут нет. А проверка может быть, например, что имя создаваемого раздела соответствует какой-то маске или что у раздела прописан хоть один администратор. Да мало ли чего может быть?

G>>>Кроме того большенство элементарных проверок будут сделаны в PL, поэтому накладных расходов на такие проверки нету, да и база сама делает такую проверку на not null поля.

T>>Нельзя полагаться, на то, что проверки сделаны в PL, его элементарно может не быть.
G>Именно поэтому проверки делаются везде. Но откинет неправльный результат самая первая, поэтому на базу нагрузки не будет.

Мне кажется этот спор начинается зацикливаться. А не спорю с тем, что есть класс проверок, которые не могут быть сделаны в базе данных.
С учетом того, что большинство современных серверов баз данных позволяют писать пользовательские функции на C++/java/C#, то и проверки туда могут быть вставлены абсолютно любые.
Вопрос лишь в том, стоит ли эти проверки делать именно в базе. Если вы ратуете за использование update-ов прямо из кода, то вам их придется туда запихнуть. Если же остаетесь в рамках domain model, то их можно расположить в бизнесе, что на мой взгляд, удобнее.
Re[24]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 00:49
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>>>Если предполагается использовать security базу в более чем одной подсистеме, то: такой подход порождает дублирование всех security-таблиц.

G>>>>Какой ужас... один скрипт в БД и все. Причем всегда одинаковый.
T>>>Я имел в виду типы LINQ2SQL entity-ей или EF, если вы его используете.

G>>Update Model From Database решает.


T>Автомитизированное дублирование — это все равно дублирование.

Кто сказал что автоматизированное дублирование — плохо? Ручное неконтроллируемое дублирование — вот что плохо, а автоматизированное — это нормально.

T>К тому же в LINQ2SQL-е нет никакого update model.

Поэтому им и не пользуюсь.

T>>>>>Эти типы будут несовместимы меж собой. Нельзя будет написать для этих типов общий код.

G>>>>Какие типы? Вы вообще о чем?
T>>>Я имел в виду типы LINQ2SQL entity-ей или EF, если вы его используете.
G>>Какой общий код?

T>Какие-нить хелперы.

Пусть хелперы реботают через общие интерфейсы.

T>>>Вот реализация AddSecurityCheck как раз и поменяется.

G>>Ну да, реализацию одного метода.
T>Везде где этот метод есть.
Не-а, в одном месте.

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

А никто не говорит про тривиальность. Все говорят что такой подход а)более правильный с точки зрения работы с данными б)обладает не меньшей мощью, по сравнению с императивным ООП подходом.

T>Я уже приводил пример, когда при регистрации кастомера нужно создать раздел в базе знаний. Ни UI, ни PL тут нет. А проверка может быть, например, что имя создаваемого раздела соответствует какой-то маске или что у раздела прописан хоть один администратор. Да мало ли чего может быть?

Ну так схему данных в студию, на словах все равно непенятно.

T>Вопрос лишь в том, стоит ли эти проверки делать именно в базе. Если вы ратуете за использование update-ов прямо из кода, то вам их придется туда запихнуть.

Элементарные проверки (not null, диапазоны значений и прочее) у вас и так будут в базе, более сложные можно запихнуть в дополнительные запросы.

T>Если же остаетесь в рамках domain model, то их можно расположить в бизнесе, что на мой взгляд, удобнее.

Чем удобнее?
Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 01:03
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Update Model From Database решает.


T>>Автомитизированное дублирование — это все равно дублирование.

G>Кто сказал что автоматизированное дублирование — плохо? Ручное неконтроллируемое дублирование — вот что плохо, а автоматизированное — это нормально.

Это лучше чем ручное дублирование, но хуже, чем его отсутствие.

T>>Какие-нить хелперы.

G>Пусть хелперы реботают через общие интерфейсы.

Ок. Пусть работают.

T>>>>Вот реализация AddSecurityCheck как раз и поменяется.

G>>>Ну да, реализацию одного метода.
T>>Везде где этот метод есть.
G>Не-а, в одном месте.

Неа, во всех.

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

G>А никто не говорит про тривиальность. Все говорят что такой подход а)более правильный с точки зрения работы с данными б)обладает не меньшей мощью, по сравнению с императивным ООП подходом.

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

T>>Я уже приводил пример, когда при регистрации кастомера нужно создать раздел в базе знаний. Ни UI, ни PL тут нет. А проверка может быть, например, что имя создаваемого раздела соответствует какой-то маске или что у раздела прописан хоть один администратор. Да мало ли чего может быть?

G>Ну так схему данных в студию, на словах все равно непенятно.

CREATE TABLE tblCustomer (pkID INT, sName NVARCHAR(20))


T>>Вопрос лишь в том, стоит ли эти проверки делать именно в базе. Если вы ратуете за использование update-ов прямо из кода, то вам их придется туда запихнуть.
G>Элементарные проверки (not null, диапазоны значений и прочее) у вас и так будут в базе, более сложные можно запихнуть в дополнительные запросы.

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

T>>Если же остаетесь в рамках domain model, то их можно расположить в бизнесе, что на мой взгляд, удобнее.

G>Чем удобнее?

Тем, что у меня полный набор средств предоставляемых ооп, вплоть до того, что эти проверки могут быть сделаны декларативно, а то и вовсе вынесены в конфигурационный файл. В общем рамками SQL-я я ограничен не буду.
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 01:05
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Резервируют не позиции, а заказ.

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

Выше по ветке есть описание задачи.
Re[26]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 01:19
Оценка:
Здравствуйте, Tissot, Вы писали:


T>>>>>Вот реализация AddSecurityCheck как раз и поменяется.

G>>>>Ну да, реализацию одного метода.
T>>>Везде где этот метод есть.
G>>Не-а, в одном месте.
T>Неа, во всех.
У меня таким образом сделано получение даты последнего обновления списка сущностей в БД.
Причем код не поменялся даже при переходе от Linq2SQL к EF.

T>>>Вопрос лишь в том, стоит ли эти проверки делать именно в базе. Если вы ратуете за использование update-ов прямо из кода, то вам их придется туда запихнуть.

G>>Элементарные проверки (not null, диапазоны значений и прочее) у вас и так будут в базе, более сложные можно запихнуть в дополнительные запросы.
T>Не, в непосредственно в запросы запихнуть будет недостаточно, т.к. все равно останется возможность вставить данные, не добавляя эти проверки в insert. Это должно быть частью инфраструктуры, так чтобы избежать этой проверки нельзя было.
Ну и я о томже. Работа с базой всегда будет вестись через какой-то объект контекста, этот объект может выствлять событие оправки батча запросов на сервер с возможностью модификации. Вот через такое событие можно будет дополнительные запросы валидации добавлять.
Аналогично событию SavingChanges в EF.

T>>>Если же остаетесь в рамках domain model, то их можно расположить в бизнесе, что на мой взгляд, удобнее.

G>>Чем удобнее?

T>Тем, что у меня полный набор средств предоставляемых ооп, вплоть до того, что эти проверки могут быть сделаны декларативно, а то и вовсе вынесены в конфигурационный файл. В общем рамками SQL-я я ограничен не буду.

А кто говорит про использование SQL?
Все про что я писал возможно именно при наличии Linq. Причем пока нету операторов для update\delete\insert все это остается только идеей.
Re[27]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 01:40
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Не, в непосредственно в запросы запихнуть будет недостаточно, т.к. все равно останется возможность вставить данные, не добавляя эти проверки в insert. Это должно быть частью инфраструктуры, так чтобы избежать этой проверки нельзя было.

G>Ну и я о томже. Работа с базой всегда будет вестись через какой-то объект контекста, этот объект может выствлять событие оправки батча запросов на сервер с возможностью модификации. Вот через такое событие можно будет дополнительные запросы валидации добавлять.

Сможете сделать это просто и удобно — честь вам и хвала.

T>>Тем, что у меня полный набор средств предоставляемых ооп, вплоть до того, что эти проверки могут быть сделаны декларативно, а то и вовсе вынесены в конфигурационный файл. В общем рамками SQL-я я ограничен не буду.

G>А кто говорит про использование SQL?

Если у тебя есть update типа update customer ... where type = vip, то валидацию ты сможешь сделать только на сервере, т.к. на клиенте неизвестно что именно будет изменено. А раз так, то и набор средств, предоставленых тебе будет ограничен SQL-ем.

G>Все про что я писал возможно именно при наличии Linq. Причем пока нету операторов для update\delete\insert все это остается только идеей.


Но как бы то ни было, идея интересная.
Re[14]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.01.09 05:50
Оценка:
Здравствуйте, Tissot, Вы писали:
T>Конструктивнее. Давай лучшие в студию.
В зависимости от используемой СУБД строим код табличной функции, который возвращает нужный датасет в уже развернутом виде. В оракле это connect by, в MS SQL и DB2 — with, в Interbase — курсор и return.

Если не устраивает быстродействие такого подхода, то реализуем на стороне СУБД транзитивное замыкание.

В любом случае, код в application tier пишется так, как будто планаризованный датасет уже доступен. Способ преобразования дерева в список — избыточная подробность. Это азы декомпозиции.

T>Кэш — в топку.

Очень хорошо. Это — правильный подход.

T>Что такого сложного в том, чтобы сделать select и результат распихать по свойствам?

Рекомендую плотненько поработать с профайлером. Для начала — с SQL Server Profiler, так, для посмотреть, во что превращается unit of work применительно к SQL — запросам.
Потом можно напустить профайлер на application tier, чтобы посмотреть, насколько "просто" выполнить селект и распихать по свойствам.
Прикинуть, не влияет ли случайно на результат то, что тест проходит на машине, где и application и data tier стоят рядом и могут обмениваться по shared memory с низкой латентностью. Если влияет, то осознать, что с ростом масштаба data tier придется выносить на другую машину, а там будет TCP/IP и все радости латентности, вызванной лишними обращениями.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Некоторые мысли о LINQ
От: alvas  
Дата: 08.01.09 05:59
Оценка:
Здравствуйте, Tissot, Вы писали:

A>>Планируется ли добавление в Nemerle insert, update и delete?


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


Однозначно.
http://alvas.net — Аудио-инструменты для .Net разработчиков
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 08:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

T>>Конструктивнее. Давай лучшие в студию.
S>В зависимости от используемой СУБД строим код табличной функции, который возвращает нужный датасет в уже развернутом виде. В оракле это connect by, в MS SQL и DB2 — with, в Interbase — курсор и return.

как поддеживать в Linq-е — рекурсивные запросы.



T>>Что такого сложного в том, чтобы сделать select и результат распихать по свойствам?

S>Рекомендую плотненько поработать с профайлером. Для начала — с SQL Server Profiler, так, для посмотреть, во что превращается unit of work применительно к SQL — запросам.

Да вроде смотрел. Ничего особо криминального. Если не учитывать дурацкие алиасы t0, t1, ... вполне себе код как код.

S>Потом можно напустить профайлер на application tier, чтобы посмотреть, насколько "просто" выполнить селект и распихать по свойствам.


Проблема в том, что сравнивать мне придется с тем, чего еще нет.

S>Прикинуть, не влияет ли случайно на результат то, что тест проходит на машине, где и application и data tier стоят рядом и могут обмениваться по shared memory с низкой латентностью. Если влияет, то осознать, что с ростом масштаба data tier придется выносить на другую машину, а там будет TCP/IP и все радости латентности, вызванной лишними обращениями.


Так и работаем.
Re[16]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.01.09 09:39
Оценка:
Здравствуйте, Tissot, Вы писали:

T>

T>как поддеживать в Linq-е — рекурсивные запросы.

Я уже написал. Linq — всего лишь средство доступа к СУБД, а не ее замена.

T>Да вроде смотрел. Ничего особо криминального. Если не учитывать дурацкие алиасы t0, t1, ... вполне себе код как код.

Всё познаётся в сравнении.

S>>Потом можно напустить профайлер на application tier, чтобы посмотреть, насколько "просто" выполнить селект и распихать по свойствам.

T>Проблема в том, что сравнивать мне придется с тем, чего еще нет.
Скорее надо сравнивать с тем, чего нет и не будет. В том смысле, что работы, которую ты пронаблюдаешь, в нормальном приложении вовсе быть не должно.

T>Так и работаем.

Ну вот и посмотри на стоимость одного roundtrip до СУБД.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 08.01.09 13:43
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Ведите себя прилично, не надо переходить на личности.

Не надо фаулером на ровном месте прекрываться, если самому сказать нечего.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[9]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 14:00
Оценка:
Здравствуйте, IB, Вы писали:

T>>Наследование само по себе (без наличия виртуальных методов) ценности не несет.

IB>Во-первых, несет, во-вторых,

Кукую?

IB>какие вообще методы ты хочешь видеть в данных


Например, методы валидации. Или user-friendly ToString.

IB>и, наконец, в третих, оно таки отлично выражается в ER, что и требовалось доказать.


Покажи, как оно отлично выражается. Те способы выражения что я знаю, не очень-то приятные для использования.

T>>Многие-ко-многим выражается через два отношения один-ко-многим.

IB>Тем не менее выражается.

T>>С этим элементарно неудобно работать

IB>Никаких фатальных неудобств с этим нет, а иногда это вообще оборачивается преимуществом.

Ну это как посмотреть. Кому-то может быть и удобно, мне — не очень.

T>>Зато имеет к ООП.

IB>Однако здесь речь идет не об ООП, а об ООП при работе с данными. И в применении к данным, методы и интерфейсы являются большой проблемой.
IB>Дело в том, что срок жизни данных — сильно больше срока жизни типичного ООП-шного объекта, реализующего конкретное поведение в определенном сценарии. Более того, одни и те же данные хорошо бы использовать в разных объектах, но как только к данным прибивается гвоздями определенное поведение и структура с помощью методов и интерфейсов, эта возможность тут же теряется.

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

IB>Именно по этому, навязать данным методы — дурная затея. Во-первых, меняя в десятый раз поведение данные нужно оставлять неизменными. Во-вторых, добавляя новое поведение, надо его просто добавлять, а не менять старое и не накручивать поверх старого, при этом стараясь оставить данные по прежнему неизменными.


По поводу неизменности данных я полностью согласен. А вот по поводу "добавлять, а не менять" — не совсем. Если требования поменялись, то код должен быть тоже поменян, зачем хранить в приложении тот код, который уже не актуален? Не понимаю.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 14:03
Оценка:
Здравствуйте, IB, Вы писали:

T>>Можно подкрепить высказывание ссылочкой? Спасибо.

IB>BOL =)

Спасибо, что не гугл
А поточнее ссылочку не подкинешь?

T>> ORMapper в конечном итоге говорит и сервером на SQL, а значит все средства остаются в силе.

IB>Классические ORM делают это настолько криво, что плохо становится и сиквелу и разработчику, так как по факту, ничего в силе не остается.

Не знаю, смотрел профайлером. Ничего особенно криминального не заметил. Все достаточно просто и понятно.

T>>Отсутствие ленивой загрузки.

IB>Угу, купи козу — продай козу. А что с остальными косяками делать?

Для начала сформулировать, что за косяки имеются в виду. Потом — отказаться от EF

T>>Над чем у тебя нет явного контроля в том же LINQ2SQL-е. Он же тупой как пробка.

IB>В этом его и прелесть. Если ты не понял, то L2S — это шаг в правильном направлении, но хочется большего, в этом и был поинт.

А чего тогда говорить что контроля нет?
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 14:09
Оценка:
Здравствуйте, IB, Вы писали:

T>>Ку так расскажи, а то все вокруг, да около. Или тоже секретная разработка?

IB>"Лень фаулера цитировать" (с)

А я цитат и не прошу. Ссылочки будет вполне достаточно.

T>>См. Фаулера, а лучше Evans-а.

IB>Ну вот и смотри лучше в фаулера, даже у него domain model — лишь один из вариантов дизайна, и даже он не настаивает на его универсализме.

Очень даже настаивает, когда говорит о сложных приложениях.

T>>Ну если другие подходы не выдерживают критики, то приходится ограничиваться "серебрянной пулей"

IB>Так где критика-то? Хотя в принципе, достаточно того, что некоторые другие подходы отлично выдерживают практику.

Ладно, проехали. Нет никакой критики. Вы абсолютно правы.

T>>Я так не считаю.

IB>Ну это сугубо твои проблемы.. Де-факто (с), его подавали именно под этим соусом.

Это его де-юре таким подавали, а де-факто он был совсем не таким кучерявым, каким хотел казаться.

T>>А это вообще не суть важно. При использовании TransactionScope ты хоть каждый чих оборачивай в транзакцию. Коммит в базу все равно будет только после последнего самомго внешнего TransactionScope-а.

IB>Да, представляю транзакции после такого получаются.. =) Самому не смешно? )

Нет, ничуть не смешно. Вложеные TransactionScope-ы реюзают в конечном итоге одну транзакцию, так что множественное число тут не очень уместно.
Re[19]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 14:11
Оценка:
Здравствуйте, IB, Вы писали:

T>>Ведите себя прилично, не надо переходить на личности.

IB>Не надо фаулером на ровном месте прекрываться, если самому сказать нечего.

Мы обсуждаем идеи или личности?
Если идеи, то какая разница, кем она высказана?
Если все-таки личности, то ... пожалуй я воздержусь от подобного обсуждения.
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 15:28
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>>>Наследование само по себе (без наличия виртуальных методов) ценности не несет.

IB>>>Во-первых, несет, во-вторых,
T>>Кукую?
G>Полиморфизм достигается не только вирткальными методами в классе.

Ну интерфейсы еще есть, конечно, но они тоже не являются частью er-модели.

T>>Например, методы валидации. Или user-friendly ToString.

G>Валидация в entity-объектах? Ну это совсем моветон.

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

T>>Пример можно показать, без абстрактных пассов руками в воздухе. По мне так чем объектная модель программы ближе к оной предметной области, тем лучше — проще понимать такой код.

G>Методы в классах сущностей это ближе к предметной области?

Ну да.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 16:04
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Полиморфизм достигается не только вирткальными методами в классе.

T>>Ну интерфейсы еще есть, конечно, но они тоже не являются частью er-модели.
G>Вам наверное стоит разобраться что такое полиморфизм.

Не стоит, я знаю, что такое полиморфизм.

T>>Сама реализация валидации может быть расположена и где-то вовне класса, а класс может просто делегировать вызов. Очень удобно, например на SubmitChanges проверять таким образом валидность измененных сущностей.

G>Да уж... Валидацию сущностей надо задавать декларативно — атрибутами или во внешних конфигах. Смотрите Validation Application Block из enterprise library.

Не все проверки стоит делать атрибутами. Иногда это может оказаться overkil-ом.

G>>>Методы в классах сущностей это ближе к предметной области?

T>>Ну да.
G>С чего это?
G>Кроме того такие решения обычно нарушают SRP,

Нарушение SRP можно где угодно усмотреть, было бы желание. Оставишь исключительно данные в сущности — все равно будет нарушение SRP, т.к. класс берет на себя не только ответственность за хранение Name-а, но и LastUpdatedBy. Так что не нужно к этому принципу подходить параноидально, во всем надо знать меру.

G>а преимуществ от них маловато, даже понимаемость кода страдает в таких условиях, за исключением самых простых случаев.


Я так не считаю.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 16:32
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Вам наверное стоит разобраться что такое полиморфизм.

T>>Не стоит, я знаю, что такое полиморфизм.
G>Видимо стоит, почитайте http://www.rsdn.ru/forum/message/2853873.aspx
Автор: Gaperton
Дата: 26.02.08


Спасибо за беспокойство, но этот пост я уже читал.

T>>Не все проверки стоит делать атрибутами. Иногда это может оказаться overkil-ом.

G>"Иногда" это когда?

Когда проверка очень специфична для сущности и реюз этой проверки не предполагается.

G>>>>>Методы в классах сущностей это ближе к предметной области?

T>>>>Ну да.
G>>>С чего это?
G>>>Кроме того такие решения обычно нарушают SRP,

T>>Нарушение SRP можно где угодно усмотреть, было бы желание. Оставишь исключительно данные в сущности — все равно будет нарушение SRP, т.к. класс берет на себя не только ответственность за хранение Name-а, но и LastUpdatedBy. Так что не нужно к этому принципу подходить параноидально, во всем надо знать меру.

G>Есть обязанность "хранить данные", вот объекты-сущности эти обязанности выполняют независимо от состава полей.

А данные — это набор атрибутов, следовательно обязанность "хранить данные" — это составная обязанность, которая может быть разбита на более мелкие.

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


Во всем надо знать меру.

G>>>а преимуществ от них маловато, даже понимаемость кода страдает в таких условиях, за исключением самых простых случаев.

T>>Я так не считаю.
G>Можете каким-нибудь аргументом подкрепись свое мнение, иначе нет смысла его писать.

Я привел пример, когда это удобно. Посмотри выше по ветке.
Re[16]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 16:49
Оценка:
Здравствуйте, Tissot, Вы писали:

T>>>Не все проверки стоит делать атрибутами. Иногда это может оказаться overkil-ом.

G>>"Иногда" это когда?
T>Когда проверка очень специфична для сущности и реюз этой проверки не предполагается.
Получается что часть проверок будет заданы атрибутами\конфигом, а часть в коде методов класса?
Совсем фигня получается. Кроме того вся валидация может быть выполнена используя только публичный контракт класса сущности, еще один повод вынести её отдельно.
Если подсистему валидации нормально продизанить, то получится что-то вроде validation app block.

G>>>>>>Методы в классах сущностей это ближе к предметной области?

T>>>>>Ну да.
G>>>>С чего это?
G>>>>Кроме того такие решения обычно нарушают SRP,

T>>>Нарушение SRP можно где угодно усмотреть, было бы желание. Оставишь исключительно данные в сущности — все равно будет нарушение SRP, т.к. класс берет на себя не только ответственность за хранение Name-а, но и LastUpdatedBy. Так что не нужно к этому принципу подходить параноидально, во всем надо знать меру.

G>>Есть обязанность "хранить данные", вот объекты-сущности эти обязанности выполняют независимо от состава полей.
T>А данные — это набор атрибутов, следовательно обязанность "хранить данные" — это составная обязанность, которая может быть разбита на более мелкие.
Это уже плод больного воображения.

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

T>Во всем надо знать меру.
Ага, самоя хорошая мера называется SRP.

G>>>>а преимуществ от них маловато, даже понимаемость кода страдает в таких условиях, за исключением самых простых случаев.

T>>>Я так не считаю.
G>>Можете каким-нибудь аргументом подкрепись свое мнение, иначе нет смысла его писать.
T>Я привел пример, когда это удобно. Посмотри выше по ветке.
Что-то не нашел примеров такого удобства. Кроме того мнимое удобство в одном месте может создать кучу неудобств в других.

На моей первой работе был гениальный класс Queue (очередь), унаследованный от TStringList (на делфи). Содатели этого класса мотивировали удобством, хотя через интерфейс TStringList можно было нарушить работу класса очереди.
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 16:56
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Когда проверка очень специфична для сущности и реюз этой проверки не предполагается.

G>Получается что часть проверок будет заданы атрибутами\конфигом, а часть в коде методов класса?
G>Совсем фигня получается. Кроме того вся валидация может быть выполнена используя только публичный контракт класса сущности, еще один повод вынести её отдельно.
G>Если подсистему валидации нормально продизанить, то получится что-то вроде validation app block.

Если ты внимательнее посмотришь validation app block, то увидишь, что в нем предусмотрен вариант для тех случаев, когда сущность сама себя валидирует.

G>>>Есть обязанность "хранить данные", вот объекты-сущности эти обязанности выполняют независимо от состава полей.

T>>А данные — это набор атрибутов, следовательно обязанность "хранить данные" — это составная обязанность, которая может быть разбита на более мелкие.
G>Это уже плод больного воображения.

Нет, это всего лишь SRP доведенный до конца.

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

T>>Во всем надо знать меру.
G>Ага, самоя хорошая мера называется SRP.

См. выше.

G>>>Можете каким-нибудь аргументом подкрепись свое мнение, иначе нет смысла его писать.

T>>Я привел пример, когда это удобно. Посмотри выше по ветке.
G>Что-то не нашел примеров такого удобства. Кроме того мнимое удобство в одном месте может создать кучу неудобств в других.

Очень жаль. Я сделал все, что мог.

G>На моей первой работе был гениальный класс Queue (очередь), унаследованный от TStringList (на делфи). Содатели этого класса мотивировали удобством, хотя через интерфейс TStringList можно было нарушить работу класса очереди.


Неудачный пример.
Re[14]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 08.01.09 18:17
Оценка:
Здравствуйте, Tissot, Вы писали:

T>А я цитат и не прошу. Ссылочки будет вполне достаточно.

Ну, считай, что я сослался на фаулера.

T>Очень даже настаивает, когда говорит о сложных приложениях.

Цитату можно? А заодно определение сложных приложений.

T>Ладно, проехали. Нет никакой критики. Вы абсолютно правы.

Ну, а что тогда вообще споришь? Просто потрепаться захотелось? )

T>Нет, ничуть не смешно.

Напрасно...

T> Вложеные TransactionScope-ы реюзают в конечном итоге одну транзакцию, так что множественное число тут не очень уместно.

То есть, больше одной транзакции не бывает?
Продолжай, очень забавная архитектура выстраивается.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[16]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 08.01.09 18:17
Оценка:
Здравствуйте, Tissot, Вы писали:

T>А поточнее ссылочку не подкинешь?

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

T>Не знаю, смотрел профайлером. Ничего особенно криминального не заметил. Все достаточно просто и понятно.

Нету там ничего простого и понятного, если приложение сложнее калькулятора.

T>Для начала сформулировать, что за косяки имеются в виду. Потом — отказаться от EF

Спасибо, я уже.

T>А чего тогда говорить что контроля нет?

Контроля нет в классических ORM и в фаулеровской rich domain model. А LINQ к ним не относится, ты хоть оригинальный-то пост внимательно читал?
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[17]: Некоторые мысли о LINQ
От: mogadanez Чехия  
Дата: 08.01.09 21:35
Оценка:
S>>>Потом можно напустить профайлер на application tier, чтобы посмотреть, насколько "просто" выполнить селект и распихать по свойствам.
T>>Проблема в том, что сравнивать мне придется с тем, чего еще нет.
S>Скорее надо сравнивать с тем, чего нет и не будет. В том смысле, что работы, которую ты пронаблюдаешь, в нормальном приложении вовсе быть не должно.

мне кажется что он имел ввиду что ты говоря что все это сложно не говоришь ничего о альтернативе, спор о том какой подход лучше подразумевает сравнение по набору _различных_ характеристик. а предложение посмотреть на какой то подход с определенного угла и "сделать выводы" мягко говоря не конструктивны.

маленько офтоп, но всеже — как то на форуме преобладает позиция втоптать чужое мнение чем продемонстрировать свое.
Re[11]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 21:40
Оценка:
Здравствуйте, IB, Вы писали:

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


T>>Кукую?

IB>Про полиморфизм тебе уже рассказали.

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

T>>Например, методы валидации. Или user-friendly ToString.

IB>Ужас какой.

Жизнь вообще страшная штука. В Палестине вон людей неповинных убивают почем зря.

T>>Те способы выражения что я знаю, не очень-то приятные для использования.

IB>Во-первых вопрос был не про приятности использования, а про сам факт выражения, а во-вторых, надо уметь готовить

Возможно, я не умею их готовить, но почему вы упорно продолжаете умалчивать о том, как это далать?

T>>Ну это как посмотреть. Кому-то может быть и удобно, мне — не очень.

IB>Ну так это твои личные проблемы.

Про переходы на личности я уже писал в дугой ветке.

T>>Пример можно показать, без абстрактных пассов руками в воздухе. По мне так чем объектная модель программы ближе к оной предметной области, тем лучше — проще понимать такой код.

IB>Уже трижды говорилось, речь не про объектную модель, а про данные. Data != Object — это то, с чего начинаются все white papers про LINQ и это очень правильно.

Ссылки, ссылки, ссылки.

IB>Далее, ER на практике, оказывается гораздо ближе к предметной области чем модель данных.


На вашей практике или не чьей-то еще. Если на чьей-то еще, то с удовольствием об этом почитаю. Накидайте ссылок.

T>>По поводу неизменности данных я полностью согласен. А вот по поводу "добавлять, а не менять" — не совсем. Если требования поменялись, то код должен быть тоже поменян, зачем хранить в приложении тот код, который уже не актуален? Не понимаю.

IB>И еще раз. Не код, а данные. Код должен быть поменян, а данные — нет.

А это наверное ваша жена написала в ваше отсутствие?

Во-вторых, добавляя новое поведение, надо его просто добавлять, а не менять старое


Ну если так, то ладно.
Re[21]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 21:45
Оценка:
Здравствуйте, IB, Вы писали:

T>>Если идеи, то какая разница, кем она высказана?

IB>Так где идея-то? Ты ее так и не высказал.

Напомню, что речь шла о использовании domain model. Если вам нужно указание на конкретные страницы, я готов вам сказать номера страниц. Если у вас нет книжки под рукой, я готов в первый рабочий день выслать вам электронный вариант.
Надеюсь, вопрос исчерпан?

IB>А фаулер много чего наговорил, как весьма толкового, так и не очень. И очень уж у неофитов на его почве крышу рвет.


Какой такой неофит? 10 лет в отрасли.
Re[12]: Некоторые мысли о LINQ
От: Gajdalager Украина  
Дата: 08.01.09 21:57
Оценка:
Здравствуйте, Tissot, Вы писали:

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


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


T>>>Кукую?

IB>>Про полиморфизм тебе уже рассказали.

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


О терминах спорить будем или согласимся, что идется только о runtime-полиморфизме в ОО-языках? http://en.wikipedia.org/wiki/Type_polymorphism
<< RSDN@Home 1.2.0 alpha 4 rev. 1128>>
Сейчас играет silent
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 22:11
Оценка:
Здравствуйте, IB, Вы писали:

T>>А поточнее ссылочку не подкинешь?

IB>Сразу после того, как перестанешь на фаулера ссылаться и расскажешь что-нибудь сам.

Я уже писал, что перепечатывать текст оттуда не буду. Если вас интересуют конкретные вопросы, я готов посмотреть в книге и назвать вам номер страницы.

IB>А вообще, читай особенности работы RC в блокировочниках.


Не мог бы ты расшифровать RC?

T>>Не знаю, смотрел профайлером. Ничего особенно криминального не заметил. Все достаточно просто и понятно.

IB>Нету там ничего простого и понятного, если приложение сложнее калькулятора.

Приложение, с которым я работаю сложнее калькулятора. Если вы что-то не понятно в том, что выдает профайлер, можете выслать ваши затруднения сюда, попробуем разобраться.

T>>А чего тогда говорить что контроля нет?

IB>Контроля нет в классических ORM и в фаулеровской rich domain model. А LINQ к ним не относится,

Почему LINQ2SQL не может быть отнесен в классическим ORM и почему с его помощью нельзя построить domain model?

IB>ты хоть оригинальный-то пост внимательно читал?


Держите свои эмоции при себе, не надо переходить на личности.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 22:16
Оценка:
Здравствуйте, Gajdalager, Вы писали:

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


G>О терминах спорить будем или согласимся, что идется только о runtime-полиморфизме в ОО-языках? http://en.wikipedia.org/wiki/Type_polymorphism


Да, имелся именно runtime-полиморфизм. Кстати, тремя сообщениями выше я упоминал про наследование,так что при желании можно было понять, что именно я имел в виду. Тем не менее, прошу прощения, если кого-то ввел в заблуждение.
Re[12]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 08.01.09 22:20
Оценка:
T>>>Кукую?
IB>>Про полиморфизм тебе уже рассказали.

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


Разъясните мне-идиоту зачем полиморфизм данным?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[16]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.01.09 22:27
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Понятие сложности — вопрос сугубо субъективный, никто тебе формулы для вычисления сложности не даст, придется с этим смириться.

Как раз понятие сложности сущесвует объективно, а вот привычность (которую многие путают с удобством) — субъективно.
Формула для вычисления сложности есть. Mantainability Index называется.
Но есть недостатки такой метрики. Во-первых она работает только для всего проекта. Расчет индекса для маленькой части большого приложения ничего не показывает. Во-вторых индекс хреново работает для не ОО-языков.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 22:46
Оценка:
Здравствуйте, VGn, Вы писали:

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


VGn>Разъясните мне-идиоту зачем полиморфизм данным?


Данным, он наверное не нужен, а объектам domain model — вполне.
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 22:52
Оценка:
Здравствуйте, gandjustas, Вы писали:

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


T>>Понятие сложности — вопрос сугубо субъективный, никто тебе формулы для вычисления сложности не даст, придется с этим смириться.

G>Как раз понятие сложности сущесвует объективно, а вот привычность (которую многие путают с удобством) — субъективно.
G>Формула для вычисления сложности есть. Mantainability Index называется.

Не верю я в такие индексы. Та же Cyclomatic Complexity несложными манипуляциями с кодом уменьшается до требуемых показателей. Зачастую не надо даже разбираться, что код делает. Туфта все это.
Re[18]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 08.01.09 23:53
Оценка:
Здравствуйте, mogadanez, Вы писали:

M>маленько офтоп, но всеже — как то на форуме преобладает позиция втоптать чужое мнение чем продемонстрировать свое.


+1, но с небольшой поправочкой. Зачастую пытаются втоптать не мнение, а собеседника.
Re[19]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 00:07
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Если ты внимательнее посмотришь validation app block, то увидишь, что в нем предусмотрен вариант для тех случаев, когда сущность сама себя валидирует.

G>Всегда все можно сделать неправильно, и оно при этом даже будет работать.

Если подсистему валидации нормально продизанить, то получится что-то вроде validation app block.

Так все-таки "нормально" или "неправильно"?

T>>>>А данные — это набор атрибутов, следовательно обязанность "хранить данные" — это составная обязанность, которая может быть разбита на более мелкие.

G>>>Это уже плод больного воображения.
T>>Нет, это всего лишь SRP доведенный до конца.
G>Это бред.

Это иллюстрация того, что фанатизм до хорошего не доводит.

G>>>Ага, самоя хорошая мера называется SRP.

T>>См. выше.
G>С каких пор абсурдные высказывания являются аргументом?

Есть такой подход в математике — доказательство от противного.

G>SRP придумали не для того чтобы начинающих программистов пугать.


Знание SRP не отменяет необходимости наличия головы не плечах.

G>>>На моей первой работе был гениальный класс Queue (очередь), унаследованный от TStringList (на делфи). Содатели этого класса мотивировали удобством, хотя через интерфейс TStringList можно было нарушить работу класса очереди.

T>>Неудачный пример.
G>Почему? Удобно же.

Применим тот же самый метод повторно: вы вроде как говорили, что не следует смешивать данные и методы работы с ними. Означает ли это, что вы, следуя SRP спроектировали бы класс queue примерно так:
public Queue {
  public object[] Data;
}

а для изменения queue у вас есть специальный сервисный класс
public QueueService {
  public void Enqueue(Queue data, object obj) {
  }
  public object Dequeue(Queue data) {
  }
}


Re[12]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 04:27
Оценка:
Здравствуйте, Tissot, Вы писали:
T>Сама реализация валидации может быть расположена и где-то вовне класса, а класс может просто делегировать вызов. Очень удобно, например на SubmitChanges проверять таким образом валидность измененных сущностей.
Эта схема хорошо работает только для одного вырожденного случая: когда пользователь интерактивно меняет какие-то свойства каких-то объектов.
Вот тут да, всё правильно. И валидация в объектах — самое оно, и Unit of Work к месту. И даже оптимистическая блокировка более-менее работает.
Потому, что позволяют генерировать UI в полуавтоматическом режиме, и при этом ничего существенно более полезного всё равно придумать нельзя — упираешься в произвольность пользовательских действий.

Обобщать этот подход на все остальные случаи — ошибка.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 07:12
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Сама реализация валидации может быть расположена и где-то вовне класса, а класс может просто делегировать вызов. Очень удобно, например на SubmitChanges проверять таким образом валидность измененных сущностей.

S>Эта схема хорошо работает только для одного вырожденного случая: когда пользователь интерактивно меняет какие-то свойства каких-то объектов.
S>Вот тут да, всё правильно. И валидация в объектах — самое оно, и Unit of Work к месту. И даже оптимистическая блокировка более-менее работает.
S>Потому, что позволяют генерировать UI в полуавтоматическом режиме, и при этом ничего существенно более полезного всё равно придумать нельзя — упираешься в произвольность пользовательских действий.

Ну наконец-то.

S>Обобщать этот подход на все остальные случаи — ошибка.


Я не считаю, что это такой уж вырожденный случай для корпоративных приложений. В них практически всегда присутствует интерактивное изменение свойств объектов.
Re[14]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 07:31
Оценка:
Здравствуйте, Tissot, Вы писали:
T>Я не считаю, что это такой уж вырожденный случай для корпоративных приложений. В них практически всегда присутствует интерактивное изменение свойств объектов.
Вопрос сложный. Конечно, везде есть какое-то редактирование справочников.

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

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

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


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


VGn>>Разъясните мне-идиоту зачем полиморфизм данным?


T>Данным, он наверное не нужен, а объектам domain model — вполне.


domain model не содержит данных?
Re[18]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 07:34
Оценка:
Здравствуйте, Tissot, Вы писали:

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


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


T>>>Понятие сложности — вопрос сугубо субъективный, никто тебе формулы для вычисления сложности не даст, придется с этим смириться.

G>>Как раз понятие сложности сущесвует объективно, а вот привычность (которую многие путают с удобством) — субъективно.
G>>Формула для вычисления сложности есть. Mantainability Index называется.

T>Не верю я в такие индексы. Та же Cyclomatic Complexity несложными манипуляциями с кодом уменьшается до требуемых показателей. Зачастую не надо даже разбираться, что код делает. Туфта все это.

Пример в студию.
Cyclomatic Complexity очень сильно чувствуешь на своей ж*** когда занимаешься whitebox-тестированием.
Очень даже объективный показатель, который работает для любых языков. И полипорфизм, за который вы тут так боретесь — именно средство уменьшения Cyclomatic Complexity.
Re[20]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 07:52
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Если ты внимательнее посмотришь validation app block, то увидишь, что в нем предусмотрен вариант для тех случаев, когда сущность сама себя валидирует.

G>>Всегда все можно сделать неправильно, и оно при этом даже будет работать.

T>

T>Если подсистему валидации нормально продизанить, то получится что-то вроде validation app block.

T>Так все-таки "нормально" или "неправильно"?
Нормально. Любая библиотека должна предоставлять множество возможностей, но какими стоит пользоваться, а какими — нет уже вам решать.

T>>>>>А данные — это набор атрибутов, следовательно обязанность "хранить данные" — это составная обязанность, которая может быть разбита на более мелкие.

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

G>>>>На моей первой работе был гениальный класс Queue (очередь), унаследованный от TStringList (на делфи). Содатели этого класса мотивировали удобством, хотя через интерфейс TStringList можно было нарушить работу класса очереди.

T>>>Неудачный пример.
G>>Почему? Удобно же.

T>Применим тот же самый метод повторно: вы вроде как говорили, что не следует смешивать данные и методы работы с ними. Означает ли это, что вы, следуя SRP спроектировали бы класс queue примерно так:

T>
T>public Queue {
T>  public object[] Data;
T>}
T>

T>а для изменения queue у вас есть специальный сервисный класс
T>
T>public QueueService {
T>  public void Enqueue(Queue data, object obj) {
T>  }
T>  public object Dequeue(Queue data) {
T>  }
T>}
T>


Не-а. В таком коде класс Queue не нужен, тем более он нарушет бредовый. Класс QueueService переименовываем в Queue, оставляем пару методов Enqueue, Dequeue и еще Count и всю реализацию прячим внутри Queue. И получаем нормальную очередь.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 07:54
Оценка:
Здравствуйте, gandjustas, Вы писали:

VGn>>>Разъясните мне-идиоту зачем полиморфизм данным?


T>>Данным, он наверное не нужен, а объектам domain model — вполне.


G>domain model не содержит данных?


Содержит, но это не голые данные, а именно domain model
Re[19]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 08:01
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Пример в студию.


Легко. Одна и величин, на которой основывается компексити — это кол-во if-ов. Часто бывает такой код выглядит так:
if (condition1())
  action1();
else if (condition2())
  action2();
...
else if (conditionN())
  actionN();

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

G>Cyclomatic Complexity очень сильно чувствуешь на своей ж*** когда занимаешься whitebox-тестированием.

G>Очень даже объективный показатель, который работает для любых языков. И полипорфизм, за который вы тут так боретесь — именно средство уменьшения Cyclomatic Complexity.

Не единственное средство.
Re[16]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 08:02
Оценка:
Здравствуйте, Tissot, Вы писали:

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


VGn>>>>Разъясните мне-идиоту зачем полиморфизм данным?


T>>>Данным, он наверное не нужен, а объектам domain model — вполне.


G>>domain model не содержит данных?


T>Содержит, но это не голые данные, а именно domain model


А что такое domain model? Интересует суть, а не цитаты из фаулера
Re[21]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 08:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Так все-таки "нормально" или "неправильно"?

G>Нормально. Любая библиотека должна предоставлять множество возможностей, но какими стоит пользоваться, а какими — нет уже вам решать.

Слив засчитан.

T>>Это иллюстрация того, что фанатизм до хорошего не доводит.

G>Это иллюстрация вашего непонимания SRP.

Обоснуй. Почему обязанность "хранить данные" не может быть разбита на более мелкие?
Только пожалуйста без аппелирования к тупости и необразованности своего собеседника. Спасибо.

T>>Применим тот же самый метод повторно: вы вроде как говорили, что не следует смешивать данные и методы работы с ними. Означает ли это, что вы, следуя SRP спроектировали бы класс queue примерно так:

T>>
T>>public Queue {
T>>  public object[] Data;
T>>}
T>>

T>>а для изменения queue у вас есть специальный сервисный класс
T>>
T>>public QueueService {
T>>  public void Enqueue(Queue data, object obj) {
T>>  }
T>>  public object Dequeue(Queue data) {
T>>  }
T>>}
T>>


G>Не-а. В таком коде класс Queue не нужен, тем более он нарушет бредовый. Класс QueueService переименовываем в Queue, оставляем пару методов Enqueue, Dequeue и еще Count и всю реализацию прячим внутри Queue. И получаем нормальную очередь.


Почему не нужен? Хранить данные — это ведь отдельная обязанность (с) gandjustas. Непоследовательно как-то получается.
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 08:08
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Содержит, но это не голые данные, а именно domain model


G>А что такое domain model? Интересует суть, а не цитаты из фаулера


domain model — это программное представление концепций предметной области, максимально к ней (области) приближенное.
Re[20]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 08:21
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>Пример в студию.


T>Легко. Одна и величин, на которой основывается компексити — это кол-во if-ов. Часто бывает такой код выглядит так:

T>
T>if (condition1())
T>  action1();
T>else if (condition2())
T>  action2();
T>...
T>else if (conditionN())
T>  actionN();

T>

T>Этот код тупо заменяется на словарь, где ключ — функция вычисляющая предикат, а в кач-ве значения — действие, которой надо выполнить, если предикат вернул true. И все, N ветвлений ушло.
Cyclomatic Complexity — это не количество ифов, а количество decision points, если у вас один if в цикле, то Cyclomatic Complexity такого куска равно количпеству проходов цикла.
Разница Cyclomatic Complexity видна когда занимаетесь тестированием кода.

T>Но это конечно простой случай, но к нему вполне можно свести многие ему подобные.

Такой код чаще всего получается при изначально плохом дизайне.

G>>Cyclomatic Complexity очень сильно чувствуешь на своей ж*** когда занимаешься whitebox-тестированием.

G>>Очень даже объективный показатель, который работает для любых языков. И полипорфизм, за который вы тут так боретесь — именно средство уменьшения Cyclomatic Complexity.

T>Не единственное средство.

Я и не говорил что единственное.
Re[22]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 08:39
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Так все-таки "нормально" или "неправильно"?

G>>Нормально. Любая библиотека должна предоставлять множество возможностей, но какими стоит пользоваться, а какими — нет уже вам решать.

T>Слив засчитан.

Ну это к MS.

T>>>Это иллюстрация того, что фанатизм до хорошего не доводит.

G>>Это иллюстрация вашего непонимания SRP.

T>Обоснуй. Почему обязанность "хранить данные" не может быть разбита на более мелкие?

T>Только пожалуйста без аппелирования к тупости и необразованности своего собеседника. Спасибо.

Сначала "от протвного". Если следовать вашему пониманию SRP, то любой класс, содержащий более одного публичного члена нарушает SRP.
Но SRP был придуман не идиотами и не прижился бы будь он настолько абсурден.

В исходном определении SRP "обязанность" модуля приравнивается к необходимости изменять модуль. Например необходимость менять класс сущности возникает только при изменении схемы данных, поэтому он не нарушает SRP. Если мы в тотже класс засунем бизнес-логику и валидацию, то уже появится три причины менять класс: изменение данных, изменение бизнес-логики, изменение валидации, поэтому будет нарушение SRP.
Такой принцип не точен математически, но общую картину позволяет получить.

T>>>Применим тот же самый метод повторно: вы вроде как говорили, что не следует смешивать данные и методы работы с ними. Означает ли это, что вы, следуя SRP спроектировали бы класс queue примерно так:

T>>>
T>>>public Queue {
T>>>  public object[] Data;
T>>>}
T>>>

T>>>а для изменения queue у вас есть специальный сервисный класс
T>>>
T>>>public QueueService {
T>>>  public void Enqueue(Queue data, object obj) {
T>>>  }
T>>>  public object Dequeue(Queue data) {
T>>>  }
T>>>}
T>>>


G>>Не-а. В таком коде класс Queue не нужен, тем более он нарушет бредовый. Класс QueueService переименовываем в Queue, оставляем пару методов Enqueue, Dequeue и еще Count и всю реализацию прячим внутри Queue. И получаем нормальную очередь.


T>Почему не нужен? Хранить данные — это ведь отдельная обязанность (с) gandjustas. Непоследовательно как-то получается.

"очередь" — это и есть одна обязанность класса. Для того чтобы быть полноценной очередью необходимо (и достаточно) реализиовать несколько членов, соотвествующих определенному контракту.
Re[18]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 08:43
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Содержит, но это не голые данные, а именно domain model


G>>А что такое domain model? Интересует суть, а не цитаты из фаулера


T>domain model — это программное представление концепций предметной области, максимально к ней (области) приближенное.

Не, какие там классы, за что отвечают итп. Можно с примерами
Re[21]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 08:51
Оценка:
Здравствуйте, gandjustas, Вы писали:

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

G>Cyclomatic Complexity — это не количество ифов, а количество decision points, если у вас один if в цикле, то Cyclomatic Complexity такого куска равно количпеству проходов цикла.

Ну тогда еще проще — уменьшаем кол-во проходов цикла до минимума и комплексити падает.
Ты неправильно понимаешь комплексити.

G>Разница Cyclomatic Complexity видна когда занимаетесь тестированием кода.


T>>Но это конечно простой случай, но к нему вполне можно свести многие ему подобные.

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

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

G>>>Очень даже объективный показатель, который работает для любых языков. И полипорфизм, за который вы тут так боретесь — именно средство уменьшения Cyclomatic Complexity.

T>>Не единственное средство.
G>Я и не говорил что единственное.

Пример, который я привел показывает технику, как эту комплексити можно снизить не вдаваясь в делали кода. При этом, хотя по формуле сложность уменьшается, де-факто она возрастает, т.к. такой код становится сложно читать, отаживать, модифицировать, т.е. то, что обыватель называет сложностью, на самом деле возрастает, не смотря на цифирки.
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 09:01
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Слив засчитан.

G>Ну это к MS.

Э, не. Это ты говорил, что "если нормально продизайнить систему ..."

T>>Обоснуй. Почему обязанность "хранить данные" не может быть разбита на более мелкие?

T>>Только пожалуйста без аппелирования к тупости и необразованности своего собеседника. Спасибо.

G>Сначала "от протвного". Если следовать вашему пониманию SRP, то любой класс, содержащий более одного публичного члена нарушает SRP.

G>Но SRP был придуман не идиотами и не прижился бы будь он настолько абсурден.

Но тем не менее, если публичным членом является метод, вы почему-то не считаете идиотами тех, кто выносит такие методы в сервисный класс. Как же так?

G>В исходном определении SRP "обязанность" модуля приравнивается к необходимости изменять модуль. Например необходимость менять класс сущности возникает только при изменении схемы данных, поэтому он не нарушает SRP.


Не, не понадобиться. Мы еще один класс заведем, с одним полем.

G>Если мы в тотже класс засунем бизнес-логику и валидацию, то уже появится три причины менять класс: изменение данных, изменение бизнес-логики, изменение валидации, поэтому будет нарушение SRP.


Поэтому валидацию мы разобъем на двести-пятьсят мелких классиков, чтобы если не дай бог понадобится что-то менять, изменения коснулись минимального объема кода. А еще лучше каждый такой класс вынести в отдельный проект. Шоб все поняли какой я крутой архитект.

G>Такой принцип не точен математически, но общую картину позволяет получить.


Жуткая какая-то картин вырисовывается.

G>>>Не-а. В таком коде класс Queue не нужен, тем более он нарушет бредовый. Класс QueueService переименовываем в Queue, оставляем пару методов Enqueue, Dequeue и еще Count и всю реализацию прячим внутри Queue. И получаем нормальную очередь.


T>>Почему не нужен? Хранить данные — это ведь отдельная обязанность (с) gandjustas. Непоследовательно как-то получается.

G>"очередь" — это и есть одна обязанность класса. Для того чтобы быть полноценной очередью необходимо (и достаточно) реализиовать несколько членов, соотвествующих определенному контракту.

Вот они и будут реализованы в сервисе, а сама очередь будет хранить данные.
Re[19]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 09:03
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>domain model — это программное представление концепций предметной области, максимально к ней (области) приближенное.

G>Не, какие там классы, за что отвечают итп.

Классы customer, customercotainer, location, department, person
Помогло?

G>Можно с примерами


Примеры можете посмтреть у Фаулера. Или у Эванса.
Re[22]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 09:12
Оценка:
Здравствуйте, Tissot, Вы писали:

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


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

G>>Cyclomatic Complexity — это не количество ифов, а количество decision points, если у вас один if в цикле, то Cyclomatic Complexity такого куска равно количпеству проходов цикла.
T>Ну тогда еще проще — уменьшаем кол-во проходов цикла до минимума и комплексити падает.
Ну покажите на вашем примере с кучей ифов как вы уменьшите Cyclomatic Complexity за счет таблицы.

T>Ты неправильно понимаешь комплексити.

А мне кажется что вы неправльно понимаете.

The cyclomatic complexity of a section of source code is the count of the number of linearly independent paths through the source code.


Так вот количество незвисимых путей не меняется.

G>>Разница Cyclomatic Complexity видна когда занимаетесь тестированием кода.


T>>>Но это конечно простой случай, но к нему вполне можно свести многие ему подобные.

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

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

На самом деле Cyclomatic Complexity при такой технике не меняется.
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 09:13
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Почему не нужен? Хранить данные — это ведь отдельная обязанность (с) gandjustas. Непоследовательно как-то получается.

S>В классе очереди хранение данных нам неинтересно. Поэтому такой обязанности вовсе нет.

А почему в entity мне должно быть это итересно? она сама по себе сохранением-то и не занимается.
Почему ради того, чтобы следовать SRP я должен выставлять все члены наружу?

S>Глумиться над SRP — неумно. Лучше попытаться всё же понять, как опытные собаководы проводят границы ответственности, и почему это делается именно так.


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

S>А кривляния в нашем деле не помогают.


Зато поднимают настроение
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 09:17
Оценка:
Здравствуйте, gandjustas, Вы писали:

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

G>>>Cyclomatic Complexity — это не количество ифов, а количество decision points, если у вас один if в цикле, то Cyclomatic Complexity такого куска равно количпеству проходов цикла.
T>>Ну тогда еще проще — уменьшаем кол-во проходов цикла до минимума и комплексити падает.
G>Ну покажите на вашем примере с кучей ифов как вы уменьшите Cyclomatic Complexity за счет таблицы.

Я написал же предельно понятно. Дойду до работы, скину примерчик. Можешь померить на нем комплексити до и после.

T>>Ты неправильно понимаешь комплексити.

G>А мне кажется что вы неправльно понимаете.

G>

G>The cyclomatic complexity of a section of source code is the count of the number of linearly independent paths through the source code.


G>Так вот количество незвисимых путей не меняется.


paths, a не проходов.

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

G>На самом деле Cyclomatic Complexity при такой технике не меняется.

См. выше.
Re[18]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 09.01.09 09:20
Оценка:
Здравствуйте, Tissot, Вы писали:

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

То есть, своих мыслей нет.

T>Не мог бы ты расшифровать RC?

Read committed

T>Если вы что-то не понятно в том, что выдает профайлер, можете выслать ваши затруднения сюда, попробуем разобраться.

Спасибо, но у меня нет никаких затруднений, так как я не использую ни ORM ни фаулеровский подход.. )

T>Почему LINQ2SQL не может быть отнесен в классическим ORM

Потому что классические ORM постороены на совсем другой идеологии и нагружены соответсвтующим функционалом. Если грубо, то они пляшут от объектной модели, в то время как LINQ, от данных.

T>и почему с его помощью нельзя построить domain model?

Можно, но не нужно, так как он для этого не предназначен и решает задачи по другому.

T>Держите свои эмоции при себе, не надо переходить на личности.

Я не перехожу, я интересуюсь. По всему видно, что не читал, просто придраться захотелось.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[16]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 09.01.09 09:20
Оценка:
Здравствуйте, Tissot, Вы писали:

T>У меня есть эта книжка. Не мог бы ты назвать раздел в котором говорится об этом? Спасибо

Там об этом вся книжка, пожалуйста. )

T>Стр. 52. О том, что я не буду переписывать Фаулера, я уже писал.

Нет ты уж потрудись, если на какой-то конструктив рассчитываешь, а не просто потрындеть пришел.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[22]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 09.01.09 09:20
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Напомню, что речь шла о использовании domain model.

Речь шла о твоем несогласии с изложенным мнением, вместо аргументов ты сослался на Фаулера, причем довольно абстрактно.
Отсюда делаем совершенно закономерный вывод, что своего мнения не имеется.

T>Надеюсь, вопрос исчерпан?

Уже давно, я свое мнение высказал, а просто так трепаться мне не интересно.

T>Какой такой неофит? 10 лет в отрасли.

... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[12]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 09.01.09 09:32
Оценка:
Здравствуйте, Tissot, Вы писали:

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

Ты же утверждал что читал объяснения на пальцах, что такое полиморфизм. Или опять делал это не внимательно?

T>Возможно, я не умею их готовить, но почему вы упорно продолжаете умалчивать о том, как это далать?

Где это я умалчиваю?

T>Про переходы на личности я уже писал в дугой ветке.

Можешь еще в ООН пожаловаться.

T>Ссылки, ссылки, ссылки.

В гугл сходи, набери LINQ.

T>А это наверное ваша жена написала в ваше отсутствие?

T>

T>Во-вторых, добавляя новое поведение, надо его просто добавлять, а не менять старое

А это тут причем? При изменении требований новое поведение должно добавляться без изменения старого, это для тебя новость?
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[24]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 09:36
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Слив засчитан.

G>>Ну это к MS.

T>Э, не. Это ты говорил, что "если нормально продизайнить систему ..."

и я же сказал что получится что-то вроде validation app block. MS в свою библиотеку включили разные возможности, но это не значит что их все всегда надо использовать.

T>>>Обоснуй. Почему обязанность "хранить данные" не может быть разбита на более мелкие?

T>>>Только пожалуйста без аппелирования к тупости и необразованности своего собеседника. Спасибо.

G>>Сначала "от протвного". Если следовать вашему пониманию SRP, то любой класс, содержащий более одного публичного члена нарушает SRP.

G>>Но SRP был придуман не идиотами и не прижился бы будь он настолько абсурден.
T>Но тем не менее, если публичным членом является метод, вы почему-то не считаете идиотами тех, кто выносит такие методы в сервисный класс. Как же так?
Я не считаю идиотами тех, кто следует SRP. Вынос метода в сервисные класс не самоцель.

G>>В исходном определении SRP "обязанность" модуля приравнивается к необходимости изменять модуль. Например необходимость менять класс сущности возникает только при изменении схемы данных, поэтому он не нарушает SRP.

T>Не, не понадобиться. Мы еще один класс заведем, с одним полем.
И не сможете обеспечить его персистентность.


G>>Если мы в тотже класс засунем бизнес-логику и валидацию, то уже появится три причины менять класс: изменение данных, изменение бизнес-логики, изменение валидации, поэтому будет нарушение SRP.

T>Поэтому валидацию мы разобъем на двести-пятьсят мелких классиков, чтобы если не дай бог понадобится что-то менять, изменения коснулись минимального объема кода. А еще лучше каждый такой класс вынести в отдельный проект. Шоб все поняли какой я крутой архитект.

G>>Такой принцип не точен математически, но общую картину позволяет получить.

T>Жуткая какая-то картин вырисовывается.

По существу есть что сказать?

G>>>>Не-а. В таком коде класс Queue не нужен, тем более он нарушет бредовый. Класс QueueService переименовываем в Queue, оставляем пару методов Enqueue, Dequeue и еще Count и всю реализацию прячим внутри Queue. И получаем нормальную очередь.


T>>>Почему не нужен? Хранить данные — это ведь отдельная обязанность (с) gandjustas. Непоследовательно как-то получается.

G>>"очередь" — это и есть одна обязанность класса. Для того чтобы быть полноценной очередью необходимо (и достаточно) реализиовать несколько членов, соотвествующих определенному контракту.

T>Вот они и будут реализованы в сервисе, а сама очередь будет хранить данные.

Еще раз. сама очередь — набор методов соотвествующих контракту. если вам требуется отдельно описывать хранение данных очереди, то вам понадобится отдельный класс QueueData и Queue будет параметризован инстансом QueueData.
Re[20]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 09:36
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>domain model — это программное представление концепций предметной области, максимально к ней (области) приближенное.

G>>Не, какие там классы, за что отвечают итп.

T>Классы customer, customercotainer, location, department, person

T>Помогло?

Да, прямо ER-модель получилась.
Re[19]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 10:41
Оценка:
Здравствуйте, IB, Вы писали:

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

IB>То есть, своих мыслей нет.

То есть иди на фик.

T>>Не мог бы ты расшифровать RC?

IB>Read committed

Спасибо посмотрю.

T>>Если вы что-то не понятно в том, что выдает профайлер, можете выслать ваши затруднения сюда, попробуем разобраться.

IB>Спасибо, но у меня нет никаких затруднений, так как я не использую ни ORM ни фаулеровский подход.. )

Нету там ничего простого и понятного, если приложение сложнее калькулятора.

А это у кого-то другого было, не у вас? Ну тогда действительно, не стоит объяснять.

T>>Почему LINQ2SQL не может быть отнесен в классическим ORM

IB>Потому что классические ORM постороены на совсем другой идеологии и нагружены соответсвтующим функционалом. Если грубо, то они пляшут от объектной модели, в то время как LINQ, от данных.

Тут вам виднее, мне доводилось общаться только с hibernate-ом и linq2sql-ом. Наверное в классических как-то иначе.

T>>и почему с его помощью нельзя построить domain model?

IB>Можно, но не нужно, так как он для этого не предназначен и решает задачи по другому.

Какой такой недостаток есть в LINQ2SQL-е, что он не позволяет построить domain model?
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 10:45
Оценка:
Здравствуйте, IB, Вы писали:

T>>Стр. 52. О том, что я не буду переписывать Фаулера, я уже писал.

IB>Нет ты уж потрудись, если на какой-то конструктив рассчитываешь, а не просто потрындеть пришел.

Еще раз прошу не переходить на личности. Если вам так хочется сказть мне что-то лично, мы можем встретиться и обсудить это в приватной беседе.
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 10:49
Оценка:
Здравствуйте, IB, Вы писали:

T>>Напомню, что речь шла о использовании domain model.

IB>Речь шла о твоем несогласии с изложенным мнением, вместо аргументов ты сослался на Фаулера, причем довольно абстрактно.
IB>Отсюда делаем совершенно закономерный вывод, что своего мнения не имеется.

Мне кажется, я уже упоминал, что обсуждается не мнение (и уж тем более не их авторство), а идеи.

P.S. Всего доброго и берегите нервы. Отвечать на ваши сообщения я больше не намерен. Если вы имеете что мне сказать, можете связаться со мной и обсудить интересующие вас вопросы и проблемы в приватной беседе, в офлайне. Всего доброго.
Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>А почему в entity мне должно быть это итересно? она сама по себе сохранением-то и не занимается.

T>>Почему ради того, чтобы следовать SRP я должен выставлять все члены наружу?
S>Ты слишком много думаешь об entity.

S>В нормальной системе entity моделируют нижележащие данные, которые и есть предметная область.


В этом и предмет разногласия. Для domain model "нижележащие данные" — это всего лишь способ долговременного хранения сущностей.

S>То, что сами эти данные в свою очередь являются моделью чего-то еще, в этот момент несущественно.


S>У данных есть только одна обязанность — "быть". Способ сохранения данных ортогонален самим данным. То, что атрибут "зарплата" не может быть меньше нуля — ортогонально структуре "карточка сотрудника". Алгоритм капитализации ФИО ортогонален структуре "Карточка сотрудника".


Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

S>Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.


И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.

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

S>Ты слишком много думаешь о классах. Выносить за пределы класса нужно всё, что можно вынести за пределы класса.
S>Поскольку публичный контракт "сущности" сводится к умению группировать данные, то 100% поведения должно быть вынесено за ее пределы.

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

T>>Зато поднимают настроение

S>Заранее намекаю: злоупотребление некошерными методами подъема настроения на этом форуме чревато воспитательными мерами.

Ок, не буду.
Re[21]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:03
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Классы customer, customercotainer, location, department, person

T>>Помогло?

G>Да, прямо ER-модель получилась.


Не, получилась вполне себе rich domain model
Re[21]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:09
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Классы customer, customercotainer, location, department, person

T>>Помогло?
S>А чему в предметной области соответствует customercontainer?

Да. Это понятие, которыем оперируют те, кто продает услуги кастомерам.

S>Вообще, как правило структура данных не совпадает с устройством предметной области. Она иногда на неё похожа, но это иллюзорное сходство.

S>Простейший пример — есть список кастомеров. Надо понимать, во-первых, что элементами списка являются не кастомеры, а записи о кастомерах.

Вы забыли добавить "при моем подходе". Если используем domain model, то вполне себе customer-ы, точнее их программное представление в domain model.

S>Во-вторых, что сам список кастомеров в "предметной области" может быть организован, к примеру, в виде Post-it бумажек, наклеенных на whiteboard.


Это не кастомер, это способ хранения информации о кастомере.

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

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

Это некорректная аналогия, т.к. моделировать нужно не листочки о кастомерах, а их самих.

S>При этом в entity "customer" появятся какие-то атрибуты, которые не имеют никакого отношения ни к реальным покупателям, ни к доске, ни к бумажкам.


Ближе к телу. Что за атрибуты?

S>Этакие "артефакты модели". Задача "максимально приблизиться к предметной области" звучит хорошо, но работает плохо. Мне больше нравится задача "придумать максимально простую модель предметной области, которая покрывает максимальное количество пользовательских сценариев".


Такой моделью как раз и является domain model
Re[22]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 11:17
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Классы customer, customercotainer, location, department, person

T>>>Помогло?

G>>Да, прямо ER-модель получилась.


T>Не, получилась вполне себе rich domain model

И чем же она Rich?

например location, чтобы быть локейшеном надо какие-то данные о местоположении содержать, этодо достаточно. Вполне себе ER-модель (сущность и атрибуты).
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:27
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Ну тогда еще проще — уменьшаем кол-во проходов цикла до минимума и комплексити падает.

G>Ну покажите на вашем примере с кучей ифов как вы уменьшите Cyclomatic Complexity за счет таблицы.

Вот пример:
//#define COMPLEX

#if !COMPLEX
using System;
using System.Collections.Generic;
#endif

namespace ConsoleApplication1 {
    class Program {
        private enum State { One, Two, Three, Four, Five }

        #if !COMPLEX
        private static readonly IDictionary<State, Action> _mapping = new Dictionary<State, Action> {
            { State.One, Action1 },
            { State.Two, Action2 },
            { State.Three, Action3 },
            { State.Four, Action4 },
            { State.Five, Action5 },
        };
        #endif

        private static void Main() {
            State state = GetState();
            #if !COMPLEX
            _mapping[state]();
            #endif

            #if COMPLEX
            if (state == State.One)
                Action1();
            if (state == State.Two)
                Action2();
            if (state == State.Three)
                Action3();
            if (state == State.Four)
                Action4();
            if (state == State.Five)
                Action5();
            #endif
        }

        private static State GetState() {
            return State.One;
        }

        private static void Action1() {
        }

        private static void Action2() {
        }

        private static void Action3() {
        }

        private static void Action4() {
        }

        private static void Action5() {
        }
    }
}


Померьте комплексити в таком коде, потом раскомментите первую строчку и померьте еще раз. Мне студия насчитала 9 и 13 соответственно.
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:29
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Не, получилась вполне себе rich domain model

G>И чем же она Rich?

G>например location, чтобы быть локейшеном надо какие-то данные о местоположении содержать, этодо достаточно. Вполне себе ER-модель (сущность и атрибуты).


ER-содель — это когда только сущность и атрибуты. Появляются методы, она уже перестает быть ER.
Re[26]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 11:33
Оценка:
Здравствуйте, Tissot, Вы писали:

S>>У данных есть только одна обязанность — "быть". Способ сохранения данных ортогонален самим данным. То, что атрибут "зарплата" не может быть меньше нуля — ортогонально структуре "карточка сотрудника". Алгоритм капитализации ФИО ортогонален структуре "Карточка сотрудника".


T>Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

Определитесь с терминологией. С точки зрения ER-моделирования есть сущности, которые группирую данные, у сущностей есть атрибуты — сами данные, сущности могут быть свзяаны между собой. Перенеся все это на ООП получаются классы и свойства, атрибуты сущностей — простые свойства, связи могут быть выражены сложными свойствами. Ортогональность валидации и способу хранения остается.
Может под "сущностью" вы имеете ввиду "объекты предметной области по фаулеру"?

S>>Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.

T>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.
Причем тут хранилище? Сущности ортогональны хранилищу.

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

S>>Ты слишком много думаешь о классах. Выносить за пределы класса нужно всё, что можно вынести за пределы класса.
S>>Поскольку публичный контракт "сущности" сводится к умению группировать данные, то 100% поведения должно быть вынесено за ее пределы.

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

Эти "инварианты" ортогональны сущности, поскольку могут меняться со временем. В отличие от класса очереди, где инварианты обеспечивают то что класс действительно является очередью.
Re[27]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:54
Оценка:
Здравствуйте, Sinclair, Вы писали:


T>>Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

S>Вот именно! Замечательное свойство ортогональности исчезает, как только карточку начинают наделять сущностью. Чем отличается сущность от карточки? Правильно, наличием поведения. Ну так вот у карточки нет никакого поведения.

У карточки нет поведения, но мы моделируем не карточки, а то, представлением чего являются карточки.

S>Искусственно внедрять в неё поведение можно, но от этого получаются негативные эффекты.


Искуственно и не надо, надо естественно внедрять.

T>>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.

S>Вот как раз контракт взаимодействия с хранилищем может запросто поменяться. Сегодня XML, завтра CSV, послезавтра — RDBMS. Сами данные при этом, естественно, останутся всё теми же.

Под контрактом взаимодействия с хранилищем я имел в виду интерфейс сущности, которым оперирует слой персистентности. От того, что мы меняем механизм хранения, это интерфейс не меняется.

T>>Не только к умению группировать но и к сохранению инвариантов.

S>У данных почти что нет инвариантов. Я уже об этом писал.

А я про данные и не говорю, я говорю о сущностях domain model. Прошу прощения, если неясно выразился.

S>Вот только что в нашем продукте напоролись: встроенная валидация хочет не более 8 символов для зипкода. В Иране — 10. Прощай, инвариант.


Не прощай инвариант, а здравствуй domain model. Кроме zip-кода надо проверить еще и страну и в зависимости от страны выбирать ту или иную стратегию валидации.

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

S>Данные — это данные. Их никак не поломаешь. Даже null/not null — и то зачастую чрезмерно жесткие ограничения для статической формализации.
S>Очень немногие "инварианты" заслуживают встраивания в "сущность".

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

S>Как правило, в бизнесе вместо них есть пред- и пост-условия. Но они применимы не к "данным", а к "операции над данными". А операции над данными, как мы уже договорились, лежат снаружи — в некоем Manager или Service. Вот в нём да — нужно обеспечивать "неломаемость" операций.


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

S>Захочется поспорить — попробуй привести примеры "реализации функционала, который может поломать сущность, будучи размещенным извне".

update orderitem set qty = -100
Re[28]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 12:00
Оценка:
Здравствуйте, Tissot, Вы писали:

S>>>>Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.

T>>>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.
G>>Причем тут хранилище? Сущности ортогональны хранилищу.
T>Нет, сущность не ортогонально зхранилищу, т.к. именно хранилище определяет что именно, какие атрибуты у нас в сущности.
Если храним в XML, то одни атрибуты, а если храним в БД, то другие?

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

G>>Эти "инварианты" ортогональны сущности, поскольку могут меняться со временем.

T>Нет, не ортогональны. Инвариант не должно быть разрешено нарушать. Если вы оставляете все поля сущности открытыми, вы не сожете гарантировать сохранность инватиантов.

Так бизнес-правила не являются инвариантами для сущностей (фактически данных).
Простой пример. Есть бизнес-правило, что ЗП сотридника не должна быть меньше МРОТ. Был у нас МРОТ 2000 рублей и были сотрудники с ЗП 2500, тут МРОТ увеличили до 4000 рублей. Если мы оформляем бизнес-правило как инвариант сущности, то становится все плохо, сотрудник с ЗП ниже 4000 даже не может быть считан из базы, возникнет ошибка и исравить её можно только прямой правкой данных в базе.
Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:09
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Померьте комплексити в таком коде, потом раскомментите первую строчку и померьте еще раз. Мне студия насчитала 9 и 13 соответственно.

G>В таком коде действительно сложность уменьшилась. Причем как формальный показатель CyclomaticComplexity, так и фактическая сложность чтения\сопровождения\расширения.

Я не считаю, что сложность уменьшилась. Меньшее кол-во строчек еще не показатель. Кроме того, в код внесена ошибка.

G>Но вы вначала привели другой:

G>
G>if (condition1())
G>  action1();
G>else if (condition2())
G>  action2();
G>...
G>else if (conditionN())
G>  actionN();
G>

G>Предположим что все conditionN зависят от одного набора параметров (уже достаточно сильное условие), даже если вы сформируете список из пар (предикат, действие), то вам придется в цикле ходить по этому списку и проверять если предикат истинный, то выполнить действие.
G>Такое преобразование не уменьшит CyclomaticComplexity.

Не знаю, может и не уменьшит, может и уменьшить. Добавь var action = _mapping.FirstOrDefault(x => x.Key(state)).Value вот и весь цикл.
Цель примера была не в том, чтобы доказать, что всегда есть способ облапошить комплексити, а в том, что такие ситуации встречаются и уже на этом основании нельзя особо полагаться на этот показатель.

G>Вот если у вас предикат одинаковый, а параметры разные, то это можно свести к таблице или паттернам состояние\стратегия.


И ты считаешь, что это проще? Вместе нескольких if-ов генерить интерфес стратегии + классы реализующие интерфейс.
Re[28]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 12:17
Оценка:
Здравствуйте, Tissot, Вы писали:

S>>Вот только что в нашем продукте напоролись: встроенная валидация хочет не более 8 символов для зипкода. В Иране — 10. Прощай, инвариант.


T>Не прощай инвариант, а здравствуй domain model. Кроме zip-кода надо проверить еще и страну и в зависимости от страны выбирать ту или иную стратегию валидации.


Вот на этом месте начинают сыпаться все преимущества Domain Model.

Представляем себе код:
public class Customer
{
  private ZipCodeValidationStrategy _zipCodeValidationStrategy;

  ...
  public string ZipCode
  {
    get {return _zipCode;}
    set
    {
      if(_zipCodeValidationStrategy.Validate(value))
      {
         _zipCode = value;
      }
    }
  }
}

Вот теперь вопрос, как кастомер получает zipCodeValidationStrategy? Сам класс инстанцировать zipCodeValidationStrategy не может потому что от страны, а страна хранится где-то еще.
Это значит маппер должен уметь инжектить переданный ему инстанс стратегии в создаваемую сущность. С другой стороны при ручном создании инстанса надо инжектить такуюже стратегию.
Учитывая что не все мапперы позволяют перехватывать процесс создания объектов получается не очень хорошо.
Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:19
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>ER-содель — это когда только сущность и атрибуты. Появляются методы, она уже перестает быть ER.

G>По каким причинам они могут там появиться не нарушая SRP и другие принципы хорошего дизайна?

По той причине, чтобы не дать перевести сущность/модель в невалидное состояние. Я же об этом уже писал.

G>Например какие методы могут появиться у location, ну кроме переопределения Equals и ToString?


Ну например, при закрытии location-а equipment, расположеный в этом location-е должен быть переведен в статус "неактивный".
Как мне соблюсти это правило, если всем доступны напрямую все сущности (как в er-модели)?
Re[29]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:27
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Причем тут хранилище? Сущности ортогональны хранилищу.

T>>Нет, сущность не ортогонально зхранилищу, т.к. именно хранилище определяет что именно, какие атрибуты у нас в сущности.
G>Если храним в XML, то одни атрибуты, а если храним в БД, то другие?

Кончай уже. Если у тебя er, то как тебе это поможет?


G>Простой пример. Есть бизнес-правило, что ЗП сотридника не должна быть меньше МРОТ. Был у нас МРОТ 2000 рублей и были сотрудники с ЗП 2500, тут МРОТ увеличили до 4000 рублей. Если мы оформляем бизнес-правило как инвариант сущности, то становится все плохо, сотрудник с ЗП ниже 4000 даже не может быть считан из базы, возникнет ошибка и исравить её можно только прямой правкой данных в базе.


Нет, не так. Инвариант будет несколько сложнее: МРОТ не существует один раз на веки вечные. Это некоторый закон, который начинает действовать с какого-то времени и теряет силу после того, как принят следующий мрот. Поэтому если уж ты проверяешь инвариант при загрузке сущности (кстати, зачем?), то ты должен взять последнюю дату модификации зарплаты и удостовериться, что зарплата не меньше значения, установленного законодательством не тот момент.
Re[29]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:33
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Вот на этом месте начинают сыпаться все преимущества Domain Model.


Посмотрим.

G>Представляем себе код:

G>
G>public class Customer
G>{
G>  private ZipCodeValidationStrategy _zipCodeValidationStrategy;

G>  ...
G>  public string ZipCode
G>  {
G>    get {return _zipCode;}
G>    set
G>    {
G>      if(_zipCodeValidationStrategy.Validate(value))
G>      {
G>         _zipCode = value;
G>      }
G>    }
G>  }
G>}
G>

G>Вот теперь вопрос, как кастомер получает zipCodeValidationStrategy? Сам класс инстанцировать zipCodeValidationStrategy не может потому что от страны, а страна хранится где-то еще.

Где-то еще — это где? Я предполагал, что у кастомера и так есть страна. Тогда получить валидацию можно так:
ZipCodeValidationStrategyFacory.GetByCountryCode(this.CountryCode)


G>Это значит маппер должен уметь инжектить переданный ему инстанс стратегии в создаваемую сущность. С другой стороны при ручном создании инстанса надо инжектить такуюже стратегию.

G>Учитывая что не все мапперы позволяют перехватывать процесс создания объектов получается не очень хорошо.

А теперь рассказывай, как ты будешь с этим бороться:

update customer set zipCode = "любой невалидный zip";
Re[26]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 12:42
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Померьте комплексити в таком коде, потом раскомментите первую строчку и померьте еще раз. Мне студия насчитала 9 и 13 соответственно.

G>>В таком коде действительно сложность уменьшилась. Причем как формальный показатель CyclomaticComplexity, так и фактическая сложность чтения\сопровождения\расширения.

T>Я не считаю, что сложность уменьшилась. Меньшее кол-во строчек еще не показатель.

Еще как уменьшилась.
1)Структурированность кода стала выше, в сами ифы стало невозможно дописывать
2)Из-за сокращения объема кода он стал нашляднее, проще читать, следовательно меньше ошибок будет допущено, быстрее они будут выявлены.
3)Стало невозможно допустить ошибку недописывания else перед новым if при добавлении условия
Кроме того появилась дополнительная гибкость — появилась возможность формировать таблицу действий в run-time.
Почитайте книгу "жемчужины программирования", так описаны такие преобразования.

T>Кроме того, в код внесена ошибка.

какая?

G>>Но вы вначала привели другой:

G>>
G>>if (condition1())
G>>  action1();
G>>else if (condition2())
G>>  action2();
G>>...
G>>else if (conditionN())
G>>  actionN();
G>>

G>>Предположим что все conditionN зависят от одного набора параметров (уже достаточно сильное условие), даже если вы сформируете список из пар (предикат, действие), то вам придется в цикле ходить по этому списку и проверять если предикат истинный, то выполнить действие.
G>>Такое преобразование не уменьшит CyclomaticComplexity.

T>Не знаю, может и не уменьшит, может и уменьшить. Добавь var action = _mapping.FirstOrDefault(x => x.Key(state)).Value вот и весь цикл.

Так тоже CyclomaticComplexity уменьшается (фактически придется меньше тестов писать), но в этом случае общая сложность решения не изменилась. Хотя некоторые преимущества появились.

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

Вы доказали что качество кода состоит не только из CyclomaticComplexity, а из многих составляющих. Но это и так известно.

G>>Вот если у вас предикат одинаковый, а параметры разные, то это можно свести к таблице или паттернам состояние\стратегия.

T>И ты считаешь, что это проще? Вместе нескольких if-ов генерить интерфес стратегии + классы реализующие интерфейс.
Если это код, подверженный частым изменениям, то проще. Иначе можно ограничиться таблицей.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:47
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Но с дальнейшим ростом аппетитов оказывается, что ввод данных стоит в самом начале длинной цепочки. Грубо говоря, логика комплектования заказа по складам и группировки заказов для оптимальной доставки получается значительно тяжелее, чем вся форма ввода заказа и свойств контрагента.


S>Вот тут-то у архитектора и наступает просветление. То, что вначале казалось таким приятным и удобным, теперь висит тяжелым грузом и сдерживает дальнейшее наращивание бизнес-логики, а также масштабирование системы.


Возможно, я не сталкивался сподобного рода задачами, но мне доводилось работать с достаточно крупной erp-системой (Axapta).
Там как раз было реализовано именно так, как я описывал — через объектную модель. Слышал краем уха что в том же SAP-е реализовано примерно таким же образом — логика не в базе, запросах, а в appserver cлое. Если все так плохо с работать через объектную модель, то почему в этих системах было реализовано именно так? Неужели тоже из-за недостатка опыта проектировщиков?
Re[26]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 12:50
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>ER-содель — это когда только сущность и атрибуты. Появляются методы, она уже перестает быть ER.

G>>По каким причинам они могут там появиться не нарушая SRP и другие принципы хорошего дизайна?
T>По той причине, чтобы не дать перевести сущность/модель в невалидное состояние. Я же об этом уже писал.
Да пусть будет в невалидном состоянии, главное чтобы сущность не была сохранена в невалидном состоянии. Но это обеспечивается другими средствами.

G>>Например какие методы могут появиться у location, ну кроме переопределения Equals и ToString?

T>Ну например, при закрытии location-а equipment, расположеный в этом location-е должен быть переведен в статус "неактивный".
T>Как мне соблюсти это правило, если всем доступны напрямую все сущности (как в er-модели)?

service.CloseLocation(licationId), остальное происходит внутри метода. А тот кто вызывает этот метод не имеет возможности сохранить в базе этот location.
Re[27]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:56
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Я не считаю, что сложность уменьшилась. Меньшее кол-во строчек еще не показатель.

G>Еще как уменьшилась.
G>1)Структурированность кода стала выше, в сами ифы стало невозможно дописывать
G>2)Из-за сокращения объема кода он стал нашляднее, проще читать, следовательно меньше ошибок будет допущено, быстрее они будут выявлены.
G>3)Стало невозможно допустить ошибку недописывания else перед новым if при добавлении условия

Но не забывай, что все это путем усложнения сруктуры класса — разные action-ы пришлось вынести в отдельные методы.

G>Кроме того появилась дополнительная гибкость — появилась возможность формировать таблицу действий в run-time.


А оно надо?

G>Почитайте книгу "жемчужины программирования", так описаны такие преобразования.


Я тебе это преобразование 5 минут назад запостил. Ты считаешь я его не знаю.

T>>Кроме того, в код внесена ошибка.

G>какая?

Найди.

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

G>Вы доказали что качество кода состоит не только из CyclomaticComplexity, а из многих составляющих. Но это и так известно.

Я показал, что один из коэффициентов, входящий MaintainabilyIndex вполне может быть обманут. А следовательно и сам index под подозрением.

G>>>Вот если у вас предикат одинаковый, а параметры разные, то это можно свести к таблице или паттернам состояние\стратегия.

T>>И ты считаешь, что это проще? Вместе нескольких if-ов генерить интерфес стратегии + классы реализующие интерфейс.
G>Если это код, подверженный частым изменениям, то проще. Иначе можно ограничиться таблицей.

Кому как, а по-моему это явный overdesign — когда простой if заменяется на непойми что.
Re[27]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:59
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>По той причине, чтобы не дать перевести сущность/модель в невалидное состояние. Я же об этом уже писал.

G>Да пусть будет в невалидном состоянии, главное чтобы сущность не была сохранена в невалидном состоянии. Но это обеспечивается другими средствами.

Какими?

T>>Ну например, при закрытии location-а equipment, расположеный в этом location-е должен быть переведен в статус "неактивный".

T>>Как мне соблюсти это правило, если всем доступны напрямую все сущности (как в er-модели)?

G>service.CloseLocation(licationId), остальное происходит внутри метода. А тот кто вызывает этот метод не имеет возможности сохранить в базе этот location.


Зато данные не защищены от поломки из других сервисов
Re[30]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:04
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>Где-то еще — это где? Я предполагал, что у кастомера и так есть страна. Тогда получить валидацию можно так:

T>
T>ZipCodeValidationStrategyFacory.GetByCountryCode(this.CountryCode)
T>

Вместо кастомера можно ченить еще придумать, где параметр валидации не находися в самой сущности.

G>>Это значит маппер должен уметь инжектить переданный ему инстанс стратегии в создаваемую сущность. С другой стороны при ручном создании инстанса надо инжектить такуюже стратегию.

G>>Учитывая что не все мапперы позволяют перехватывать процесс создания объектов получается не очень хорошо.

T>А теперь рассказывай, как ты будешь с этим бороться:


T>
T>update customer set zipCode = "любой невалидный zip";
T>


С этим вообще никак нельзя бороться, если кто угодно может получить доступ к базе, то смысла нет городить валидацию в приложении. Но это вопрос администрирования.
Re[31]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 13:09
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Где-то еще — это где? Я предполагал, что у кастомера и так есть страна. Тогда получить валидацию можно так:

T>>
T>>ZipCodeValidationStrategyFacory.GetByCountryCode(this.CountryCode)
T>>

G>Вместо кастомера можно ченить еще придумать, где параметр валидации не находися в самой сущности.

Нпример?

T>>А теперь рассказывай, как ты будешь с этим бороться:


T>>
T>>update customer set zipCode = "любой невалидный zip";
T>>


G>С этим вообще никак нельзя бороться, если кто угодно может получить доступ к базе, то смысла нет городить валидацию в приложении. Но это вопрос администрирования.


Я имею в виду если кто-то выставит невалидный zip в приложении и сасабмитит в базу.
Re[30]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:10
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>Причем тут хранилище? Сущности ортогональны хранилищу.

T>>>Нет, сущность не ортогонально зхранилищу, т.к. именно хранилище определяет что именно, какие атрибуты у нас в сущности.
G>>Если храним в XML, то одни атрибуты, а если храним в БД, то другие?

T>Кончай уже. Если у тебя er, то как тебе это поможет?

Я смысл фразы "сущность не ортогонально зхранилищу" пытаюсь понять.


G>>Простой пример. Есть бизнес-правило, что ЗП сотридника не должна быть меньше МРОТ. Был у нас МРОТ 2000 рублей и были сотрудники с ЗП 2500, тут МРОТ увеличили до 4000 рублей. Если мы оформляем бизнес-правило как инвариант сущности, то становится все плохо, сотрудник с ЗП ниже 4000 даже не может быть считан из базы, возникнет ошибка и исравить её можно только прямой правкой данных в базе.


T>Нет, не так. Инвариант будет несколько сложнее: МРОТ не существует один раз на веки вечные. Это некоторый закон, который начинает действовать с какого-то времени и теряет силу после того, как принят следующий мрот. Поэтому если уж ты проверяешь инвариант при загрузке сущности (кстати, зачем?), то ты должен взять последнюю дату модификации зарплаты и удостовериться, что зарплата не меньше значения, установленного законодательством не тот момент.

То есть нам еще надо будет хранить сведения об истории изменения МРОТ, при каждом измении ЗП и лезть в базу за проверкой значения МРОТ...

Вот и проблемы Domain Model на лице, нереальное стремление к тяжеловесности решений. Это даже фаулер в своей книге упоминает, но как-то всколзь, как-будто это нормально.
Re[31]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 13:23
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Кончай уже. Если у тебя er, то как тебе это поможет?

G>Я смысл фразы "сущность не ортогонально зхранилищу" пытаюсь понять.

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

T>>Нет, не так. Инвариант будет несколько сложнее: МРОТ не существует один раз на веки вечные. Это некоторый закон, который начинает действовать с какого-то времени и теряет силу после того, как принят следующий мрот. Поэтому если уж ты проверяешь инвариант при загрузке сущности (кстати, зачем?), то ты должен взять последнюю дату модификации зарплаты и удостовериться, что зарплата не меньше значения, установленного законодательством не тот момент.

G>То есть нам еще надо будет хранить сведения об истории изменения МРОТ, при каждом измении ЗП и лезть в базу за проверкой значения МРОТ...

Конечно. Так и делают. Закон редко когда вступает в силу с момента публикации, как правило отдельно оговаривается с какой даты в будущем он начинает действовать.

G>Вот и проблемы Domain Model на лице, нереальное стремление к тяжеловесности решений. Это даже фаулер в своей книге упоминает, но как-то всколзь, как-будто это нормально.


Это не сложность привнесенная domain model, а сложность предметной области. В er тебе тоже пришлось бы хранить этот инвариант в том или ином виде.

P.S. Кстати, а зачем тебе валидировать сущность при загрузке?
Re[28]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:23
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>По той причине, чтобы не дать перевести сущность/модель в невалидное состояние. Я же об этом уже писал.

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

T>>>Ну например, при закрытии location-а equipment, расположеный в этом location-е должен быть переведен в статус "неактивный".

T>>>Как мне соблюсти это правило, если всем доступны напрямую все сущности (как в er-модели)?

G>>service.CloseLocation(licationId), остальное происходит внутри метода. А тот кто вызывает этот метод не имеет возможности сохранить в базе этот location.


T>Зато данные не защищены от поломки из других сервисов

Для проверки такого есть тесты.
Re[32]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:26
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Где-то еще — это где? Я предполагал, что у кастомера и так есть страна. Тогда получить валидацию можно так:

T>>>
T>>>ZipCodeValidationStrategyFacory.GetByCountryCode(this.CountryCode)
T>>>

G>>Вместо кастомера можно ченить еще придумать, где параметр валидации не находися в самой сущности.
T>Нпример?
Просто представьте что такой кастомер.

T>>>А теперь рассказывай, как ты будешь с этим бороться:


T>>>
T>>>update customer set zipCode = "любой невалидный zip";
T>>>


G>>С этим вообще никак нельзя бороться, если кто угодно может получить доступ к базе, то смысла нет городить валидацию в приложении. Но это вопрос администрирования.


T>Я имею в виду если кто-то выставит невалидный zip в приложении и сасабмитит в базу.

1)в приложении все подряд не могут сабмитить в базу.
2)Есть тесты, которые проверят правильность работы логики
3)Саму валидацию на всех уровнях никто не отменял, но она содержится не классах сущностей, а вне их.
Re[29]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 13:27
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>1)Структурированность кода стала выше, в сами ифы стало невозможно дописывать

G>>>2)Из-за сокращения объема кода он стал нашляднее, проще читать, следовательно меньше ошибок будет допущено, быстрее они будут выявлены.
G>>>3)Стало невозможно допустить ошибку недописывания else перед новым if при добавлении условия

T>>Но не забывай, что все это путем усложнения сруктуры класса — разные action-ы пришлось вынести в отдельные методы.

G>Это разве плохо? Обычно считается что разные методы (особенно небольшие) — это замечательно.

Все хорошо в меру.

G>>>Кроме того появилась дополнительная гибкость — появилась возможность формировать таблицу действий в run-time.

T>>А оно надо?
G>А кто знает, может и надо. Любой код стоит рассматривать с точки зрения дальнейшиго расширения.

Этот вопрос заслуживает отдельного флейма. Давай не будем.

T>>Я показал, что один из коэффициентов, входящий MaintainabilyIndex вполне может быть обманут. А следовательно и сам index под подозрением.

G>Чем обманут? в приведенных примерах CyclomaticComplexity снижался, но снижения одного мараметра в маленьком куске кода на сложность проекта вообще не влияет. MaintainabilyIndex работает для больших кусков. Я об этом писал.

Размер тут большого значения не имеет. Смогли скомпрометировать в одном месте, сможем и везде.

T>>Кому как, а по-моему это явный overdesign — когда простой if заменяется на непойми что.

G>Любой код стоит рассматривать с точки зрения дальнейшиго расширения.
G>А вы только АКПП Фаулера читали? Еще Рефакторинг почитайте, там один из первых примеров как раз такой.

Спасибо за заботу, но я его уже читал лет этак 5 назад.
Re[29]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 13:31
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>>>По той причине, чтобы не дать перевести сущность/модель в невалидное состояние. Я же об этом уже писал.

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

Как она будет вызываться? Если какой-то сервис не станет ее вызывать, получим невалидные данные?

G>>>service.CloseLocation(licationId), остальное происходит внутри метода. А тот кто вызывает этот метод не имеет возможности сохранить в базе этот location.


T>>Зато данные не защищены от поломки из других сервисов

G>Для проверки такого есть тесты.

Если автор не захотел писать тест или автор — третье лицо, то смиримся с тем, что данные могут поломать?
Re[30]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:34
Оценка:
Здравствуйте, Tissot, Вы писали:

T>>>Я показал, что один из коэффициентов, входящий MaintainabilyIndex вполне может быть обманут. А следовательно и сам index под подозрением.

G>>Чем обманут? в приведенных примерах CyclomaticComplexity снижался, но снижения одного мараметра в маленьком куске кода на сложность проекта вообще не влияет. MaintainabilyIndex работает для больших кусков. Я об этом писал.

T>Размер тут большого значения не имеет. Смогли скомпрометировать в одном месте, сможем и везде.

А кто-то говорил про универсальность MaintainabilyIndex? Смотреть MaintainabilyIndex для частей проекта (классов, методов) полезно только для определения что влияет на индекс. Само значение индекса для одного класса\метода смысла практически не имеет.

Например запихнув все в один класс (domain model и active record) вы получите в этом классе маленький MaintainabilyIndex, но вам придется немало кода написать чтобы маппер инжектил все параметры в такой класс что сильно негативно повлияет на MaintainabilyIndex всего проекта.
Re[33]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 13:35
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Вместо кастомера можно ченить еще придумать, где параметр валидации не находися в самой сущности.

T>>Нпример?
G>Просто представьте что такой кастомер.

Какой такой? Если есть страна, то она где-то хранится. Следовательно её всегда можно узнать.

G>>>С этим вообще никак нельзя бороться, если кто угодно может получить доступ к базе, то смысла нет городить валидацию в приложении. Но это вопрос администрирования.


T>>Я имею в виду если кто-то выставит невалидный zip в приложении и сасабмитит в базу.

G>1)в приложении все подряд не могут сабмитить в базу.

"кто-то" — какой-то сервис

G>2)Есть тесты, которые проверят правильность работы логики


А так она (валидация) будет в одном месте — в модели.

G>3)Саму валидацию на всех уровнях никто не отменял, но она содержится не классах сущностей, а вне их.


Где? Когда вызывается?
Re[30]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:39
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>>>По той причине, чтобы не дать перевести сущность/модель в невалидное состояние. Я же об этом уже писал.

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

T>Как она будет вызываться? Если какой-то сервис не станет ее вызывать, получим невалидные данные?

Валидация будет вызыватся при сохранении. Если у нас валидация задана декларативно, то можно через AOP заставить её проходить везде.

G>>>>service.CloseLocation(licationId), остальное происходит внутри метода. А тот кто вызывает этот метод не имеет возможности сохранить в базе этот location.


T>>>Зато данные не защищены от поломки из других сервисов

G>>Для проверки такого есть тесты.

T>Если автор не захотел писать тест или автор — третье лицо, то смиримся с тем, что данные могут поломать?

А если автор не захотел писать проверки в классе?
Как это вообще касается архитектуры и дизайна?
Re[31]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 13:43
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Размер тут большого значения не имеет. Смогли скомпрометировать в одном месте, сможем и везде.

G>А кто-то говорил про универсальность MaintainabilyIndex? Смотреть MaintainabilyIndex для частей проекта (классов, методов) полезно только для определения что влияет на индекс. Само значение индекса для одного класса\метода смысла практически не имеет.

"значение индекса для одного класса\метода" вносит свою ЛЕПТУ в общее значение индекса для всего проекта. Малую, но вносит.
Если классов много, N штук например, то вклад уже будет N * ЛЕПТА. Если мы для каждого класса подхачим ЛЕПТУ до меньшего значения лепта, то в совокупности это даст снижение на N * (ЛЕПТА — лепта). Что уже может иметь смысл.
Re[31]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 13:47
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Как она будет вызываться? Если какой-то сервис не станет ее вызывать, получим невалидные данные?

G>Валидация будет вызыватся при сохранении. Если у нас валидация задана декларативно, то можно через AOP заставить её проходить везде.

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

G>>>>>service.CloseLocation(licationId), остальное происходит внутри метода. А тот кто вызывает этот метод не имеет возможности сохранить в базе этот location.


T>>Если автор не захотел писать тест или автор — третье лицо, то смиримся с тем, что данные могут поломать?

G>А если автор не захотел писать проверки в классе?

А это уже проблема модели. Важно то, что имеющиеся проверки никогда не будут (не могут) быть проигнорированы.
Re[34]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:51
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>Вместо кастомера можно ченить еще придумать, где параметр валидации не находися в самой сущности.

T>>>Нпример?
G>>Просто представьте что такой кастомер.
T>Какой такой? Если есть страна, то она где-то хранится. Следовательно её всегда можно узнать.
Замечательно, для загрузки кастомера из хранилища потребуется загрузка связанных сущностей.

G>>>>С этим вообще никак нельзя бороться, если кто угодно может получить доступ к базе, то смысла нет городить валидацию в приложении. Но это вопрос администрирования.


T>>>Я имею в виду если кто-то выставит невалидный zip в приложении и сасабмитит в базу.

G>>1)в приложении все подряд не могут сабмитить в базу.
T>"кто-то" — какой-то сервис
Тесты это отловят. Когда БЛ разбита на независимые сервисы тестировать становится лего и непринужденно.

G>>2)Есть тесты, которые проверят правильность работы логики


T>А так она (валидация) будет в одном месте — в модели.

Только это потребует гораздо больше "приседаний" чтобы валидация действительно везде работала, пример с zip code уже привели.

G>>3)Саму валидацию на всех уровнях никто не отменял, но она содержится не классах сущностей, а вне их.

T>Где? Когда вызывается?
Как минимум при сохранении, например по событию SavingChanges.
Re[32]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 13:53
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Размер тут большого значения не имеет. Смогли скомпрометировать в одном месте, сможем и везде.

G>>А кто-то говорил про универсальность MaintainabilyIndex? Смотреть MaintainabilyIndex для частей проекта (классов, методов) полезно только для определения что влияет на индекс. Само значение индекса для одного класса\метода смысла практически не имеет.

T>"значение индекса для одного класса\метода" вносит свою ЛЕПТУ в общее значение индекса для всего проекта. Малую, но вносит.

T>Если классов много, N штук например, то вклад уже будет N * ЛЕПТА. Если мы для каждого класса подхачим ЛЕПТУ до меньшего значения лепта, то в совокупности это даст снижение на N * (ЛЕПТА — лепта). Что уже может иметь смысл.
Это верно если все лепты независимы друг от друга. Но такого в жизни не бывает.
Re[35]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 13:58
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Просто представьте что такой кастомер.

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

Зачем? Требуемая сущность будет загружена по требованию, при валидации.

T>>"кто-то" — какой-то сервис

G>Тесты это отловят.

Лучший тест — это тест которого нет. Дзэнская мудрость.

G>Когда БЛ разбита на независимые сервисы тестировать становится лего и непринужденно.


А когда у тебя domain model необходимость тестирования валидности отпадает.

G>>>2)Есть тесты, которые проверят правильность работы логики


T>>А так она (валидация) будет в одном месте — в модели.

G>Только это потребует гораздо больше "приседаний" чтобы валидация действительно везде работала, пример с zip code уже привели.

В примере с zip-ом лишь сказали, что такая проблема была. Как её решили сказано не было.

G>>>3)Саму валидацию на всех уровнях никто не отменял, но она содержится не классах сущностей, а вне их.

T>>Где? Когда вызывается?
G>Как минимум при сохранении, например по событию SavingChanges.

Тем самым только расширяется интервал времени когда модель будет в невалидном состоянии. Зачем оно? Не лучше ли не допускать невалидности модели?
Re[33]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 14:01
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Если классов много, N штук например, то вклад уже будет N * ЛЕПТА. Если мы для каждого класса подхачим ЛЕПТУ до меньшего значения лепта, то в совокупности это даст снижение на N * (ЛЕПТА — лепта). Что уже может иметь смысл.

G>Это верно если все лепты независимы друг от друга.

Эта техника — суть локальное изменение внутри метода. Изменение кода внутри метода никаких зависимостей не порождает.

G>Но такого в жизни не бывает.


Бывает, на одном проекта, в котором я принимал участие, мы в течении пары дней таким образом очень неплохо снизили индекс.
Re[32]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 14:01
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Как она будет вызываться? Если какой-то сервис не станет ее вызывать, получим невалидные данные?

G>>Валидация будет вызыватся при сохранении. Если у нас валидация задана декларативно, то можно через AOP заставить её проходить везде.

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

Да, и это на самом деле сильно упрощает методы.

G>>>>>>service.CloseLocation(licationId), остальное происходит внутри метода. А тот кто вызывает этот метод не имеет возможности сохранить в базе этот location.


T>>>Если автор не захотел писать тест или автор — третье лицо, то смиримся с тем, что данные могут поломать?

G>>А если автор не захотел писать проверки в классе?

T>А это уже проблема модели. Важно то, что имеющиеся проверки никогда не будут (не могут) быть проигнорированы.

Важно то что честное обеспечение всех проверок может быть очень тяжелым.

Пример с темже кастомером, у которого страна лежит в другой сущности.
есть у нас загруженный кастомер, у кторого zip валидируется определенным образом. Тут кто-то (другой пользователь) меняет связанную сущность, выставляя там другую страну. Загруженный кастомер об этом не знает, все приплыли.

Чтобы этого избежать кастомер должен каждый раз лазить в базу за валидацией зип-кода, на простом присваивании свойству. Или в память приложения должна быть загружена вся база. И то и другое — хреновые решения.

Еще одна ситуация: когда кастомер в процессе создания и еще не имеет ссылки на сущность со страной, как валидировать его zipCode?
Re[33]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 14:07
Оценка:
Здравствуйте, gandjustas, Вы писали:

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

G>Да, и это на самом деле сильно упрощает методы.

Разве. И как себя должен будет вести сервис списания остатков на складе если ему подсунули заказ с отрицательным количеством?
Увеличить складские остатки?

T>>А это уже проблема модели. Важно то, что имеющиеся проверки никогда не будут (не могут) быть проигнорированы.

G>Важно то что честное обеспечение всех проверок может быть очень тяжелым.

А что делать?

G>Пример с темже кастомером, у которого страна лежит в другой сущности.

G>есть у нас загруженный кастомер, у кторого zip валидируется определенным образом. Тут кто-то (другой пользователь) меняет связанную сущность, выставляя там другую страну. Загруженный кастомер об этом не знает, все приплыли.

G>Чтобы этого избежать кастомер должен каждый раз лазить в базу за валидацией зип-кода, на простом присваивании свойству. Или в память приложения должна быть загружена вся база. И то и другое — хреновые решения.


Или при сохранении проверить, что он пользовался валидной версией сущности, из которой он считал занчение country code. Варианты есть.

G>Еще одна ситуация: когда кастомер в процессе создания и еще не имеет ссылки на сущность со страной, как валидировать его zipCode?


Я не знаю, зависит от бизнес-логики.
Re[36]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 14:11
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>Просто представьте что такой кастомер.

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

T>Зачем? Требуемая сущность будет загружена по требованию, при валидации.

Чтобы сформировать объект валидатора для инстанцирования класса вам нужен CoutryCode, если эту связь оставлять ленивой, то это сильно усложнит валидаторы.

G>>Когда БЛ разбита на независимые сервисы тестировать становится лего и непринужденно.

T>А когда у тебя domain model необходимость тестирования валидности отпадает.
А тестирование валидности не нужно, нужно проверить что сервис делает только то что должен.

G>>>>2)Есть тесты, которые проверят правильность работы логики


T>>>А так она (валидация) будет в одном месте — в модели.

G>>Только это потребует гораздо больше "приседаний" чтобы валидация действительно везде работала, пример с zip code уже привели.
T>В примере с zip-ом лишь сказали, что такая проблема была. Как её решили сказано не было.
Решается это тем, что валидация проводится там где необходимо. Тогда мы будем полностью контролировать количество обращений к базе за дополнительными параметрами.

G>>>>3)Саму валидацию на всех уровнях никто не отменял, но она содержится не классах сущностей, а вне их.

T>>>Где? Когда вызывается?
G>>Как минимум при сохранении, например по событию SavingChanges.
T>Тем самым только расширяется интервал времени когда модель будет в невалидном состоянии. Зачем оно? Не лучше ли не допускать невалидности модели?
Совсем её не допускать при отсутствии пессимистичной блокировки (как в БД) не получится, только если не держать всю базу в памяти.
Гораздо проще устранить эффект от невалидности модели и не допустить сохранения невалидных сущностей.
Re[34]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 14:14
Оценка:
Здравствуйте, Tissot, Вы писали:

G>>Но такого в жизни не бывает.

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

unit-тесты после такого снижения можно было бы значительно упростить, некоторые вообще выкинуть.

Лучший тест — это тест которого нет. Дзэнская мудрость.

Re[37]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 14:19
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Зачем? Требуемая сущность будет загружена по требованию, при валидации.

G>Чтобы сформировать объект валидатора для инстанцирования класса вам нужен CoutryCode, если эту связь оставлять ленивой, то это сильно усложнит валидаторы.

Как усложнит?

G>>>Когда БЛ разбита на независимые сервисы тестировать становится лего и непринужденно.

T>>А когда у тебя domain model необходимость тестирования валидности отпадает.
G>А тестирование валидности не нужно, нужно проверить что сервис делает только то что должен.

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

G>>>Только это потребует гораздо больше "приседаний" чтобы валидация действительно везде работала, пример с zip code уже привели.

T>>В примере с zip-ом лишь сказали, что такая проблема была. Как её решили сказано не было.
G>Решается это тем, что валидация проводится там где необходимо. Тогда мы будем полностью контролировать количество обращений к базе за дополнительными параметрами.

Вообще-то о zip-е писал Sinclair

T>>Тем самым только расширяется интервал времени когда модель будет в невалидном состоянии. Зачем оно? Не лучше ли не допускать невалидности модели?

G>Совсем её не допускать при отсутствии пессимистичной блокировки (как в БД) не получится, только если не держать всю базу в памяти.

Почему не получится. Приведи вариант, когда не получится. И зачем для этого вся база в памяти?

G>Гораздо проще устранить эффект от невалидности модели и не допустить сохранения невалидных сущностей.


В одном месте упрощаешь, усложняется в другом. Теперь сервисам надо уметь работать с невалидными данными. И что в итоге проще?
Re[35]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 14:20
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Но такого в жизни не бывает.

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

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


Нельзя. На сoverage такая реорганизация не влияет.

G>

G>Лучший тест — это тест которого нет. Дзэнская мудрость.

Re[34]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 14:29
Оценка:
Здравствуйте, Tissot, Вы писали:

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


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

G>>Да, и это на самом деле сильно упрощает методы.

T>Разве. И как себя должен будет вести сервис списания остатков на складе если ему подсунули заказ с отрицательным количеством?

T>Увеличить складские остатки?
А откуда пришел заказ?
Если из базы, то как он туда попал?
Если от PL, то срочно идти смотреть тесты и выяснять по какой причине заказ с отрицательным количеством оттуда пришел, почему не были провалидированы введеные пользователем данные.
Даже если все забили на валидацию, то заказ будет провалидирован при сохранении в базу и бизнес-транзакция будет отменена.
Валидацию по хорошему и в PL надо делать, но так чтобы она быстро работала.

T>>>А это уже проблема модели. Важно то, что имеющиеся проверки никогда не будут (не могут) быть проигнорированы.

G>>Важно то что честное обеспечение всех проверок может быть очень тяжелым.
T>А что делать?
Не делать проверки везде.

G>>Пример с темже кастомером, у которого страна лежит в другой сущности.

G>>есть у нас загруженный кастомер, у кторого zip валидируется определенным образом. Тут кто-то (другой пользователь) меняет связанную сущность, выставляя там другую страну. Загруженный кастомер об этом не знает, все приплыли.
G>>Чтобы этого избежать кастомер должен каждый раз лазить в базу за валидацией зип-кода, на простом присваивании свойству. Или в память приложения должна быть загружена вся база. И то и другое — хреновые решения.

T>Или при сохранении проверить, что он пользовался валидной версией сущности, из которой он считал занчение country code. Варианты есть.

Ключевое слово — при сохранении. Фактическое принятие решение о валидности сущности переносится на один конкретный момент — сохранение данных. То есть речь о постоянной валидности сущности уже не идет.

G>>Еще одна ситуация: когда кастомер в процессе создания и еще не имеет ссылки на сущность со страной, как валидировать его zipCode?

T>Я не знаю, зависит от бизнес-логики.
Это как раз вопрос дизайна. На форуме "архитектура" было такое обсуждение. Варианты — плодить builder или data object. Но тогда возникает смысловое дублирование.
Re[35]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 14:46
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Даже если все забили на валидацию, то заказ будет провалидирован при сохранении в базу и бизнес-транзакция будет отменена.

G>Валидацию по хорошему и в PL надо делать, но так чтобы она быстро работала.

Что-то я подзадолбался отвечать. Чего в сотый раз перетира domain model vs something else? Все равно все останутся при своих мнениях, т.к. плюсы есть и там и там.

Давай завяжем с этим.

G>>>Еще одна ситуация: когда кастомер в процессе создания и еще не имеет ссылки на сущность со страной, как валидировать его zipCode?

T>>Я не знаю, зависит от бизнес-логики.
G>Это как раз вопрос дизайна. На форуме "архитектура" было такое обсуждение. Варианты — плодить builder или data object. Но тогда возникает смысловое дублирование.

У нас у таких сущностей есть состояние Draft. В этом состоянии проверки не делаются, т.е. фактически она работает как data object. После завершения инициализации сущность переходит в состояние Ready (с валидацией). Переход обратно невозможен.
Re[38]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 14:51
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Зачем? Требуемая сущность будет загружена по требованию, при валидации.

G>>Чтобы сформировать объект валидатора для инстанцирования класса вам нужен CoutryCode, если эту связь оставлять ленивой, то это сильно усложнит валидаторы.

T>Как усложнит?

связанная сущность, хранящаяя страну — Region
ZipCodeValidationStrategyFacory.GetByCountryCode(Region.CountryCode) //здесь cущность Region должна быть загружена

Если захочется связь ленивой сделать то придется усложнить валидатор. Можно валидатор создавать при первом обращении, но тогда не факт что будет контекст существовать в момент загрузки связанной сущности (у нас всего лишь происходит изменение свойтва).

G>>>>Когда БЛ разбита на независимые сервисы тестировать становится лего и непринужденно.

T>>>А когда у тебя domain model необходимость тестирования валидности отпадает.
G>>А тестирование валидности не нужно, нужно проверить что сервис делает только то что должен.
T>Как же тогда убедиться, что сервис не поломал валидность? Каждый раз сабмитить в базу?
А зачем нам это? Если каждый маленький кусочек работает правильно и интеграционные тесты показывают что основные сценарии проходят успешно (вместе с записью в базу), то все ок.

T>>>Тем самым только расширяется интервал времени когда модель будет в невалидном состоянии. Зачем оно? Не лучше ли не допускать невалидности модели?

G>>Совсем её не допускать при отсутствии пессимистичной блокировки (как в БД) не получится, только если не держать всю базу в памяти.
T>Почему не получится. Приведи вариант, когда не получится. И зачем для этого вся база в памяти?
Дык пример с кастомером и регионом. Валидность зип-кода кастомера зависит от страны, хранящейся в сущности регион. Мы работаем с кастомером, а другой пользователь в этот момент меняет страну реиона. Валидность кастомера нарушена, а потимистичная блокировка нам не поможет ибо регион не был изменен в нашем сеансе.
Если вся база в памяти, то мы можем контролировать каждое изменение.

G>>Гораздо проще устранить эффект от невалидности модели и не допустить сохранения невалидных сущностей.

T>В одном месте упрощаешь, усложняется в другом. Теперь сервисам надо уметь работать с невалидными данными. И что в итоге проще?
Работать с невалидными данными проще, не нужно проверок, обработок исключений и прочего.
Re[36]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 14:57
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>>>Но такого в жизни не бывает.

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

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


T>Нельзя. На сoverage такая реорганизация не влияет.

Ну если у вас тесты для кавереджа, тогда да. Если тестируются сценарии использования, то количество тестов уменьшится.
Например в вашем коде после рефакторинга можно сделать всего два теста, место тестов на каждый if.

G>>

G>>Лучший тест — это тест которого нет. Дзэнская мудрость.

Re[39]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 15:04
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Как усложнит?

G>связанная сущность, хранящаяя страну — Region
G>
G>ZipCodeValidationStrategyFacory.GetByCountryCode(Region.CountryCode) //здесь cущность Region должна быть загружена
G>

G>Если захочется связь ленивой сделать то придется усложнить валидатор. Можно валидатор создавать при первом обращении, но тогда не факт что будет контекст существовать в момент загрузки связанной сущности (у нас всего лишь происходит изменение свойтва).

Чего-то как-то у тебя все сложно получается. Валидатор никак не связан с ленивостью чего-либо. Он просто строку проверяет. Или я опять чего-то не вкуриваю?

G>>>А тестирование валидности не нужно, нужно проверить что сервис делает только то что должен.

T>>Как же тогда убедиться, что сервис не поломал валидность? Каждый раз сабмитить в базу?
G>А зачем нам это? Если каждый маленький кусочек работает правильно и интеграционные тесты показывают что основные сценарии проходят успешно (вместе с записью в базу), то все ок.

Значит все ок. Здолбался. Давай не будем больше это обсуждать.
Я могу написать тут еще аргументов, но на каждое ты дашь свой вариант ответа, чтобы остаться при мнении, и эти варианты будут работать.
Но есть также и другой вариант — domain model. Он тоже не лишен недостатков, на некоторые из них в частности тут уже указывали. Но и эти недостатки находят свое решение.
Так что давай каждый останется при своем и разойдемся с миром, чтобы не скатиться до поливания друг друга грязью, как это делал один из участников дискуссии.



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

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

Тогда встанет другая проблема — как обеспечить валидность при конкурентном доступе. А эта проблема еще хуже всех перечисленных до этого.

G>>>Гораздо проще устранить эффект от невалидности модели и не допустить сохранения невалидных сущностей.

T>>В одном месте упрощаешь, усложняется в другом. Теперь сервисам надо уметь работать с невалидными данными. И что в итоге проще?
G>Работать с невалидными данными проще, не нужно проверок, обработок исключений и прочего.

Есть и другое мнение. См. Defensive programming
Re[37]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 15:08
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Нельзя. На сoverage такая реорганизация не влияет.

G>Ну если у вас тесты для кавереджа, тогда да. Если тестируются сценарии использования, то количество тестов уменьшится.

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

G>Например в вашем коде после рефакторинга можно сделать всего два теста, место тестов на каждый if.


Нельзя. Нужно чтобы тест проверил что каждый action работает корректно. А это как минимум 4 теста (по кол-ву action-ов).
Re[38]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 15:34
Оценка:
Здравствуйте, Tissot, Вы писали:


G>>Например в вашем коде после рефакторинга можно сделать всего два теста, место тестов на каждый if.

T>Нельзя. Нужно чтобы тест проверил что каждый action работает корректно. А это как минимум 4 теста (по кол-ву action-ов).

От них никуда не денешься. Я имел ввиду метод, который вызывает экшены.
Re[39]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 15:36
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>От них никуда не денешься. Я имел ввиду метод, который вызывает экшены.


Они приватные. Они должны протестироваться косвенным образом, через тестирование публичных методов.
Re[40]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 15:59
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Как усложнит?

G>>связанная сущность, хранящаяя страну — Region
G>>
G>>ZipCodeValidationStrategyFacory.GetByCountryCode(Region.CountryCode) //здесь cущность Region должна быть загружена
G>>

G>>Если захочется связь ленивой сделать то придется усложнить валидатор. Можно валидатор создавать при первом обращении, но тогда не факт что будет контекст существовать в момент загрузки связанной сущности (у нас всего лишь происходит изменение свойтва).

T>Чего-то как-то у тебя все сложно получается. Валидатор никак не связан с ленивостью чего-либо. Он просто строку проверяет. Или я опять чего-то не вкуриваю?

Чтобы проверить строку он должен знать как её проверить. Чтобы знать как он должен знать CountryCode, чтобы знать CountryCode нужно подгрузить связанную сущность, в которой лежит CountryCode. Создавать валидатор один раз во время создания объекта нельзя, потому что в связанном регионе может CountryCode измениться из другого контекста и кастомер об этом не узнает. Как обеспечить по-настоящиму валидное состояние кастомера при каждом изменении zip code, чтобы не лазить каждый раз в базу?

G>>>>А тестирование валидности не нужно, нужно проверить что сервис делает только то что должен.

T>>>Как же тогда убедиться, что сервис не поломал валидность? Каждый раз сабмитить в базу?
G>>А зачем нам это? Если каждый маленький кусочек работает правильно и интеграционные тесты показывают что основные сценарии проходят успешно (вместе с записью в базу), то все ок.

T>Значит все ок. Здолбался. Давай не будем больше это обсуждать.

T>Я могу написать тут еще аргументов, но на каждое ты дашь свой вариант ответа, чтобы остаться при мнении, и эти варианты будут работать.
T>Но есть также и другой вариант — domain model. Он тоже не лишен недостатков, на некоторые из них в частности тут уже указывали. Но и эти недостатки находят свое решение.
Ну так я и говорю что все можно сделать неправильно и оно будет работать.

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

Не переживайте, он всегда так разговаривает.

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

G>>Если вся база в памяти, то мы можем контролировать каждое изменение.
T>Тогда встанет другая проблема — как обеспечить валидность при конкурентном доступе. А эта проблема еще хуже всех перечисленных до этого.
Ну система блокировок как в БД.

G>>>>Гораздо проще устранить эффект от невалидности модели и не допустить сохранения невалидных сущностей.

T>>>В одном месте упрощаешь, усложняется в другом. Теперь сервисам надо уметь работать с невалидными данными. И что в итоге проще?
G>>Работать с невалидными данными проще, не нужно проверок, обработок исключений и прочего.

T>Есть и другое мнение. См. Defensive programming

Defensive programming — это когда мы считаем что отовсюду нас хотя нае**ть, а мы тут предлагаем просто игнорировать факт невалидности сущностей (на самом деле данных, которые по идеологии не могут быть невалидными) пока это не станет важно.
Это важно в первую очередь при сохранении, во вторую очередь важно в UI (PL) или другом месте откуда приходят данные чтобы обеспечить хороший feedback.
Re[41]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 16:09
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>>>
G>>>ZipCodeValidationStrategyFacory.GetByCountryCode(Region.CountryCode) //здесь cущность Region должна быть загружена
G>>>

G>>>Если захочется связь ленивой сделать то придется усложнить валидатор. Можно валидатор создавать при первом обращении, но тогда не факт что будет контекст существовать в момент загрузки связанной сущности (у нас всего лишь происходит изменение свойтва).

T>>Чего-то как-то у тебя все сложно получается. Валидатор никак не связан с ленивостью чего-либо. Он просто строку проверяет. Или я опять чего-то не вкуриваю?

G>Чтобы проверить строку он должен знать как её проверить. Чтобы знать как он должен знать CountryCode,

Валидатор не должен он просто преверяет. CountryCode должен знать тот, что получает валидатор. См. код выше.

T>>Значит все ок. Здолбался. Давай не будем больше это обсуждать.

T>>Я могу написать тут еще аргументов, но на каждое ты дашь свой вариант ответа, чтобы остаться при мнении, и эти варианты будут работать.
T>>Но есть также и другой вариант — domain model. Он тоже не лишен недостатков, на некоторые из них в частности тут уже указывали. Но и эти недостатки находят свое решение.
G>Ну так я и говорю что все можно сделать неправильно и оно будет работать.

Это не неправильно. Это просто по другому. На эту тему я больше не буду отвечать.

T>>Есть и другое мнение. См. Defensive programming

G>Defensive programming — это когда мы считаем что отовсюду нас хотя нае**ть, а мы тут предлагаем просто игнорировать факт невалидности сущностей (на самом деле данных, которые по идеологии не могут быть невалидными) пока это не станет важно.

Я понял что вы предлагаете. Не надо продолжать.
Re[42]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 16:24
Оценка:
Здравствуйте, Tissot, Вы писали:

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

G>>>>
G>>>>ZipCodeValidationStrategyFacory.GetByCountryCode(Region.CountryCode) //здесь cущность Region должна быть загружена
G>>>>

G>>>>Если захочется связь ленивой сделать то придется усложнить валидатор. Можно валидатор создавать при первом обращении, но тогда не факт что будет контекст существовать в момент загрузки связанной сущности (у нас всего лишь происходит изменение свойтва).

T>>>Чего-то как-то у тебя все сложно получается. Валидатор никак не связан с ленивостью чего-либо. Он просто строку проверяет. Или я опять чего-то не вкуриваю?

G>>Чтобы проверить строку он должен знать как её проверить. Чтобы знать как он должен знать CountryCode,

T>Валидатор не должен он просто преверяет. CountryCode должен знать тот, что получает валидатор. См. код выше.

Разницы нету, можно писать new ZipCodeValidator(Region.CountryCode), проблема останется таже. за время жизни кастомера валидатор может стать ... эээ ... невалидным.

Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).
Re[43]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 16:29
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Валидатор не должен он просто преверяет. CountryCode должен знать тот, что получает валидатор. См. код выше.

G>Разницы нету, можно писать new ZipCodeValidator(Region.CountryCode), проблема останется таже. за время жизни кастомера валидатор может стать ... эээ ... невалидным.

Посмотри код, где он создается. Нет необходимости его хранить. Он легковесный.

G>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).


Можно, через метод, меняющий CountryCode и Zip.
Re[44]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 16:35
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Валидатор не должен он просто преверяет. CountryCode должен знать тот, что получает валидатор. См. код выше.

G>>Разницы нету, можно писать new ZipCodeValidator(Region.CountryCode), проблема останется таже. за время жизни кастомера валидатор может стать ... эээ ... невалидным.

T>Посмотри код, где он создается. Нет необходимости его хранить. Он легковесный.

То есть каждый раз лезть в базу и получать текущий CountryCode из связанной сущности?

G>>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).


T>Можно, через метод, меняющий CountryCode и Zip.

А если у нас WPF и свойства забайндены на контролы?

Да и слишком сложно для такой простой операции. Надеюсь стало понятно что работать с "невалидными сущностями" проще?
Re[40]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 16:40
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>От них никуда не денешься. Я имел ввиду метод, который вызывает экшены.


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

Ну тогда понятно.
Re[45]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 16:40
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Посмотри код, где он создается. Нет необходимости его хранить. Он легковесный.

G>То есть каждый раз лезть в базу и получать текущий CountryCode из связанной сущности?

Зачем каждый раз? Ты же говорил, что у тебя ленивая загрузка.

G>>>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).


T>>Можно, через метод, меняющий CountryCode и Zip.

G>А если у нас WPF и свойства забайндены на контролы?

А нефик биндить сущности на контролы. А то тут скатиться до дельфевого подхода недалеко.

G>Да и слишком сложно для такой простой операции. Надеюсь стало понятно что работать с "невалидными сущностями" проще?


Пока.
Re[46]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 17:12
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Посмотри код, где он создается. Нет необходимости его хранить. Он легковесный.

G>>То есть каждый раз лезть в базу и получать текущий CountryCode из связанной сущности?

T>Зачем каждый раз? Ты же говорил, что у тебя ленивая загрузка.

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

G>>>>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).


T>>>Можно, через метод, меняющий CountryCode и Zip.

G>>А если у нас WPF и свойства забайндены на контролы?

T>А нефик биндить сущности на контролы. А то тут скатиться до дельфевого подхода недалеко.

DataBinding плохой подход для UI?
Re[16]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 17:43
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Возможно, я не сталкивался сподобного рода задачами, но мне доводилось работать с достаточно крупной erp-системой (Axapta).

T>Там как раз было реализовано именно так, как я описывал — через объектную модель. Слышал краем уха что в том же SAP-е реализовано примерно таким же образом — логика не в базе, запросах, а в appserver cлое. Если все так плохо с работать через объектную модель, то почему в этих системах было реализовано именно так? Неужели тоже из-за недостатка опыта проектировщиков?
Не знаю, я свечку им не держал. Но обе системы новыми назвать сложно. Фаулер, собственно, свою книжку-то выпустил совсем недавно. Формализовав, с опозданием на пять лет, опыт передовых разработчиков 1998 года. Сейчас, в принципе, уже прошел 2008. Я думаю, современные системы сейчас еще только проектируются. Уж очень длинный у них лайфтайм.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[31]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 17:46
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Прекрасный пример. Давайте разберем его поподробнее.

S>1. Логика проверки зипкода инкапсулирована внутрь объекта "кастомер". Тебе это очень нравится, но на самом деле это означает, что у нас нет никакого способа узнать, валиден ли зип, не попробовав выполнить присваивание свойству. С точки зрения внешнего кода, кастомер — это чёрный ящик.
S>Возникают вопросы примерно такого рода:
S>а) как нам проверить валидность зипа прямо в UI, где недоступен экземпляр класса "кастомер"?
S>б) как нам получить осмысленный результат проверки, а не просто исключение и роллбэк? Ну, там, чтобы, к примеру, было сказано, где именно в индексе ошибка, и образец правильного заполнения?

S>2. Наша "сущность" начинает резко утяжеляться. Вот сейчас ей уже нужна по соседству табличка со всеми странами. Ну, то есть на самом деле надо будет еще и хранить историю правил формирования зип-кодов для всех стран.

S>Это еще уменьшает шансы "оторвать" ее от сервера приложений и обработать где-то еще.
S>Я уж не говорю про повторное использование в другой ситуации.

Что-то в этом есть.

T>>А теперь рассказывай, как ты будешь с этим бороться:


T>>
T>>update customer set zipCode = "любой невалидный zip";
T>>

S>Очень просто. Такого кода в прикладном слое вовсе нет. Потому что модификация зип-кода проходит только через CustomerManager, который конечно же не забудет позвать все правила проверки пре-кондишнов. Это раз.

Откуда CustomerManager и как он может помешать изменить Customer-а напрямую?

S>Два, в большом-большом количестве случаев лучше этот код разрешить. В частности, к примеру, потому, что далеко не всегда при создании кастомера есть информация про его зипкод. При таком подходе очень быстро окажется, что "ой, проверить стоимость остатков нельзя без проведения заказа, заказ нельзя ввести без кастомера, а кастомера нельзя завести без корректного зип-кода и ИНН". До свидания, бизнес сломался.

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

Ну это скорее аргумент в пользу изменени логики валидации — она должна запускаться только при определенном статусе заказа.

S>В итоге, вместо вшитой в ZipCode { set ; } логики мы получаем Precondition для операции "отгрузить заказ", как я и говорил.
Re[14]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 09.01.09 18:56
Оценка:
T>Данным, он наверное не нужен, а объектам domain model — вполне.

Замечательно. А к базе она какое имеет отношение?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 19:05
Оценка:
Здравствуйте, VGn, Вы писали:

T>>Данным, он наверное не нужен, а объектам domain model — вполне.


VGn>Замечательно. А к базе она какое имеет отношение?


Никакого.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 19:08
Оценка:
Здравствуйте, gandjustas, Вы писали:

VGn>>>Разъясните мне-идиоту зачем полиморфизм данным?


T>>Данным, он наверное не нужен, а объектам domain model — вполне.


G>domain model не содержит данных?


Содержит, конечно.
Re[48]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 19:31
Оценка:
Здравствуйте, Tissot, Вы писали:

T>>>А нефик биндить сущности на контролы. А то тут скатиться до дельфевого подхода недалеко.

G>>DataBinding плохой подход для UI?

T>Нет, DataBinding прямиком на сущности — плохой прием.

Аргументы?
Re[16]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 09.01.09 19:38
Оценка:
T>>>Данным, он наверное не нужен, а объектам domain model — вполне.
VGn>>Замечательно. А к базе она какое имеет отношение?

T>Никакого.


Тогда вот это
T>>>>Методы. Интерфейсы.
IB>>>А это вообще никакого отношения к данным не имеет.
T>>Зато имеет к ООП.
о чём?

Ты ответишь: как же? у нас же есть специальная прокладка с крылышками!
Да?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[17]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 20:43
Оценка:
Здравствуйте, VGn, Вы писали:

VGn>Тогда вот это

T>>>>>Методы. Интерфейсы.
IB>>>>А это вообще никакого отношения к данным не имеет.
T>>>Зато имеет к ООП.
VGn>о чём?

Для тебя сущность — это данные и поэтому ты не видишь, зачем тут методы.
Для меня сущность — это сущность domain model и поэтому методам там самое место.

Как-то так.

VGn>Ты ответишь: как же? у нас же есть специальная прокладка с крылышками!

VGn>Да?

Какая прокладка? Ты о чем вообще? Или у вас тут уже сложившаяся практика на этом форуме — хамить?
Re[18]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 09.01.09 21:30
Оценка:
VGn>>Ты ответишь: как же? у нас же есть специальная прокладка с крылышками!
VGn>>Да?

T>Какая прокладка? Ты о чем вообще? Или у вас тут уже сложившаяся практика на этом форуме — хамить?


Всё о том же — об ООП для доступа к данным.
Заметь, как раз я эмоциональных оценок твоему поведению не давал. Т.е. вёл дискуссию вполне в рамках формальных правил.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[19]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 22:00
Оценка:
Здравствуйте, VGn, Вы писали:

VGn>>>Ты ответишь: как же? у нас же есть специальная прокладка с крылышками!

VGn>>>Да?

T>>Какая прокладка? Ты о чем вообще? Или у вас тут уже сложившаяся практика на этом форуме — хамить?


VGn>Всё о том же — об ООП для доступа к данным.

VGn>Заметь, как раз я эмоциональных оценок твоему поведению не давал. Т.е. вёл дискуссию вполне в рамках формальных правил.

"специальная прокладка с крылышками" — это видимо специальное такое формальное обращения?!
В топку такую дискуссию, адью.
Re[20]: Некоторые мысли о LINQ
От: VGn Россия http://vassilsanych.livejournal.com
Дата: 09.01.09 22:20
Оценка:
T>"специальная прокладка с крылышками" — это видимо специальное такое формальное обращения?!
А как ещё назвать программную прослойку, усложняющую код изменением парадигмы доступа к данным, введением промежуточных хранилищ и ещё бог знает чем только для того, чтобы подстроить этот самый механизм доступа под любимый золотой молот разработчика?

T>В топку такую дискуссию, адью.

Как будет угодно
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[18]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 10.01.09 10:01
Оценка:
Здравствуйте, Tissot, Вы писали:

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

Хочешь сказать, что в приватной беседе у тебя появятся мысли отличные от Фаулера?
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[20]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 10.01.09 10:01
Оценка:
Здравствуйте, Tissot, Вы писали:

T>То есть иди на фик.

Ну я так и думал, что сказать нечего.

T>Какой такой недостаток есть в LINQ2SQL-е, что он не позволяет построить domain model?

T>>и почему с его помощью нельзя построить domain model?
IB>Можно, но не нужно, <...>

Принципиально не читаешь, что тебе пишут? Еще раз — позволяет, но в этом нет необходимости.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[33]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 10.01.09 12:31
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Откуда CustomerManager и как он может помешать изменить Customer-а напрямую?

S>Как откуда? Это и есть класс, в котором сосредоточены методы управления кастомерами.

Все равно вопросы остаются. Не совсем понятно где располагать методы, манипулирующие несколькими типами сущностей.
Например, если чуть изменить тот пример с резервированием:
пусть в случае отсутствия на складе нужного количества товара, товар резервируется частично и информация о зарезервированном кол-ве сохраняется в заказе. То есть, если мы хотели заказать 50 стульев, а на складе оказалось только 20, то 20 и зарезервируется, а после того, как на склад довезут товар, можно будет до-зарезервировать оставшиеся 30 стульев.
В такой формулировке операция резервирования меняет как остатки на складе, так и строки заказа.
В DDD для такого сценария был бы заведен ReservationService, в котором и был бы расположен весь код и по списанию остатков, и по обновлению заказа.
А куда вы его поместите?

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


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

S>А вот запретить из прикладного кода вызовы апдейт-стейтментов можно в том числе и при помощи FxCop.

S>Это если не хватает культуры программирования.
S>Нужно просто отделить случайные ошибки от преднамеренных действий.

В том-то и вопрос, как избежать случайных ошибок.

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

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

Не совсем верно выразился. В описанном случае отсутствие zip-кода или его невалидность вообще не должно учитываться при валидации кастомера. Это действительно, скорее пред-условие для осуществления отгрузки.
Re[34]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 04:29
Оценка:
Здравствуйте, Tissot, Вы писали:

T>В DDD для такого сценария был бы заведен ReservationService, в котором и был бы расположен весь код и по списанию остатков, и по обновлению заказа.

T>А куда вы его поместите?
В этом подходе точно так же будет ReservationService. Как раз в rich domain model непонятно, где располагать такой метод — в заказе, в складе, или еще где.

А так у нас есть некий сервис, которому для работы нужны заказы (с определенным поведением), и склад.

T>В том-то и вопрос, как избежать случайных ошибок.

Очень трудно сделать случайную ишибку, если есть определенные договоренности.

T>Не совсем верно выразился. В описанном случае отсутствие zip-кода или его невалидность вообще не должно учитываться при валидации кастомера. Это действительно, скорее пред-условие для осуществления отгрузки.

Я просто веду к тому, что в реальной жизни инвариантов, которые можно безопасно захардкодить в класс ентити, практически не встречается. В развитых системах те же предусловия на операции вообще задаются путем конфигурирования workflow, без какой-либо перекомпиляции.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[22]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 07:18
Оценка:
Здравствуйте, Tissot, Вы писали:
T>Это не кастомер, это способ хранения информации о кастомере.
Правильно.

T>Ближе к телу. Что за атрибуты?

Например "ID следующего кастомера, которого нужно обрабатывать, если обработка этого не удалась".
Это в случае представления приоритета кастомеров на основе односвязного списка. Или "Customer Priority". Или "Customer Access Control List".
Кастомер может оказаться разрезанным на несколько entity. А может оказаться наоборот. Контактный телефон может оказаться атрибутом кастомера; может оказаться атрибутом сущности "представитель кастомера", может оказаться отдельной сущностью, которая связана с первыми двумя отношением "многие-ко-многим".
При этом, что характерно, сама предметная область никак не меняется от этих страшных манипуляций. Какая из этих моделей domain model? Та, которая ближе к "предметной области"? Предметная область бесконечно сложна. К примеру,

S>>Этакие "артефакты модели". Задача "максимально приблизиться к предметной области" звучит хорошо, но работает плохо. Мне больше нравится задача "придумать максимально простую модель предметной области, которая покрывает максимальное количество пользовательских сценариев".


T>Такой моделью как раз и является domain model

Боюсь тебя разочаровать, но "максимальная близость к предметной области", которую ты постулировал как основной признак domain model, здесь может получиться только случайно.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 07:48
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Ближе к телу. Что за атрибуты?

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

Зачем это ID делать атрибутом Customer-а?

S>Или "Customer Priority".


Вполне себе атрибут предметной области.

S>Или "Customer Access Control List".


Внешняя по отношению к кастомеру сущность. По крайней мере у нас.

S>Кастомер может оказаться разрезанным на несколько entity. А может оказаться наоборот. Контактный телефон может оказаться атрибутом кастомера; может оказаться атрибутом сущности "представитель кастомера", может оказаться отдельной сущностью, которая связана с первыми двумя отношением "многие-ко-многим".

S>При этом, что характерно, сама предметная область никак не меняется от этих страшных манипуляций. Какая из этих моделей domain model?

Это вообще вопрос маппинга на хранилище. У нас не проекте как раз недавно такой рефакторинг делался. Объектная модель не поменялась. Почти

S>Та, которая ближе к "предметной области"? Предметная область бесконечно сложна. К примеру,


В программе не интересна "вся" сложность кастомера. Интересно лишь то, что ... хм, интересно. Собственно как раз это и отквочено ниже.

S>>>Этакие "артефакты модели". Задача "максимально приблизиться к предметной области" звучит хорошо, но работает плохо. Мне больше нравится задача "придумать максимально простую модель предметной области, которая покрывает максимальное количество пользовательских сценариев".


T>>Такой моделью как раз и является domain model

S>Боюсь тебя разочаровать, но "максимальная близость к предметной области", которую ты постулировал как основной признак domain model, здесь может получиться только случайно.

Ну это как вести метрику "близость".
Re[35]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 08:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>В DDD для такого сценария был бы заведен ReservationService, в котором и был бы расположен весь код и по списанию остатков, и по обновлению заказа.

T>>А куда вы его поместите?
S>В этом подходе точно так же будет ReservationService.

То есть задача манипулирования заказами начинает расползаться на большее кол-во сервисов, не только на ЗаказМнеджер?

S>Как раз в rich domain model непонятно, где располагать такой метод — в заказе, в складе, или еще где.


rich model не отрицает наличие сервисов.

S>А так у нас есть некий сервис, которому для работы нужны заказы (с определенным поведением), и склад.


с поведением?

T>>В том-то и вопрос, как избежать случайных ошибок.

S>Очень трудно сделать случайную ишибку, если есть определенные договоренности.

ой, не факт. на договоренности надейся, а сам не плошай.

T>>Не совсем верно выразился. В описанном случае отсутствие zip-кода или его невалидность вообще не должно учитываться при валидации кастомера. Это действительно, скорее пред-условие для осуществления отгрузки.

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

Да есть инварианты, просто с zip-кодом вариант не не совсем удачный. С тем же заказчиком изначально заключается договор и в нем обговорены многие данные о заказчике. Так что они вполне могут проверяться в самой сущности.
Re[14]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 08:03
Оценка:
Здравствуйте, Tissot, Вы писали:

T>>>

T>>>Во-вторых, добавляя новое поведение, надо его просто добавлять, а не менять старое

IB>>А это тут причем? При изменении требований новое поведение должно добавляться без изменения старого, это для тебя новость?

T>

T>Код должен быть поменян, а данные — нет.
T>(с) IB

T>

Поставил минус и в кусты. Ты (IB) уж расскажи, как могут сосуществовать "Код должен быть поменян" с "новое поведение должно добавляться без изменения старого"?
Интересно же.
Re[24]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 08:11
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Зачем это ID делать атрибутом Customer-а?

А чьим?

S>>Или "Customer Access Control List".

T>Внешняя по отношению к кастомеру сущность. По крайней мере у нас.
И какому объекту предметной области она соответствует?

T>Это вообще вопрос маппинга на хранилище. У нас не проекте как раз недавно такой рефакторинг делался. Объектная модель не поменялась. Почти

Это вопрос выбора сущностей для моделирования.

T>В программе не интересна "вся" сложность кастомера. Интересно лишь то, что ... хм, интересно. Собственно как раз это и отквочено ниже.

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

T>Ну это как вести метрику "близость".

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

T>Ну это как вести метрику "близость".




Ну вообще ваша "domain model по фаулеру" наиболее близка к предметной области по вашей метрике. Это же оченивдно.
Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 08:43
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Зачем это ID делать атрибутом Customer-а?

S>А чьим?

"ID следующего кастомера, которого нужно обрабатывать, если обработка этого не удалась"

Зачем это ID в кастомере? Просто передавай в метод обработки список кастомеров.

S>>>Или "Customer Access Control List".

T>>Внешняя по отношению к кастомеру сущность. По крайней мере у нас.
S>И какому объекту предметной области она соответствует?

Мне кажется ты слишком узко трактуешь понятие "предметная область". Это не обязательно что-то, что существует в предметном мире. Это вполне может быть и концепцией. Например, если говорят о ресурсах, доступных кастомеру, то понятие "доступ" к ресурсу существует в предметной области. А ACL — это не более чем набор этих "доступов".

T>>Это вообще вопрос маппинга на хранилище. У нас не проекте как раз недавно такой рефакторинг делался. Объектная модель не поменялась. Почти

S>Это вопрос выбора сущностей для моделирования.

Опять 25. Если для тебе данные — это сущность, то да, если для тебя (меня) сущность — это сущность domain model, то нет.

T>>В программе не интересна "вся" сложность кастомера. Интересно лишь то, что ... хм, интересно. Собственно как раз это и отквочено ниже.

S>Вот и оказывается, что в модель попадает не всё, что было в "предметной области", и попадает то, чего там отродясь не было.

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

T>>Ну это как вести метрику "близость".

S>Как ни вводи — всегда останется возможность привести контрпримеры.

Возможно. Я вроде и не говорил, что доменная модель — это конец истории. Все когда-нить уйдет. Но вот придет ли на смену ей тот подход о котором вы говорите —
Время покажет.
Re[15]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 11.01.09 08:44
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Поставил минус и в кусты.

Ты же сам отказался со мной дискутировать, так чего бисер метать?

T>Ты (IB) уж расскажи, как могут сосуществовать "Код должен быть поменян" с "новое поведение должно добавляться без изменения старого"?

Про OCP принцип слышал? Поинт в том, что при добавлении новго функционала, та часть исходников, которая реализует старый и все еще актуальный функционал даже трогаться не должна, а не только не меняться. Меняется и трогается только то, что нужно изменить. Необходимость менять данные возникает гораздо реже, чем логику, которая навернута поверх этих данных. Таким образом, выделяя данные в отдельную сущность мы защищаем их от лишних изменений, трогая только тот код, который должен поменяться.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 08:44
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>


G>Ну вообще ваша "domain model по фаулеру" наиболее близка к предметной области по вашей метрике. Это же оченивдно.


См. ответ Синклеру.
Re[36]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 08:46
Оценка:
Здравствуйте, Tissot, Вы писали:

T>То есть задача манипулирования заказами начинает расползаться на большее кол-во сервисов, не только на ЗаказМнеджер?

Всё зависит от конкретной задачи. Не забываем про Single Responsibbility Principle.
То есть наш xxxService должен делать всё, что относится к соответствующей ответственности. Речь не идет о тупом механическом выносе всех методов из класса Xxx в класс XxxManager.

T>rich model не отрицает наличие сервисов.

Ну, ты только что боролся за то, чтобы методы включать в entity. Опять напомню, что ReservationService не соответствует вообще ничему в предметной области; таким образом, мы уходим от твоей "максимально близкой к предметной области модели".

T>с поведением?

Ага. В простом случае достаточно прямой манипуляции данными; в более сложном ReservationService будет делегировать построение запросов для модификации позиций заказа и остатков на складах соответствующим сервисам.

T>ой, не факт. на договоренности надейся, а сам не плошай.

Опять же, для плохих танцоров есть FxCop.

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

Какие например? Договор заключается с каждым отдельным заказчиком. Надеюсь, ты не предполагаешь каждый раз писать новый класс сущности для него?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 08:46
Оценка:
Здравствуйте, Tissot, Вы писали:
T>Поставил минус и в кусты. Ты (IB) уж расскажи, как могут сосуществовать "Код должен быть поменян" с "новое поведение должно добавляться без изменения старого"?
T>Интересно же.
Это просто два разных сценария. В одном на существующих данных применяются новые методы, а старые вообще выбрасываются из рассмотрения. Это — замена функциональности.
Она типична, например, когда мы берем накопленные за годы данные и передаём их третьим лицам для data mining.
Дата майнингу совершенно неинтересна валидация, workflow, и прочие приколы, которыми мы пользовались в исходном OLTP приложении. Более того, для него крайне вредно иметь всякие такие штуки типа "адрес кастомера вычисляется полиморфно в зависимости от его типа и параметров", потому что вместе с данными придется тащить вот это "полиморфное поведение". Которое, в частности, может вообще не заработать на той платформе, где датамайнинг собрались выполнять.

В другом случае речь идет о расширении функциональности существующей системы.
И в нём важна возможность произвести это расширение с минимальными потерями. Зашивание логики в data objects чревато неконтролируемым расползанием изменений.
Вот мы по соседству обсуждали валидацию зипкодов. Буквально за два дня у нас код валидации изменился не то четыре, не то пять раз — в зависимости от вторичных подробностей. Это признак того, что с самого начала было сделано что-то неправильно. Если поддержка еще одной страны требует внесения изменений в классы кастомера, заказа, и еще хрен знает чего, то как-то становится жалко потраченных на разработку усилий.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 08:58
Оценка:
Здравствуйте, IB, Вы писали:

T>>Поставил минус и в кусты.

IB>Ты же сам отказался со мной дискутировать, так чего бисер метать?

Опять хамишь. Ты что, без этого совсем не можешь?

T>>Ты (IB) уж расскажи, как могут сосуществовать "Код должен быть поменян" с "новое поведение должно добавляться без изменения старого"?

IB>Про OCP принцип слышал?

Слышал конечно (зевок). Я же тебе же отвечал, что я не со школьной скамьи сюда пришел.

IB>Поинт в том, что при добавлении новго функционала, та часть исходников, которая реализует старый и все еще актуальный функционал даже трогаться не должна, а не только не меняться. Меняется и трогается только то, что нужно изменить.


Слушай, у меня от твоих слов мозг начинает плавиться. Зачем ты тогда писал

добавляя новое поведение, надо его просто добавлять, а не менять старое

, если какая-то часть исходников все-таки трогается.

IB>Необходимость менять данные возникает гораздо реже, чем логику, которая навернута поверх этих данных. Таким образом, выделяя данные в отдельную сущность мы защищаем их от лишних изменений, трогая только тот код, который должен поменяться.


Тут имхо, идет смешение понятий.
То, о чем ты говоришь — это защита схемы данных (контракт), а не самих данных. Данные как раз мы не защищаем, а наоборот выставляем напоказ.
Re[37]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 09:12
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>То есть задача манипулирования заказами начинает расползаться на большее кол-во сервисов, не только на ЗаказМнеджер?

S>Всё зависит от конкретной задачи. Не забываем про Single Responsibbility Principle.

Ответственности тоже можно порезать по-разному. Можно — по модифицирующим сущностям (CustomerManager, OrderManager), можно и по бизнес — сценариям (ReservationService).

S>То есть наш xxxService должен делать всё, что относится к соответствующей ответственности. Речь не идет о тупом механическом выносе всех методов из класса Xxx в класс XxxManager.


Не, я пытаюсь понять как ты предлагаешь это сделать.

T>>rich model не отрицает наличие сервисов.

S>Ну, ты только что боролся за то, чтобы методы включать в entity.

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

S>Опять напомню, что ReservationService не соответствует вообще ничему в предметной области; таким образом, мы уходим от твоей "максимально близкой к предметной области модели".


Дык, ReservationService и не является частью domain model. Это бизнес-операция.

T>>с поведением?

S>Ага. В простом случае достаточно прямой манипуляции данными; в более сложном ReservationService будет делегировать построение запросов для модификации позиций заказа и остатков на складах соответствующим сервисам.

T>>ой, не факт. на договоренности надейся, а сам не плошай.

S>Опять же, для плохих танцоров есть FxCop.

Ну так как его использовать, если функциональность изменения остатков на складе уже переползла из соответствующего менеджера в ReservationService?

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

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

Из того, что "Договор заключается с каждым отдельным заказчиком" не следует, что договоры с заказчиками не имеют ничего общего. Первое что приходит в голову — это название заказчика и SLA. Кроме того, каждый заказчик регистрируется в бухгалтерской системе, в которой он получает свой номер. Этот номер — второй претендент на проверку.
Re[16]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 09:22
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Поставил минус и в кусты. Ты (IB) уж расскажи, как могут сосуществовать "Код должен быть поменян" с "новое поведение должно добавляться без изменения старого"?

T>>Интересно же.
S>Это просто два разных сценария. В одном на существующих данных применяются новые методы, а старые вообще выбрасываются из рассмотрения. Это — замена функциональности.

S>В другом случае речь идет о расширении функциональности существующей системы.


Ладно, будем считать, что IB именно это и имел в виду, хотя из его слов это было совсем не ясно.

S>И в нём важна возможность произвести это расширение с минимальными потерями. Зашивание логики в data objects чревато неконтролируемым расползанием изменений.


Нет dataobjects в domain model, потому и такого явления как "зашивание логики в data objects", а следовательно нет и "расползанием изменений". domain model рулит!

S>Вот мы по соседству обсуждали валидацию зипкодов. Буквально за два дня у нас код валидации изменился не то четыре, не то пять раз — в зависимости от вторичных подробностей. Это признак того, что с самого начала было сделано что-то неправильно.


Правильно, не был проведен анализ.

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


И какой вывод? Отказаться от валидации совсем? Дык это не решение, т.к. если на этапе анализа было решено, что валидация нужна, то и моем и в твоем случае ее делать придется.
Re[38]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 09:38
Оценка:
Здравствуйте, Tissot, Вы писали:
T>Ответственности тоже можно порезать по-разному. Можно — по модифицирующим сущностям (CustomerManager, OrderManager), можно и по бизнес — сценариям (ReservationService).
Первый способ — неправильный; второй — правильный.

T>Нет, я боролся за то, чтобы те сделать контракт сущности таковым, чтобы нельзя было нарушить инварианты. Если метод работы с сущностью не нарушает инвариантов, то его можно поместить и вовне класса, например в виде extension-метода, если мы используем C#. Если область действия метода шире чем данный экземпляр класса, то ему не место в классе, нужно завести отельный сервис, в котором и реализовывать необходимый функционал.

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

T>Дык, ReservationService и не является частью domain model. Это бизнес-операция.

Ну вот очень странно получается — важное поведение не попадает в модель. Это получается какая-то плохая модель, некачественная. Непонятно, почему одно поведение входит в модель, а другое — нет.
В анемичной модели всё просто: "сущности" моделируют только статическую часть предметной области, у них нет никакого поведения. А всё поведение сосредоточено во всяких ...Manager, ...Service, ...Strategy, ...Policy.

T>Ну так как его использовать, если функциональность изменения остатков на складе уже переползла из соответствующего менеджера в ReservationService?

Очень просто — в данном сценарии ReservationService и стал "соответствующим менеджером"

T>Из того, что "Договор заключается с каждым отдельным заказчиком" не следует, что договоры с заказчиками не имеют ничего общего. Первое что приходит в голову — это название заказчика и SLA. Кроме того, каждый заказчик регистрируется в бухгалтерской системе, в которой он получает свой номер. Этот номер — второй претендент на проверку.

На проверку чего?
Намекну: бухгалтерская система может быть завтра заменена, без изменения бизнеса.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 09:53
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Нет dataobjects в domain model, потому и такого явления как "зашивание логики в data objects", а следовательно нет и "расползанием изменений". domain model рулит!

Ну щас прямо. То, что было бы в анемичной модели банальной структурой "кастомер", то бишь дата обжектом, в твоей "domain model" обрастает какими-то методами, валидацией там, и так далее. В итоге изменения таки расползаются.

T>Правильно, не был проведен анализ.

Почему это? Представь себе реальную жизнь — бизнес эволюционирует, требования, которых не было в Release 1, появляются в Release 2.
Как бы ты ни пыхтел в Release 1, всех требований ты предсказать не можешь

T>И какой вывод? Отказаться от валидации совсем? Дык это не решение, т.к. если на этапе анализа было решено, что валидация нужна, то и моем и в твоем случае ее делать придется.

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

T>Нет dataobjects в domain model, потому и такого явления как "зашивание логики в data objects", а следовательно нет и "расползанием изменений". domain model рулит!

domain model по фаулеру и есть dataobjects+"какое-то мифическое поведение". А расползание вы получите при первом же изменении бизнес требований.
например рассмотрим ввод данных. Раз у вас "сущности" не байндятся на контролы, то валидацию в процессе ввода вы получить не сможете. Поэтому вам придется продублировать логику валидации в UI, чтобы сделать хороший фидбэк.
Если у вас меняется логика валидации, то вам уже надо менять в двух местах.

Можно такой же пример с разграничением доступа рассмотреть. Если логика проверки прав вшита внутрь "сущности", то вам придется её продублировать в UI чтобы скрыть\задизейблить ненужные контролы.
Re[27]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 10:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

T>>Зачем это ID в кастомере? Просто передавай в метод обработки список кастомеров.
S>Откуда возьмется "список"?

Оттуда же откуда взялся у тебя свзязаный список.

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

S>Об этом я и говорю. Вот эта "предметная область" — нифига не "предметная область". Это "модель предметной области", которая сделана по некоторым соображениям.
S>Имхо, Фаулер говорил именно о предметной области, а не об артефактах, вызванных моделированием.

Ну не надо Фаулера уж совсем за идиота считать. Понятно же, что анализ/моделирование присутствует всегда.

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

S>Как артефакт анализа. Простейшая штука — ID. В предметной области никаких суррогатных ключей нету. В данных почему-то появляются.

Анализ всегда есть. Он предполагается "по умолчанию"

S>В предметной области нет никаких понятий типа "доступа", они появляются только после моделирования. Этакие "сущности второго порядка".


Почему нет? Ест такие понятия. Только формулируются они не как "существительные", а как некоторые правила, ограничения.

S>В развитом приложении, к примеру, правила валидации сами становятся "сущностями", хотя никакому объекту в предметной области они не соответствуют.


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

S>В итоге, применение ООП для моделирования "реального мира" в большинстве случаев совершенно бесполезно.


Отнюдь.

S>Вообще, напомню, что ООП появилось как попытка разработать удачную абстракцию для оконно-ориентированного GUI. Именно поэтому в ранних книгах по ООП так много примеров на тему pWindow->draw() или pFigure->draw().

S>Прошли годы, и оказалось, что даже для этих задач ООП в таком виде малопригодно.
S>Что окна удобнее собирать из готовых примитивов как агрегаты, а не наследовать друг от друга.
S>Что и геометрические фигуры не надо наследовать друг от друга, а достаточно иметь ровно один класс VectorPath, который рисуется ровно одним образом, а бытность его квадратом или треугольником — всего лишь предикат, а не имманентное свойство.

Ты очень правильно выделил "в таком". Но из того, что "в таком виде малопригодно" не следует, что ООП само по себе непригодно.
Re[39]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 11:00
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Ответственности тоже можно порезать по-разному. Можно — по модифицирующим сущностям (CustomerManager, OrderManager), можно и по бизнес — сценариям (ReservationService).

S>Первый способ — неправильный; второй — правильный.

Зачем ты тогда его ввел?

T>>Нет, я боролся за то, чтобы те сделать контракт сущности таковым, чтобы нельзя было нарушить инварианты. Если метод работы с сущностью не нарушает инвариантов, то его можно поместить и вовне класса, например в виде extension-метода, если мы используем C#. Если область действия метода шире чем данный экземпляр класса, то ему не место в классе, нужно завести отельный сервис, в котором и реализовывать необходимый функционал.

S>Всё правильно. Повторюсь: при анализе предметной области тех инвариантов, о которых ты говоришь, возникает пренебрежимо мало.
S>Даже самые очевидные штуки, типа "остатки на складе не могут быть меньше нуля" в реальной жизни оказываются неверными (например, из-за того, что оприходование товара выполняется с опозданием).

Еще раз. Это другой вопрос, это проблема анализа, не программирования.

T>>Дык, ReservationService и не является частью domain model. Это бизнес-операция.

S>Ну вот очень странно получается — важное поведение не попадает в модель.

Неудачно выразился. Резервирование не является опреацией entity, а является отдельным сервисом.

S>Это получается какая-то плохая модель, некачественная. Непонятно, почему одно поведение входит в модель, а другое — нет.


Очень все понятно. И критерий отнесения к entity тоже был сформулирован.

S>В анемичной модели всё просто: "сущности" моделируют только статическую часть предметной области, у них нет никакого поведения. А всё поведение сосредоточено во всяких ...Manager, ...Service, ...Strategy, ...Policy.


Ну так и в domain model не особо сложнее: entity, service, repository, ...

T>>Ну так как его использовать, если функциональность изменения остатков на складе уже переползла из соответствующего менеджера в ReservationService?

S>Очень просто — в данном сценарии ReservationService и стал "соответствующим менеджером"

То есть меняем мы не только в соответствующем менеджере, но и в сервисах?

T>>Из того, что "Договор заключается с каждым отдельным заказчиком" не следует, что договоры с заказчиками не имеют ничего общего. Первое что приходит в голову — это название заказчика и SLA. Кроме того, каждый заказчик регистрируется в бухгалтерской системе, в которой он получает свой номер. Этот номер — второй претендент на проверку.

S>На проверку чего?

На проверку того, что этот номер указан у кастомера

S>Намекну: бухгалтерская система может быть завтра заменена, без изменения бизнеса.


Сильно ошибаешься. Это такая замена, которая меняет многие бизнес-процессы в организации, без изменения бизнеса не получится.
Re[18]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 11:14
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Нет dataobjects в domain model, потому и такого явления как "зашивание логики в data objects", а следовательно нет и "расползанием изменений". domain model рулит!

S>Ну щас прямо. То, что было бы в анемичной модели банальной структурой "кастомер", то бишь дата обжектом, в твоей "domain model" обрастает какими-то методами, валидацией там, и так далее. В итоге изменения таки расползаются.

Так изменения и у тебя расползаются. Инварианты же тебе все равно придется проверять во всех своих сервисах/менеджерах. Где преимущество?

T>>Правильно, не был проведен анализ.

S>Почему это? Представь себе реальную жизнь — бизнес эволюционирует, требования, которых не было в Release 1, появляются в Release 2.
S>Как бы ты ни пыхтел в Release 1, всех требований ты предсказать не можешь

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

T>>И какой вывод? Отказаться от валидации совсем? Дык это не решение, т.к. если на этапе анализа было решено, что валидация нужна, то и моем и в твоем случае ее делать придется.

S>Только в моём случае не придется менять класс Customer при изменении требований к валидации.
Тебя смущает,. что файл, в котором лежит объявление атрибутов сущности, меняется или что-то еще?
Если первое, то это легко решить при помощи тех же partial-классов (C#).
Re[18]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 11:20
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>domain model по фаулеру и есть dataobjects+"какое-то мифическое поведение".


Я вчера не поленился и бегло посмотрел Фаулера. Он ссылается на книжку Эванса, которая на момент публикации PoEA не была доступна. Сейчас он уже несколько лет как ледит в магазинах. Там DDD расписан более подробно.

G>А расползание вы получите при первом же изменении бизнес требований.

G>например рассмотрим ввод данных. Раз у вас "сущности" не байндятся на контролы, то валидацию в процессе ввода вы получить не сможете. Поэтому вам придется продублировать логику валидации в UI, чтобы сделать хороший фидбэк.
G>Если у вас меняется логика валидации, то вам уже надо менять в двух местах.

Есть и другой вариант — логика валидации лежит во внешнем классе, а при изменении сущности этот внешний класс пользуется сущностью. И получили руюз.

G>Можно такой же пример с разграничением доступа рассмотреть. Если логика проверки прав вшита внутрь "сущности", то вам придется её продублировать в UI чтобы скрыть\задизейблить ненужные контролы.


То же самое может быть сделано и для разграничения доступа.
Re[19]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 11:32
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Так изменения и у тебя расползаются. Инварианты же тебе все равно придется проверять во всех своих сервисах/менеджерах. Где преимущество?

Э нет. Тут фишка в том, что за формулировку "инвариантов" отвечает один класс, а за проверку — разные.
К примеру, UI запрашивает у бизнеслогики набор правил валидации, благодаря чему пользователь получает "упс" не дожидаясь коммита.
При этом само по себе правило записано ровно один раз.

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

Вопрос только в том, где именно будет расположена эта валидация.

T>Тебя смущает,. что файл, в котором лежит объявление атрибутов сущности, меняется или что-то еще?

T>Если первое, то это легко решить при помощи тех же partial-классов (C#).
Не вижу ничего легкого.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[40]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 11:32
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Ну так и в domain model не особо сложнее: entity, service, repository, ...

Непонятно, по каким критериям распределяется логика между entity, service и repository.

T>То есть меняем мы не только в соответствующем менеджере, но и в сервисах?

Что именно меняем?

T>На проверку того, что этот номер указан у кастомера

Ок, то есть мы с трудом придумали неубедительный пример с not null инвариантом. Как и следовало ожидать,
а) этот пример достаточно сомнительный. В том смысле, что дальнейший анализ запросто может привести к тому, что в реальных сценариях нам нужно разрешать работу с кастомером еще до того, как его "номер" будет доступен
б) это настолько мягкий инвариант, что большую роль ему придавать я бы не стал. Ну то есть он же ничего не говорит ни о структуре этого номера, ни о том, что он соответствует какой-то реальной записи в бухгалтерской программе, ни, тем более, о том, что по этому номеру там заведен именно этот кастомер, а не просто сделана ошибка.

T>Сильно ошибаешься. Это такая замена, которая меняет многие бизнес-процессы в организации, без изменения бизнеса не получится.

Да ну. Никакие бизнес-процессы в организациях не меняются. Вообще, с бухгалтерской программой взаимодействуют в организации единицы людей.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[29]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 11:35
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Оттуда же откуда взялся у тебя свзязаный список.

S>Еще раз объясняю: чтобы упорядочить список кастомеров "в реале", не нужно ничего. Можно просто написать их на бумажке в нужном порядке.
S>В программировании нет концепции "пространственного расположения", поэтому нужно искусственно ввести в "описание кастомера" какие-то дополнительные данные.
S>Либо номер его позиции в списке, либо ссылку на следующего в списке.
S>Ни то ни другое не имеет отношения к предметной области. Это — артефакты моделирования. Точно так же, как и табличка для связи "многие-ко-многим" не соответствует никакому классу объектов предметной области.

Ты узко трактуешь понятие предметной области. Я отписался в предыдущем посте об этом.

T>>Ну не надо Фаулера уж совсем за идиота считать. Понятно же, что анализ/моделирование присутствует всегда.

S>Пока что непонятно. Ты очень ловко манипулируешь понятием "domain model". В итоге, она моделирует всё, что угодно. Как у Лема про сепульки.
S>Так всё-таки, что именно моделирует domain model? К чему она должна быть близка?

Тут все просто. Следите за руками
Есть бизнес. Есть анализ этого бизнеса. Есть программы, нацеленные на облегчение ведения бизнеса.
Так вот, DDD относится к третьему этапу. Основной постулат DDD — это что модель, используемая в программе должна максимально соответствовать результату анализа.

S>Мне как-то не хочется пользоваться термином, определенным через самого себя.


Это разные domain: первый — концептуальный (результат анализа), второй — программная реализация первого.

T>>Ест такие понятия. Только формулируются они не как "существительные", а как некоторые правила, ограничения.

S> И какие же правила в предметной области соответствуют DACL?

Пользователь, ассоциированный с указанным кастомером не должен иметь возможности резервировать остатки на складе №555.

T>>Для них нет "физического" представления в предметной области, но есть концептуальное.

S>Что такое "концептуальное представление"?

Результат анализа.

T>>Ты очень правильно выделил "в таком". Но из того, что "в таком виде малопригодно" не следует, что ООП само по себе непригодно.

S>Никто и не протестует против ООП вообще. Просто в бизнесе полиморфизм оказывается применим не к данным, а к сервисам.

Не надо приравнивать ООП к полиморфизму. Оно полиморфизмом не ограничивается, есть еще как минимум инкапсуляция, aka сохранение инвариантов.

S>Применять всю мощь ООП к данным — примерно то же самое, что одушевлять бухгалтерские проводки


К данным вообще не нужно применять мощь ООП, а вот к сущностям — .... см. выше
Re[20]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 11:39
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Так изменения и у тебя расползаются. Инварианты же тебе все равно придется проверять во всех своих сервисах/менеджерах. Где преимущество?

S>Э нет. Тут фишка в том, что за формулировку "инвариантов" отвечает один класс, а за проверку — разные.
S>К примеру, UI запрашивает у бизнеслогики набор правил валидации, благодаря чему пользователь получает "упс" не дожидаясь коммита.
S>При этом само по себе правило записано ровно один раз.

Я как раз по этому поводу отписался gandjustas-у.

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

S>Вопрос только в том, где именно будет расположена эта валидация.

Совершенно верно. Но тем не менее она будет нужна в обоих случаях.
Поэтому тот факт, что авлидация поменялась 5 раз за два дня, не является аргументом ни за, ни против domain model.

T>>Тебя смущает,. что файл, в котором лежит объявление атрибутов сущности, меняется или что-то еще?

T>>Если первое, то это легко решить при помощи тех же partial-классов (C#).
S>Не вижу ничего легкого.

Так тебя именно это смущало или есть что-то еще?
Re[41]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 11:47
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Ну так и в domain model не особо сложнее: entity, service, repository, ...

S>Непонятно, по каким критериям распределяется логика между entity, service и repository.

Да все понятно.
Для entity: те методы, которые относятся только к самой этой entity.
Для сервиса: сложные операции, затрагивающие "многое"
Репозиторий — взаимодействи с хранилищем.

T>>То есть меняем мы не только в соответствующем менеджере, но и в сервисах?

S>Что именно меняем?

Есть ReservationService. Как мы предположили, он списывает остатки, и обновляет строки резервируемого заказа (прописывает сколько было зарезервировано). Соответственно ответ на твой вопрос — меняем остатки на складе и кол-во зарезервированного товара в заказе.

T>>На проверку того, что этот номер указан у кастомера

S>Ок, то есть мы с трудом придумали неубедительный пример с not null инвариантом. Как и следовало ожидать,
S>а) этот пример достаточно сомнительный. В том смысле, что дальнейший анализ запросто может привести к тому, что в реальных сценариях нам нужно разрешать работу с кастомером еще до того, как его "номер" будет доступен
S>б) это настолько мягкий инвариант, что большую роль ему придавать я бы не стал. Ну то есть он же ничего не говорит ни о структуре этого номера, ни о том, что он соответствует какой-то реальной записи в бухгалтерской программе, ни, тем более, о том, что по этому номеру там заведен именно этот кастомер, а не просто сделана ошибка.

Все эти вопросы/сомнения — out of scope разработки. Это относится к анализу, поэтому в качестве аргумента за/против rich model они не очень подходят.

T>>Сильно ошибаешься. Это такая замена, которая меняет многие бизнес-процессы в организации, без изменения бизнеса не получится.

S>Да ну. Никакие бизнес-процессы в организациях не меняются. Вообще, с бухгалтерской программой взаимодействуют в организации единицы людей.

В частности меняется важнейшая операция организации, то, ради чего она собственно и существует — выставление счетов кастомерам.
Re[19]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 12:00
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>domain model по фаулеру и есть dataobjects+"какое-то мифическое поведение".


T>Я вчера не поленился и бегло посмотрел Фаулера. Он ссылается на книжку Эванса, которая на момент публикации PoEA не была доступна. Сейчас он уже несколько лет как ледит в магазинах. Там DDD расписан более подробно.


G>>А расползание вы получите при первом же изменении бизнес требований.

G>>например рассмотрим ввод данных. Раз у вас "сущности" не байндятся на контролы, то валидацию в процессе ввода вы получить не сможете. Поэтому вам придется продублировать логику валидации в UI, чтобы сделать хороший фидбэк.
G>>Если у вас меняется логика валидации, то вам уже надо менять в двух местах.

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

Не будет реюза. Как UI узнает что конкретного текстбокса нужно применить конкретное правило? А если UI автоматически генерируется для разных типов сущностей?
Будет реюз самих проверок, типа длина строки меньше X и соответствует regexp Y.
Re[30]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.01.09 12:07
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Тут все просто. Следите за руками

T>Есть бизнес. Есть анализ этого бизнеса. Есть программы, нацеленные на облегчение ведения бизнеса.
T>Так вот, DDD относится к третьему этапу. Основной постулат DDD — это что модель, используемая в программе должна максимально соответствовать результату анализа.
Ок, прекрасно. А что является результатом анализа?


T>Пользователь, ассоциированный с указанным кастомером не должен иметь возможности резервировать остатки на складе №555.

Ух, как интересно. Вообще-то, здесь нет никакой произвольности. Напомню, что DACL — это discretionary access control list.
Поэтому наиболее близкой к такому результату анализа является модель, в которой так и зашито "если работаем под пользователем, который ассоциирован с указанным кастомером, то выбросить склад №555 из рассмотрения".

Никаким DACL тут и не пахнет.

T>Результат анализа.

Ок. Сепульки — результат сепуления. В таком стиле мы далеко не уедем.

T>Не надо приравнивать ООП к полиморфизму. Оно полиморфизмом не ограничивается, есть еще как минимум инкапсуляция, aka сохранение инвариантов.

Ок. Не будем.
Почитай вот здесь.
Сильно помогает правильно расставить акценты.

S>>Применять всю мощь ООП к данным — примерно то же самое, что одушевлять бухгалтерские проводки

T>К данным вообще не нужно применять мощь ООП, а вот к сущностям — .... см. выше
Продолжаю непонимать, какой смысл в замене данных сущностями.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[20]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 12:18
Оценка:
Здравствуйте, gandjustas, Вы писали:

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

G>Не будет реюза. Как UI узнает что конкретного текстбокса нужно применить конкретное правило? А если UI автоматически генерируется для разных типов сущностей?

Ну это уже как сделаешь, это вопрос технический.
Re[31]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 12:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Есть бизнес. Есть анализ этого бизнеса. Есть программы, нацеленные на облегчение ведения бизнеса.

T>>Так вот, DDD относится к третьему этапу. Основной постулат DDD — это что модель, используемая в программе должна максимально соответствовать результату анализа.
S>Ок, прекрасно. А что является результатом анализа?

Концептуальная модель.

T>>Пользователь, ассоциированный с указанным кастомером не должен иметь возможности резервировать остатки на складе №555.

S>Ух, как интересно. Вообще-то, здесь нет никакой произвольности. Напомню, что DACL — это discretionary access control list.
S>Поэтому наиболее близкой к такому результату анализа является модель, в которой так и зашито "если работаем под пользователем, который ассоциирован с указанным кастомером, то выбросить склад №555 из рассмотрения".
S>Никаким DACL тут и не пахнет.

Не забывай, что DACL — это не только пользователи, но и группы. Вот как раз по кастомерам пользователи и группируются. Я же специально написал "ассоциированный с указанным кастомером"

T>>Результат анализа.

S>Ок. Сепульки — результат сепуления. В таком стиле мы далеко не уедем.

А что ты от меня хотел бы услышать? Формат оформления документов? В этом я увы не силен.

T>>Не надо приравнивать ООП к полиморфизму. Оно полиморфизмом не ограничивается, есть еще как минимум инкапсуляция, aka сохранение инвариантов.

S>Ок. Не будем.
S>Почитай вот здесь.
S>Сильно помогает правильно расставить акценты.

Прочитал: "HTTP/1.1 403 Access Denied." Действительно, просветление снизошло.

S>>>Применять всю мощь ООП к данным — примерно то же самое, что одушевлять бухгалтерские проводки

T>>К данным вообще не нужно применять мощь ООП, а вот к сущностям — .... см. выше
S>Продолжаю непонимать, какой смысл в замене данных сущностями.

Продолжаю повторять — сохранение инвариантов.
Re[31]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 12:30
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Есть бизнес. Есть анализ этого бизнеса. Есть программы, нацеленные на облегчение ведения бизнеса.

T>>Так вот, DDD относится к третьему этапу. Основной постулат DDD — это что модель, используемая в программе должна максимально соответствовать результату анализа.
G>Результаты анализа обычно составляют:
G>1)Описания сущностей и свзязей — ER модель
G>2)Описания бизнес-правил — валидация модели
G>3)Описания бизнес-процессов — действия, которые производятся над моделью
G>4)Описание ролей — ограничение доступа к процессам и их частям

G>Как из этого получаются объекты с поведением?


Замени "ER модель" на сущности domain model, а "валидация модели" — на constraint-ы
Re[21]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 12:52
Оценка:
Здравствуйте, Tissot, Вы писали:

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


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

G>>Не будет реюза. Как UI узнает что конкретного текстбокса нужно применить конкретное правило? А если UI автоматически генерируется для разных типов сущностей?

T>Ну это уже как сделаешь, это вопрос технический.


Это вопрос дизайна.

Чтобы такое можно было сделать каждый объект должен уметь отавать описание валидации.
Этого можно добиться двумя способами: а)интерфейсом, но тогда надо корректно инстанцировать это описание, ведь объект может создаваться явно, через конструктор, и неявно — маппером. б)внешним описанием — атрибутами, xml или чем-то еще и получать это описание по некоторому индентификатору, которым обладает объект (самое простое — по типу).
Самим процессом валидации объекта по соответствующему описанию должен заниматься какой-то сервис.

Вот и получается что валидацией знаимается внешний сервис, а не сама сущность. Можно кончено обязанность валидации сущности повесить на саму сущность и делегировать процесс сервису, но получаем теже проблемы с получением ссылки на сервис в различных условиях. А также приседания при необходимости отключить валидацию и прочее.
Re[22]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 12:58
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Чтобы такое можно было сделать каждый объект должен уметь отавать описание валидации.

G>Этого можно добиться двумя способами: а)интерфейсом, но тогда надо корректно инстанцировать это описание, ведь объект может создаваться явно, через конструктор, и неявно — маппером. б)внешним описанием — атрибутами, xml или чем-то еще и получать это описание по некоторому индентификатору, которым обладает объект (самое простое — по типу).
G>Самим процессом валидации объекта по соответствующему описанию должен заниматься какой-то сервис.

G>Вот и получается что валидацией знаимается внешний сервис, а не сама сущность. Можно кончено обязанность валидации сущности повесить на саму сущность и делегировать процесс сервису, но получаем теже проблемы с получением ссылки на сервис в различных условиях.


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

G>А также приседания при необходимости отключить валидацию и прочее.


Не надо ее отключать.
Re[32]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 13:05
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Есть бизнес. Есть анализ этого бизнеса. Есть программы, нацеленные на облегчение ведения бизнеса.

T>>>Так вот, DDD относится к третьему этапу. Основной постулат DDD — это что модель, используемая в программе должна максимально соответствовать результату анализа.
G>>Результаты анализа обычно составляют:
G>>1)Описания сущностей и свзязей — ER модель
G>>2)Описания бизнес-правил — валидация модели
G>>3)Описания бизнес-процессов — действия, которые производятся над моделью
G>>4)Описание ролей — ограничение доступа к процессам и их частям

G>>Как из этого получаются объекты с поведением?


T>Замени "ER модель" на сущности domain model, а "валидация модели" — на constraint-ы


И что от этого изменится. Указанные выше 4 пунтка как были ортогональны друг другу, так и останутся.
Re[23]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 13:12
Оценка:
Здравствуйте, Tissot, Вы писали:

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


G>>Чтобы такое можно было сделать каждый объект должен уметь отавать описание валидации.

G>>Этого можно добиться двумя способами: а)интерфейсом, но тогда надо корректно инстанцировать это описание, ведь объект может создаваться явно, через конструктор, и неявно — маппером. б)внешним описанием — атрибутами, xml или чем-то еще и получать это описание по некоторому индентификатору, которым обладает объект (самое простое — по типу).
G>>Самим процессом валидации объекта по соответствующему описанию должен заниматься какой-то сервис.

G>>Вот и получается что валидацией знаимается внешний сервис, а не сама сущность. Можно кончено обязанность валидации сущности повесить на саму сущность и делегировать процесс сервису, но получаем теже проблемы с получением ссылки на сервис в различных условиях.


T>Какие проблемы, если валидатор получаем например по типу сущности?

Такие что валидация в конечнои итоге может зависить не только от типа сущности. См валидацию zipCode.

G>>А также приседания при необходимости отключить валидацию и прочее.

T>Не надо ее отключать.
Не смешите.
Сами писали

У нас у таких сущностей есть состояние Draft. В этом состоянии проверки не делаются, т.е. фактически она работает как data object. После завершения инициализации сущность переходит в состояние Ready (с валидацией). Переход обратно невозможен.



Даже вот это

G>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).
Можно, через метод, меняющий CountryCode и Zip.

является примером временного отключения валидации, в какой-то момент внутри метода сущность перестанет быть валидной.
Re[33]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 13:23
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Замени "ER модель" на сущности domain model, а "валидация модели" — на constraint-ы


G>И что от этого изменится. Указанные выше 4 пунтка как были ортогональны друг другу, так и останутся.


Пункты ортогональны, но в программную модель они лягут по другому
Re[34]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 13:26
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Замени "ER модель" на сущности domain model, а "валидация модели" — на constraint-ы


G>>И что от этого изменится. Указанные выше 4 пунтка как были ортогональны друг другу, так и останутся.


T>Пункты ортогональны, но в программную модель они лягут по другому


По какой причние?

Указанные пункты отлично ложатся на код с тойже степенью ортогональности.
Re[24]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 13:26
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Какие проблемы, если валидатор получаем например по типу сущности?

G>Такие что валидация в конечнои итоге может зависить не только от типа сущности. См валидацию zipCode.

С zip-ом вообще в конце концов выяснили, что он не влияет на валидность кастомера, а является пред-условием отгрузки.

G>>>А также приседания при необходимости отключить валидацию и прочее.

T>>Не надо ее отключать.
G>Не смешите.
G>Сами писали
G>

G>У нас у таких сущностей есть состояние Draft. В этом состоянии проверки не делаются, т.е. фактически она работает как data object. После завершения инициализации сущность переходит в состояние Ready (с валидацией). Переход обратно невозможен.


Это состояние сущности, не искусственно введенное для отключения валидации, а отдельное состояние.

G>Даже вот это

G>

G>>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).
G>Можно, через метод, меняющий CountryCode и Zip.

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

Это внутренняя реализация, с точки зрения стороннего наблюдателя инварианты сохраняются.
Re[25]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 13:37
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>Какие проблемы, если валидатор получаем например по типу сущности?

G>>Такие что валидация в конечнои итоге может зависить не только от типа сущности. См валидацию zipCode.

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

Это в одной конкретной модели, но кастомеры могут в разных моделях.

G>>>>А также приседания при необходимости отключить валидацию и прочее.

T>>>Не надо ее отключать.
G>>Не смешите.
G>>Сами писали
G>>

G>>У нас у таких сущностей есть состояние Draft. В этом состоянии проверки не делаются, т.е. фактически она работает как data object. После завершения инициализации сущность переходит в состояние Ready (с валидацией). Переход обратно невозможен.


T>Это состояние сущности, не искусственно введенное для отключения валидации, а отдельное состояние.

Опять вспоминаем кастомера и его zipCode.


G>>Даже вот это

G>>

G>>>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).
G>>Можно, через метод, меняющий CountryCode и Zip.

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

T>Это внутренняя реализация, с точки зрения стороннего наблюдателя инварианты сохраняются.

А если сторонний наблюдатель в другом потоке?
Re[35]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 16:01
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Пункты ортогональны, но в программную модель они лягут по другому


G>По какой причние?


Потому что инвариант.

G>Указанные пункты отлично ложатся на код с тойже степенью ортогональности.


Не очень. Как защитить инварианты?
Пока что кроме договоренности о том, что изменений надо вызвать валидацию, ничего не было предложено.
Re[26]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 11.01.09 16:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>>>Какие проблемы, если валидатор получаем например по типу сущности?

G>>>Такие что валидация в конечнои итоге может зависить не только от типа сущности. См валидацию zipCode.

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

G>Это в одной конкретной модели, но кастомеры могут в разных моделях.

Какие разные модели уже? Откуда они взялись?

T>>Это состояние сущности, не искусственно введенное для отключения валидации, а отдельное состояние.

G>Опять вспоминаем кастомера и его zipCode.

Опять читаем коммент выше и забываем про zip

T>>Это внутренняя реализация, с точки зрения стороннего наблюдателя инварианты сохраняются.

G>А если сторонний наблюдатель в другом потоке?

А если между моментом, когда был вызван ваш сервис, и до момента, когда была вызвана реализация, кто-то прочитает значение из другого потока?
Не усложняй, не надо тут приплетать еще и другой поток.
Re[17]: Некоторые мысли о LINQ
От: IB Австрия http://rsdn.ru
Дата: 11.01.09 16:40
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Опять хамишь. Ты что, без этого совсем не можешь?

А как ты ждешь, чтобы на твое хамство отвечали?

T>Слышал конечно (зевок). Я же тебе же отвечал, что я не со школьной скамьи сюда пришел.

Меня терзают смутные сомнения.

T>Слушай, у меня от твоих слов мозг начинает плавиться. Зачем ты тогда писал

T>

T>добавляя новое поведение, надо его просто добавлять, а не менять старое

T>, если какая-то часть исходников все-таки трогается.
Что тебе в этой фразе не понятно?

T> Данные как раз мы не защищаем, а наоборот выставляем напоказ.

Нет, именно что защищаем. Ознакомься еще раз с тем, что такое инкапсуляция.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[27]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.01.09 18:50
Оценка:
Здравствуйте, Tissot, Вы писали:

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


T>>>>>Какие проблемы, если валидатор получаем например по типу сущности?

G>>>>Такие что валидация в конечнои итоге может зависить не только от типа сущности. См валидацию zipCode.

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

G>>Это в одной конкретной модели, но кастомеры могут в разных моделях.

T>Какие разные модели уже? Откуда они взялись?

Например система, которая занимается почтно (обычной бумажной). Все кастомеры имеют zip, кастомеры расположены в разных регионах, каждый регион в какой-то стране.
Вот вам пример. Таких моделей миллион.
Валидация zip зависит от страны региона. Как вы в таком случае обеспечите валидность zipCode в каждый момент времени в многопользовательской системе?

T>>>Это внутренняя реализация, с точки зрения стороннего наблюдателя инварианты сохраняются.

G>>А если сторонний наблюдатель в другом потоке?

T>А если между моментом, когда был вызван ваш сервис, и до момента, когда была вызвана реализация, кто-то прочитает значение из другого потока?

Если не пытаться постоянно сохранять "валиднось" по абсолютно пофиг кто и сколько раз чего читает и пишет. Конкурентную запись данных разраливает БД, перед записью данные будут провалидированы.

T>Не усложняй, не надо тут приплетать еще и другой поток.

С учетом тенденций развития железа стоит каждую программу рассматривать с позиции распараллеливания.
Re[32]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.01.09 04:51
Оценка:
Здравствуйте, Tissot, Вы писали:
T>Концептуальная модель.
А что такое "концептуальная модель"? Где ее определение?

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


T>Не забывай, что DACL — это не только пользователи, но и группы. Вот как раз по кастомерам пользователи и группируются. Я же специально написал "ассоциированный с указанным кастомером"

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

T>А что ты от меня хотел бы услышать? Формат оформления документов? В этом я увы не силен.

При чем здесь формат? Просто если мы прожолжим в том же духе, то всё сведется к утверждению типа "код приложения должен делать то, что должен делать код приложения, по мнению системного аналитика". Что, очевидно, никак не годится для аргументации той или иной архитектуры.

T>Прочитал: "HTTP/1.1 403 Access Denied." Действительно, просветление снизошло.

Прикольно. Только что закрыли. Попробуй порыть в кэше гугла.

T>Продолжаю повторять — сохранение инвариантов.

Пока что никаких инвариантов, невыразимых настройками банальной ER-модели, не прозвучало.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[33]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 12.01.09 07:40
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Концептуальная модель.

S>А что такое "концептуальная модель"? Где ее определение?

S>Замечу, что ты как-то плавно съехал с утверждения "доменная модель должна быть максимально приближена к предметной области" к "доменная модель должна соответствовать концептуальной модели". Со вторым никто не спорил, особенно если учесть, что концептуальная модель вообще только что внезапно появилась в обсуждении.


Для меня предметная область и есть результат анализа. Разве это не для всех так?! Тады ой.

T>>Не забывай, что DACL — это не только пользователи, но и группы. Вот как раз по кастомерам пользователи и группируются. Я же специально написал "ассоциированный с указанным кастомером"

S>Вот пока что непонятно, что означает "указанный кастомер". К тому же, пока что никаких групп не возникло. Есть упоминания про склад, про кастомеров, про пользователей, которые как-то проассоциированы с кастомером.
S>Группе пользователей пока что в пмире ничего не соответствует.

Соответствует — пользователи, относящиеся к этому кастомеру.

T>>А что ты от меня хотел бы услышать? Формат оформления документов? В этом я увы не силен.

S>При чем здесь формат? Просто если мы прожолжим в том же духе, то всё сведется к утверждению типа "код приложения должен делать то, что должен делать код приложения, по мнению системного аналитика". Что, очевидно, никак не годится для аргументации той или иной архитектуры.

Годится. Программная архитектура — это то, что следует ЗА анализом, не перед.

T>>Прочитал: "HTTP/1.1 403 Access Denied." Действительно, просветление снизошло.

S>Прикольно. Только что закрыли. Попробуй порыть в кэше гугла.

Ок

T>>Продолжаю повторять — сохранение инвариантов.

S>Пока что никаких инвариантов, невыразимых настройками банальной ER-модели, не прозвучало.

Где-то из подветок писал, что при закрытии кастомера должны быть закрыты соотвтствующие equipment-ы. Это вполне себе констрейнт.
Re[2]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.01.09 19:06
Оценка:
Здравствуйте, alvas, Вы писали:

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


A>Планируется ли добавление в Nemerle insert, update и delete?


Да. Но скорее всего это так и останется расширением доступным только для немерлистов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.01.09 06:21
Оценка:
Здравствуйте, Tissot, Вы писали:

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


Так не может быть "вредным и не нужным" или требуется это обосновывать? Ты уж определись.

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


T>А можно ссылку на информацию о том, что ER-подход был когда-либо продекларирован командой ADO.NET.


Читать над больше. Это не раз говорилось. К тому же даже названия технологий "LINQ to SQL" и "LINQ to Entity" говорят сами за себя.

Я всегда считал, что они делают O/R Mapper, а тут оказывается такое.

Ты бы читал внимательно что написано, тогда не пришлось бы тебе по сто раз повторять одно и то же.
Еще раз. O/R Mapper не имеет никакого отношения к идеям персистентности объектов. Так что ничего не мешает создавать O/R Mapper основанный на на них, а на ER-модели. Все что делают O/R Mapper-ы — это отображают сущности БД на типы в прграмме.

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


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


T>Которое высказывание требует доказательства?


Вот это:

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

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

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


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


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


Нельзя жить так буквально. Update, delete и insert делают тоже самое, но с учетом некоторых особенностей СУБД.
В общем, тебе яно хочется уйти от темы и поспорить с деталями.

По делу что-то хочешь сказать? Другими словами — какие у тебя имеются претензии к предложению ввести в LINQ операторы update, delete и insert?

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


Тем что нельзя написать скажем:
update customer set some = 123 where customer.Name = "XXX";

Я уже не говрю, о вариантах с подзапросами и соеденениями нескольких сущностей.

Ну, а то что ты не понимаешь и является отличным доказательством того тезиса, что Корба, ЁДжиБи и прочие Гибернэйты отлично отшлифовали мозг большой части программистов. И та теперь уже и мыслить иными категориямти не может.


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


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

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

Где в объектной модели понятие "связи" (relation)?
Как эффективно преобразовать изменение объектного графа в изменениие таблиц БД?

Утверждение о том, что объектная модель более гибка нежели ER в обще-о верно. Но гибкость определяется тем, что модель эта была предназначена для представления объектны графов в памяти, не данных в БД.
Так что именно эта гибкость и становится проблемой. По ER-модели же можно легко создать адекватную ОО-медель. Эта модель не будет иметь возможности оперировать всеми ОО-принципами и подходами, но для обработки данных этого и не надо. Зато управлять данными становится просто и можно делать это эффективно.

T>2) SQL DML vs unit of work: unit of work в большинстве случаев удобнее и предпочтительнее.


Офтоп: Господи, какая ужасная терминология. Русскими словами это выразить нельзя?

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

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


Чушь изволите говорить. Ни LINQ to SQL ни EF использовать DML не позволяют.
К тому же использование запросов эффективнее даже при единичном обновлении, так как не требуется предварительно вытаскивать данные объекта на клиента (или можно вытащить только нужные данные и за один прием).

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

Scope?

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>>


T>using(new TransactionScope())

T>Найди 10 отличий.

Ты покажи весь код. Где у тебя связь с контекстом?
Потом что будешь делать если у тебя нужно использовать один "объект" в двух транзакциях одновременно? Как это будет выглядеть.

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


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


А что тут рассказывать то? Тот кто умеет писать что-то более высокоуровневое нежели нагромаждение if-ов и циклов, тот и сам это прекрасно понимает.

Ты с sql много работал?

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


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


Да, не плохо. Но в данном случае речь не о нем.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.01.09 06:48
Оценка:
Здравствуйте, Tissot, Вы писали:

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

T>Если у вас другая информация, не мог бы ты подилиться источником оной?

Если речь идет об изменении полей одной таблицы, то всегда можно написать один запрос производящий все нужные вычисления и обновляющий данные. А такой запрос как раз будет отлично оптимизироваться.

В прочем, господа, вы в очередной раз уходите от темы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.01.09 07:16
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>В Unit of Work чтение — это обращение к объектам. Причем выполняется оно в две фазы:

S>1. Подъем объектов в память (в этот момент работает select)
S>2. Обращение к свойствам объектов.
S>Как правило, операция №1 настолько дорога, что ее выполняют через кэш. Кэширование на корню убивает возможность автоматической блокировки прочитанных объектов. Поэтому для обеспечения целостности приходится делать дополнительные приседания. Например, вручную блокировать интересующие объекты.

S>Конечно, можно обойтись и без кэша. Но тогда ситуация будет достаточно малоприятной для unit of work из-за просада производительности.

S>Теоретически, можно было бы трассировать и операции №2, аналогично тому, как это делается для отслеживания модификаций. Но на практике я такого не встречал. Смею полагать, что тоже по соображениям производительности.

Что касается блокировок, то селекты обеспечивают их не во всех случаях. Фактически полной гарантии можно добиться только при использовании верхнего уровня изоляции, что само по себе снижает эффективность. Но есть простые приемы позволяющие добиться блокировки при исползовании SQL DML. Например, меня "в детстве" учили, что получать значение счетчика надо не так (гипотетический LINQ DML):
var counter = select counter from table where id = 123;
counter++;
update table set table.counter where id = 123;

а так:
update table set counter where id = 123;
select counter from table where id = 123;

При этом запись будет заблокирована первым выражением и второй выражение вернет всегда верное значение. Блокировка же будет снята во время комита.
Более того мы можем проанализировать измененное значение и если что откатить транзакцию.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.01.09 07:26
Оценка:
Здравствуйте, Tissot, Вы писали:

T>А почему Axapta не является крупной системой?


А как ты думаешь с использованием каких подходов написана Axapta ?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 13.01.09 08:53
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Да, не плохо. Но в данном случае речь не о нем.


Ты не успел. Я уже смирился с попыткой что-либо доказать.
С "unit of work" подходом я работал и достаточно много. С ER — могу только представлять как это может выглядеть, да поверить вам на слово. Но что-то мне подсказывает, что не все так гладко будет, как вы пытаетесь тут представить.
Хотя может оказаться, что я и ошибаюсь.
Re[6]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.01.09 19:46
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Ты не успел. Я уже смирился с попыткой что-либо доказать.

T>С "unit of work" подходом я работал и достаточно много. С ER — могу только представлять как это может выглядеть, да поверить вам на слово. Но что-то мне подсказывает, что не все так гладко будет, как вы пытаетесь тут представить.
T>Хотя может оказаться, что я и ошибаюсь.

А вы его есть пробовали? (с) Реклама майонеза.

В общем, распробуй оба блюда и тогда можно будет говорить предметно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.01.09 11:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Что касается блокировок, то селекты обеспечивают их не во всех случаях.

Соыершенно верно.
VD>Фактически полной гарантии можно добиться только при использовании верхнего уровня изоляции, что само по себе снижает эффективность.
Не совсем. "Само по себе" ничто ничего не снижает.
Дело в том, что "уровень изоляции" сам по себе — некоторая фикция. Изоляция либо есть, либо её нет.
Просто обеспечение изоляции должно делаться по-разному, в зависимости от того, что делается в транзакции.
Уровни изоляции позволяют программисту подсказать серверу объем необходимых мер. Можно обойтись вместо них прямыми хинтами на каждый стейтмент, но это путь жедаев.
Фишка — в том, что теоретически инфраструктура сама может выбрать нужный уровень изоляции в том случае, если ей дать полный набор действий, которые нужно выполнить в транзакции.

VD> Но есть простые приемы позволяющие добиться блокировки при исползовании SQL DML. Например, меня "в детстве" учили, что получать значение счетчика надо не так (гипотетический LINQ DML):

VD>
VD>var counter = select counter from table where id = 123;
VD>counter++;
VD>update table set table.counter where id = 123;
VD>

Совершенно верно. Другая фишка — как раз в том, что только такой способ предлагает существующий Linq2sql. Сначала мы делаем select, потом у выбранного объекта делаем table.Counter++, а потом вызываем SaveChanges() или как он там, который построит ровно такой апдейт, как ты написал.

Причем если бы мы писали это на SQL, то можно было бы сделать в первой строчке select with(updlock), что сделало бы семантику эквивалентной семантике твоего второго примера. А если бы мы имели умный фреймворк (тм), то он бы сам добавил upddlock в первый стейтмент, увидев, что прочитанное значение используется в транзакции дальше. (А если бы мы в третьей строчке не стали менять тот же кортеж, то обошлось бы holdlock).

VD>а так:

VD>
VD>update table set counter where id = 123;
VD>select counter from table where id = 123;
VD>

VD>При этом запись будет заблокирована первым выражением и второй выражение вернет всегда верное значение. Блокировка же будет снята во время комита.
VD>Более того мы можем проанализировать измененное значение и если что откатить транзакцию.
Всё правильно. Более того, соврменный MS SQL позволяет тебе записать это одним стейтментом. И очень бы хотелось похожей мощи от Linq, вместо приседаний с unit of work.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Некоторые мысли о LINQ
От: no4  
Дата: 15.01.09 20:05
Оценка:
Здравствуйте, VladD2, Вы писали:

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

VD>Утверждение о том, что объектная модель более гибка нежели ER в обще-о верно. Но гибкость определяется тем, что модель эта была предназначена для представления объектны графов в памяти, не данных в БД.
VD>Так что именно эта гибкость и становится проблемой. По ER-модели же можно легко создать адекватную ОО-медель. Эта модель не будет иметь возможности оперировать всеми ОО-принципами и подходами, но для обработки данных этого и не надо. Зато управлять данными становится просто и можно делать это эффективно.


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

Например, сделать объектно-ориентированный язвк, чтобы он:

* был декларативныой
* поддерживал транзакции

Сделать некий рантайм, чтобы он трактовал СУБД как некий сопроцессор.

То есть как сейчас JIT транслирует IL в машкод, так подобный JIT транслировал часть IL в SQL и объекты базы данных.
Re[6]: Некоторые мысли о LINQ
От: Sinix  
Дата: 16.01.09 04:33
Оценка:
no4>Например, сделать объектно-ориентированный язвк, чтобы он:

no4> * был декларативныой

no4> * поддерживал транзакции

no4>Сделать некий рантайм, чтобы он трактовал СУБД как некий сопроцессор.


no4>То есть как сейчас JIT транслирует IL в машкод, так подобный JIT транслировал часть IL в SQL и объекты базы данных.


Можно но ненужно. Либо имеем тот же SQL, но раздутый от дополнительных фич, важных клиенту, но никак не серверу. Либо имеем некое подмножество, которое подходит для части сценариев, а для остальных — работайте напрямую с БД. Часть фич типа тех же транзакций для чисто императивных операций сделать практически нереально. Не решает это ничего, в общем.
Re[7]: Некоторые мысли о LINQ
От: no4  
Дата: 16.01.09 19:47
Оценка:
S> Либо имеем некое подмножество, которое подходит для части сценариев, а для остальных — работайте напрямую с БД.

Разве с LINQ сейчас не так?
Re[2]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.01.09 18:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А вот подоспел и ответ из Редмонда. Правда, неофициальный.


Ссылочка не открывается.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Некоторые мысли о LINQ
От: Aen Sidhe Россия Просто блог
Дата: 27.01.09 07:51
Оценка:
Здравствуйте, VladD2, Вы писали:

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


Щас меня запишут в подпевалы.

Когда я впервые увидел linq, я задался вопросом — где insert/update/delete. До сих не понимаю, почему этого не было сделано сразу — ибо сколько геморроя можно было бы избежать

ЗЫ: ссылка Sinclair у меня открылась, там описание вот этой библиотеки.
ЗЗЫ: когда Sinclair успевает все эти блоги читать? о_О
С уважением, Анатолий Попов.
ICQ: 995-908
Re[3]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 28.01.09 10:29
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Ссылочка не открывается.

Пинай своего провайдера — я только что проверил. Всё работает.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.09 14:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

VD>>Ссылочка не открывается.

S>Пинай своего провайдера — я только что проверил. Всё работает.

Может еще прохожих попинать? Сервер отвечал "Server unavailable" или тупа таймаут.
Сейчас открылся с большим скрипом.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: LINQ rulez ! , но это не только SQL
От: _DAle_ Беларусь  
Дата: 14.03.09 12:36
Оценка:
Здравствуйте, Silver_s, Вы писали:

S_>Допустим функция получает список ребер (список пар вершин) и должна вернуть вершины сгруппированые по "компонентам связности".

S_>Если смотреть такие алгоритмы в разной литературе по дискретноой математике, то там самая настоящая мышиная возня, на каком то языке паскале-си-подобном. На таких языках (такими средствами) самого алгоритма совсем чуть-чуть, основной объем кода это возня со структурами данных.
S_> Этот алгоритм можно почти целиком сделать на LINQ и объем кода раз в 5 меньше и читабельность выше, и еще Generic вершины будут.(И вроде даже производительность сильно не подсаживает.)
S_>Две небольшие статические функции. Одна публичная, другая рекурсивная:

Все это неплохо, безусловно. Я просто приведу код, делающий почти тоже самое на дуболомном с++, чтобы можно было нормально сравнить объем кода и читабельность.

S_>
S_>//Нахождение "компонент связности" графа. Принимает список ребер графа.
S_>// Возвращает список компонент, в компоненте список вершин.
S_>//если ребра(связи) повторяются то тоже будет работать правильно.
S_>public static List<List<TVertex>> FindConnectivityComponents<TVertex>(IEnumerable<Pair<TVertex, TVertex>> Links) 
S_>    where TVertex: class
S_>{
S_>    Links = Links.Concat(    //добавляем обратные связи
S_>        Links.Select(l => new Pair<TVertex, TVertex> { First = l.Second, Second= l.First })   
S_>        ); 
S_>    Dictionary<TVertex, Pair<TVertex, int>> markedVertexDict =   //ключ-вершина, значение-маркированая вершина
S_>        Links.Select(l => l.First).Distinct()
S_>        .Select(vertex => new Pair<TVertex, int> { First = vertex, Second = 0 })    //превращаем в маркированую
S_>        .ToDictionary(markedVertex => markedVertex.First)
S_>        ;
S_>    var adjucentLists =   //ключ-маркированая вершина, значение-список примыкающих маркированых вершин 
S_>        Links.ToLookup(l => markedVertexDict[l.First], l => markedVertexDict[l.Second]);

S_>    int componentNum = 1;
S_>    foreach (var vertex in markedVertexDict.Values)
S_>        MarkConnectedVertexesRecursive(vertex, componentNum++, adjucentLists);
S_>    return
S_>        markedVertexDict.Values
S_>        .GroupBy(v => v.Second, v => v.First) //(ключ-номер компоненты, значение-вершина)
S_>        .Select(grouping => grouping.ToList())
S_>        .ToList();
S_>}
S_>//Маркирует числом markWithNumber вершины начиная с startVertex, рекурсивно все связаные с ней.
S_>private static void MarkConnectedVertexesRecursive<TVertex>(
S_>    Pair<TVertex, int> startVertex,
S_>    int markWithNumber,
S_>    ILookup<Pair<TVertex, int>, Pair<TVertex, int>> graphAsAdjacentLists)
S_>{
S_>    if (startVertex.Second != 0) //уже прошлись по этой вершине
S_>        return;
S_>    startVertex.Second = markWithNumber;
S_>    foreach (Pair<TVertex, int> linked in graphAsAdjacentLists[startVertex])
S_>        MarkConnectedVertexesRecursive(linked, markWithNumber, graphAsAdjacentLists);
S_>}       
S_>


template<class TVertex> 
vector<vector<TVertex> > FindConnectivityComponents(const vector<pair<TVertex, TVertex> >& Links) 
{
    map<TVertex, int> vertexDict;
    vector<vector<int> > adjacentList;
    vector<vector<TVertex> > result;
    vector<TVertex> vertices;
    for (size_t i = 0; i < Links.size(); ++i)
    {
        if (vertexDict.count(Links.first) == 0)
        {
            vertexDict[Links.first] = vertexDict.size();
            vertices.push_back(Links.first);
            adjacentList.push_back(vector<int>());
        }
        if (vertexDict.count(Links.second) == 0)
        {
            vertexDict[Links.second] = vertexDict.size();
            vertices.push_back(Links.second);
            adjacentList.push_back(vector<int>());
        }
        adjacentList[vertexDict[Links.first]].push_back(vertexDict[Links.second]);
        adjacentList[vertexDict[Links.second]].push_back(vertexDict[Links.first]);
    }
    vector<int> was(vertices.size(), 0);
    for (size_t i = 0; i < vertices.size(); ++i)
        if (was[i] == 0)
        {
            result.push_back(vector<TVertex>())
            MarkConnectedVertexesRecursive(i, adjacentList, vertices, result);       
        }
    return result;
}

template<class TVertex>
void MarkConnectedVertexesRecursive(
    int vertex,
    const vector<vector<int> >& adjacentList,
    const vector<TVertex>& vertices,
    const vector<int>& was,
    vector<vector<TVertex> >& result 
{
    was[vertex] = 1;
    result.back().push_back(vertices[vertex[vertex]]);
    for (size_t i = 0; i < adjacentList[vertex].size(); ++i)
        if (was[adjacentList[vertex][i]] == 0) 
           MarkConnectedVertexesRecursive(adjacentList[vertex][i], adjacentList, vertices, was, result);
}

Теперь можно избивать пещерный императивный код на плюсах на примере.
Re[3]: LINQ rulez ! , но это не только SQL
От: Silver_s Ниоткуда  
Дата: 14.03.09 15:27
Оценка:
Здравствуйте, _DAle_, Вы писали:

__DA>... Я просто приведу код, делающий почти тоже самое на дуболомном с++, чтобы можно было нормально сравнить объем кода и читабельность.



Ну, конечно, ATL (или как его там) не такая уж беспомощная вещь...
А читабельность все же (по крайней мере для меня) выше у варианта на LINQ.
На LINQ читабельность будет высокая если семантика, и можно сказать синтаксис (т.к. это почти язык в языке C#),
всех функций в Enumerable до боли знакома.
Читабельность снижают for с индексами, if внутри циклов, крупные тела циклов, большое количество вложенных индексаторов
например такое не очень красиво выглядит:
adjacentList[vertexDict[Links[i].first]].push_back(vertexDict[Links[i].second]);
Кстати в в тексте пропущен индексатор после Links (или промежуточная переменная не создана)
Снижают читабельность и тайные(неявные) связи, например между векторами adjacentList и vertices

В варианте на LINQ код более плоский, последовательный.

Хотя, конечно, никаких проблем с таким кодом на C++ нету, достаточно компактный.
Но он все таки немного по другому сделан, просто есть альтернативные варианты реаизации этой функции.
Но примеры можно найти и когда 3-4 строчки против 15.

Но так издеваться над данными как LINQ, кромсать, переделывать, переорганизовывать,обрабатывать, в 3-4 строчек
кода традиционный ATL все-таки не может.
Все же основная польза от LINQ даже не такие функции, как приведенна выше, а мелкие но меткие вставки в 2-3 строчки
разбросаные по всему проекту.
Re[2]: LINQ rulez ! , но это не только SQL
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.03.09 05:04
Оценка:
Здравствуйте, Silver_s, Вы писали:


S_>И еще хочется чтобы конструкторы имели Generic параметры и по ним выводился создаваемый класс.

S_>например вместо new Pair<int,string>(1,"s") чтобы можно было бы написать new Pair(1,"s") и по конструктору
S_>бы настроился созданный класс. Потому что вместо int,string могут стоять гигантские конструкции с Generic,
S_>а класс Pair (или Triple) могут употребляться часто в разных целях. Анонимными типами их не всегда удается заменить.

Для этого достаточно сделать вот так:
public static Pair<T1, T2> NewPair<T1, T2>(T1 t1, T2 t2)
{
  return new Pair<T1, T2>(t1, t2);
}

Тогда твой код будет немножко покороче:
public static List<List<TVertex>> FindConnectivityComponents<TVertex>(IEnumerable<Pair<TVertex, TVertex>> Links) 
    where TVertex: class
{
    Links = Links.Concat(    //добавляем обратные связи
        Links.Select(l => NewPair(l.Second, l.First))
            ); 
    var markedVertexDict =   //ключ-вершина, значение-маркированая вершина
        Links.Select(l => l.First).Distinct()
        .Select(vertex => NewPair(vertex, 0))    //превращаем в маркированую
        .ToDictionary(markedVertex => markedVertex.First)
        ;
    var adjucentLists =   //ключ-маркированая вершина, значение-список примыкающих маркированых вершин 
        Links.ToLookup(l => markedVertexDict[l.First], l => markedVertexDict[l.Second]);

    int componentNum = 1;
    foreach (var vertex in markedVertexDict.Values)
        MarkConnectedVertexesRecursive(vertex, componentNum++, adjucentLists);
    return
        markedVertexDict.Values
        .GroupBy(v => v.Second, v => v.First) //(ключ-номер компоненты, значение-вершина)
        .Select(grouping => grouping.ToList())
        .ToList();
}
//Маркирует числом markWithNumber вершины начиная с startVertex, рекурсивно все связаные с ней.
private static void MarkConnectedVertexesRecursive<TVertex>(
    Pair<TVertex, int> startVertex,
    int markWithNumber,
    ILookup<Pair<TVertex, int>, Pair<TVertex, int>> graphAsAdjacentLists)
{
    if (startVertex.Second != 0) //уже прошлись по этой вершине
        return;
    startVertex.Second = markWithNumber;
    foreach (Pair<TVertex, int> linked in graphAsAdjacentLists[startVertex])
        MarkConnectedVertexesRecursive(linked, markWithNumber, graphAsAdjacentLists);
}
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 23.03.09 22:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Чтобы изменить данные в обеих реализациях LINQ нужно получить объект, изменить его свойства, поместить этот объект в специальный контекст (если он еще не находится в нем) и, в конце концов, выполнить у этого контекста процедуру записи. Это тот же самый подход, что используется в Hibernate и ему подобных PI-средах. И нужен этот подход именно потому, и только для того, чтобы скрыть от разработчика реальную – реляционную – суть обрабатываемых данных, и позволить ему возиться с объектами, как будто они являются полноценными (в смысле ООП) объектами, а не отображением ER-сущностей.


Это нужно не для того, чтобы скрыть реляционную модель. Это нужно потому, что кроме запросов там есть еще и контроль т.н. "optimistic concurrency". А это — очень немаловажная часть работы с базой данных в типичных сценариях. Про это часто забывают, а когда в конце-концов сталкиваются — о-го-го как огребают граблями по голове. А тут оно как-то вроде неплохо приделано: вроде и не мешает, и вроде как на виду.
А потом — какой ты хочешь API для insert/update в плане передачи значений строчки? Как-бы самый логичный — это использовать для этого объект, который уже замэплен на таблицу. А оно так и сделано.
Или ты имеешь ввиду всякие вставки с параллельным селектом из других таблиц или "update X set Y = 0 where"? Если да — то это тоже отдельная история на мой взгляд. Это очень нечасто требуется, реализовать сложно, это выпадает из концепции. Да и красота — она в простоте
Re[2]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.03.09 23:02
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Это нужно не для того, чтобы скрыть реляционную модель. Это нужно потому, что кроме запросов там есть еще и контроль т.н. "optimistic concurrency". А это — очень немаловажная часть работы с базой данных в типичных сценариях. Про это часто забывают, а когда в конце-концов сталкиваются — о-го-го как огребают граблями по голове. А тут оно как-то вроде неплохо приделано: вроде и не мешает, и вроде как на виду.


С блокировками у текущего подхода только больше проблем. А на запросах я тебе любую модель изобразить смогу.

J>А потом — какой ты хочешь API для insert/update в плане передачи значений строчки? Как-бы самый логичный — это использовать для этого объект, который уже замэплен на таблицу. А оно так и сделано.


Этот вопрос требует продумывания. Но ясно одно, что нужно не только иметь возможность изменить один объект, но и иметь возможность изменить одним запросом группу объектов (точнее строк/кортежей данных).

J>Или ты имеешь ввиду всякие вставки с параллельным селектом из других таблиц или "update X set Y = 0 where"?


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

J> Если да — то это тоже отдельная история на мой взгляд. Это очень нечасто требуется, реализовать сложно, это выпадает из концепции. Да и красота — она в простоте


Тебе, может быть. Мне это периодически требовалось.
Что касается концепции, то это какие-то твои личные концепции. Я как-то не вижу выпадения из концепций linq-а. Вот отсутствие возможности изменить объект запросом — это и правда выпадение из концепции.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 24.03.09 00:06
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>С блокировками у текущего подхода только больше проблем. А на запросах я тебе любую модель изобразить смогу.


Проблем много, но все-таки в LINQ to SQL проблемы с concurency хотя бы как-то выпаливаются и выдаются в относительно удобоваримом виде. Можно было бы как-то отделить это, чтобы можно было и самостоятельно эту проблему решать. Но, как показывает практика, если постоянно не напоминать об этой проблеме, то среднестатистические C#-разработчики просто забудут или отложат на потом. И я считаю что вся эта эпопея с обязательным DataContext-ом — очень мудрое решение, хотя это и копромис. Оно решает далеко не все проблемы с конкурентным доступом, но, как показывает практика, часто и такого уже — за глаза.
Ну и вообще, в целом, я только хотел сказать что db.InsertOnUpdate() — оно именно из-за этого так, а не для высоких ORM-целей.

VD>Что касается концепции, то это какие-то твои личные концепции. Я как-то не вижу выпадения из концепций linq-а. Вот отсутствие возможности изменить объект запросом — это и правда выпадение из концепции.


Я концепцию Linq to sql не стал бы идеализировать. Это всего лишь совокупность средств, призваных решать типовые задачи по работе с базой, без каких-либо потугов на панацею. А типовые задачи такие:
1. достать данные из базы. Достать по возможности быстро и без гемора в любых его проявлениях. Достать только необходимый объем: чем меньше — тем лучше, но без фанатизма.
2. засунуть данные назад в базу. Чаще всего их немного: пара-дюжина измененных руками на UI объектов, пара строчек каких-либо свежеполученых откуда-либо данных, и т.п.
3. найти и помочь программисту разрулить проблемы конкурентного изменения данных
Все остальные задачи по работе с БД в типовых проектах составляют часто весьма большую, но не бОльшую часть.
Задачи, кроме этих трех, бывают весьма разнообразные. И непонятно как их обобщить. Одному нужно по ночам заливать в базу гигабайты blob-ов, другой увеличивает оклад через update X set salary = salary + 100 where gender = 'F', и т.п. Есть еще миграция данных при изменении схемы, где массовые update-ы и insert-ы как раз очень кстати.
Но это все хрен впихнешь в общую концепцию.

В общем моё имхо — ни к чему было пытаться это все впихнуть в легкий и прозрачный Linq to sql. И если ты, когда припрет, напишешь sqlCommand.CommandText = "update ... set ... where ...", динозавр не прибежит и не откусит тебе голову*

*http://xkcd.com/292/
Re[4]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.03.09 19:16
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>В общем моё имхо — ни к чему было пытаться это все впихнуть в легкий и прозрачный Linq to sql. И если ты, когда припрет, напишешь sqlCommand.CommandText = "update ... set ... where ...", динозавр не прибежит и не откусит тебе голову*


Это будет резко отличаться от подхода с датаконтекстом и с большой вероятностью приведет к проблемам.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 11:08
Оценка:
Здравствуйте, VladD2, Вы писали:

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


J>>В общем моё имхо — ни к чему было пытаться это все впихнуть в легкий и прозрачный Linq to sql. И если ты, когда припрет, напишешь sqlCommand.CommandText = "update ... set ... where ...", динозавр не прибежит и не откусит тебе голову*


VD>Это будет резко отличаться от подхода с датаконтекстом и с большой вероятностью приведет к проблемам.


Ну вот и непонятно как в подходе с датаконтекстом обрабатывать запросы типа "delete * from Blabla". Я не представляю как такое может жить вместе со всяким identity tracking.
Re[7]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 12:04
Оценка:
Здравствуйте, VladD2, Вы писали:

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


VD>>>Это будет резко отличаться от подхода с датаконтекстом и с большой вероятностью приведет к проблемам.


J>>Ну вот и непонятно как в подходе с датаконтекстом обрабатывать запросы типа "delete * from Blabla". Я не представляю как такое может жить вместе со всяким identity tracking.


VD>Дык, мне сам этот подход и не нравится. Датоконтекст должен пойти в топку.


И отслеживать identity и конфликты самостоятельно? Или придумывать свой велосипед? Нет уж. Я лучше уж с DataContext, а без массовых update-ов как-нибудь проживу.
Re[8]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.03.09 12:27
Оценка:
Здравствуйте, Jakobz, Вы писали:

VD>>Дык, мне сам этот подход и не нравится. Датоконтекст должен пойти в топку.


J>И отслеживать identity и конфликты самостоятельно? Или придумывать свой велосипед? Нет уж. Я лучше уж с DataContext, а без массовых update-ов как-нибудь проживу.


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

Твое identity не более чем уникальный идентификатор. Хочешь сделай счетчик на сервере, хочешь используй GUID. Это сто лет назад решенная проблема.

Конфликтов же у тебя будет даже меньше. По крайней мере ими можно будет успешно управлять.

RowID позволяет обеспечить оптимистическую блокировку. Явное управлением транзакциями и уровнем изоляции — пессимистическую. Где проблемы то?

Просто ты привык к схемам тяжелых OR-маперов. Вот и боишься, что они вдруг исчезнут.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 13:18
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Не будет дурацкой схемы датаконтекстов не будет и проблем связанных с ней.


Хорошая логика. Типа "нет человека — нет проблем" Не будет датаконтекстов — не будет и удобств, которые они дают.

Собственно тебя никто и не заставляет юзать DataContext. Совсем от него отказаться нельзя, но можно же select-ить в ReadOnly, а апдейтить потом как угодно.

VD>Твое identity не более чем уникальный идентификатор. Хочешь сделай счетчик на сервере, хочешь используй GUID. Это сто лет назад решенная проблема.


Я имел ввиду identity объектов:
1. select * from Persons where person_id = 1
2. юзер выбирает список персон
3. select * from Persons
Первая персона у нас теперь в виде объектов в двух экземплярах — из первого и второго запроса.
Не запутаешься с этим? Ничего что "==" для объектов нельзя будет использовать? Или будет собственный велик?

VD>Конфликтов же у тебя будет даже меньше. По крайней мере ими можно будет успешно управлять.


Откуда их станет меньше? Почему я не могу успешно управлять ими в LINQ to SQL?

VD>RowID позволяет обеспечить оптимистическую блокировку. Явное управлением транзакциями и уровнем изоляции — пессимистическую. Где проблемы то?


Проблема в том, что эта проблема в очередной раз будет решаться руками или велосипедами.

VD>Просто ты привык к схемам тяжелых OR-маперов. Вот и боишься, что они вдруг исчезнут.


Не, я вообще не привык к комфорту. На проекте, на котором я уже пару лет занят — вообще датасеты и все руками. Но у нас специфика такая, что в основном с базой только на чтение работа идет.
Re[10]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.03.09 14:24
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Хорошая логика. Типа "нет человека — нет проблем" Не будет датаконтекстов — не будет и удобств, которые они дают.


А в чем удобства то?

J>Собственно тебя никто и не заставляет юзать DataContext. Совсем от него отказаться нельзя, но можно же select-ить в ReadOnly, а апдейтить потом как угодно.


Дык апдэйты не типизированными будут.

J>Я имел ввиду identity объектов:

J>1. select * from Persons where person_id = 1
J>2. юзер выбирает список персон
J>3. select * from Persons
J>Первая персона у нас теперь в виде объектов в двух экземплярах — из первого и второго запроса.

И что? Это не проблема. Апдэйты ведь ведутся по тому самому person_id.

J>Не запутаешься с этим? Ничего что "==" для объектов нельзя будет использовать?


Это почему нельзя? Реализуй оператор корректно и используй.

J>Или будет собственный велик?


Классы все равно самому писать... точнее генерировать их функциональность. Реализация оператор сравнения делается в пол пинка. Я же не C# весь код добить собираюсь .

VD>>Конфликтов же у тебя будет даже меньше. По крайней мере ими можно будет успешно управлять.


J>Откуда их станет меньше? Почему я не могу успешно управлять ими в LINQ to SQL?


А потому что датаконтекс предлагает тебе только одну реализацию. У нее масса ограничений и проблем.

VD>>RowID позволяет обеспечить оптимистическую блокировку. Явное управлением транзакциями и уровнем изоляции — пессимистическую. Где проблемы то?


J>Проблема в том, что эта проблема в очередной раз будет решаться руками или велосипедами.


А что там решать то? В коде апдэйта автоматом докидвать RowID = RowID?

А как решать проблемы создаваемые этим самым датаконтекстом? Что если оптимистическая блокировка по логике не подходит? Подстраиваться?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 15:12
Оценка:
Здравствуйте, gandjustas, Вы писали:

VD>>>Не будет дурацкой схемы датаконтекстов не будет и проблем связанных с ней.

J>>Хорошая логика. Типа "нет человека — нет проблем" Не будет датаконтекстов — не будет и удобств, которые они дают.
G>Самое интересное что это работает.

Что работает?

J>>Собственно тебя никто и не заставляет юзать DataContext. Совсем от него отказаться нельзя, но можно же select-ить в ReadOnly, а апдейтить потом как угодно.

G>В том то и дело что заапдейтить без работы с объектами и datacontext нельзя.

Ну, можно написать же самому. Нужна штука, которой нужно передать список объектов, которые нужно залить в базу, она отсортирует операции update/delete/insert по связям и в нужной очереди зальёт. Стоп... Что-то мне это напоминает...


G>В EF есть entitykey для этих целей.

G>И даже без него операцию == можно определить так чтобы она нормально работала (по ключам).

Можно. Но нужно будет это делать самостоятельно.


G>На самом деле привычка больше в способе работы: считать->изменить->записать. Естественно между двумя обращениями может много чего произойти, вот и городят optimistic concurrency.


Проблема optimistic concurency вызвана ограниченостью скорости света. Ее не городят специально, это природное явление.

G>Если применить Command-query separation к работе с данными, то все операции можно будет разделить на два типа

G>1)выборка без побочных эффектов, identity map и unit of work не нужны, и никакой контекст не нужен.
G>2)операции, вызывающие изменения данных можно будет делать как отправку батча sql-команд на сервер, контекст тоже не нужен.

А чем это отличается от подхода "считали -> изменили -> записали"?
Re[11]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 15:28
Оценка:
Здравствуйте, VladD2, Вы писали:

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


J>>Хорошая логика. Типа "нет человека — нет проблем" Не будет датаконтекстов — не будет и удобств, которые они дают.


VD>А в чем удобства то?


— identity tracking
— change tracking


J>>Собственно тебя никто и не заставляет юзать DataContext. Совсем от него отказаться нельзя, но можно же select-ить в ReadOnly, а апдейтить потом как угодно.


VD>Дык апдэйты не типизированными будут.


Апдейть через другой DataContext. Или пиши своё — со множественными апдейтами.


J>>Я имел ввиду identity объектов:

J>>1. select * from Persons where person_id = 1
J>>2. юзер выбирает список персон
J>>3. select * from Persons
J>>Первая персона у нас теперь в виде объектов в двух экземплярах — из первого и второго запроса.

VD>И что? Это не проблема. Апдэйты ведь ведутся по тому самому person_id.


Какую из персон менять будешь? Не перепутаешь потом какую в базу потом запихивать? Не получится что обе-две в случайном порядке?


VD>>>Конфликтов же у тебя будет даже меньше. По крайней мере ими можно будет успешно управлять.


J>>Откуда их станет меньше? Почему я не могу успешно управлять ими в LINQ to SQL?


VD>А потому что датаконтекс предлагает тебе только одну реализацию. У нее масса ограничений и проблем.


Датаконтект предлагает реализацию оптимистических блокировок. И не мешает делать пессимистические. Разве кроме этих двух есть какие-то другие подходы?


VD>А что там решать то? В коде апдэйта автоматом докидвать RowID = RowID?

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

VD>А как решать проблемы создаваемые этим самым датаконтекстом? Что если оптимистическая блокировка по логике не подходит? Подстраиваться?


Отключать оптимистический контроль. Включать блокировку при запросе, если все проводится в одну транзакцию. Если не в одну транзакцию — наверное делать какой-то lock manager. Не вижу чтобы Linq to SQL здесь навязывала именно свое решение.
Re[11]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 15:31
Оценка:
Здравствуйте, IT, Вы писали:

J>>Я имел ввиду identity объектов:

J>>1. select * from Persons where person_id = 1
J>>2. юзер выбирает список персон
J>>3. select * from Persons
J>>Первая персона у нас теперь в виде объектов в двух экземплярах — из первого и второго запроса.
J>>Не запутаешься с этим? Ничего что "==" для объектов нельзя будет использовать? Или будет собственный велик?

IT>Вот уже лет пять не испытываю с этим никаких проблем. Два экземпляра одной сущности могут мещать только в statefull архитектурах, которые являются проблемой сами по себе. А вместо "==", которое опять же в нормальном дизайне нафиг не нужно, можно с успехом использовать person1.ID == person2.ID.


А что ты понимаешь под базвордом "statefull-архитектура"? Почему дизайн с person1 == person2 — не нормален?
Re[12]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.09 15:47
Оценка:
Здравствуйте, Jakobz, Вы писали:


J>>>Собственно тебя никто и не заставляет юзать DataContext. Совсем от него отказаться нельзя, но можно же select-ить в ReadOnly, а апдейтить потом как угодно.

G>>В том то и дело что заапдейтить без работы с объектами и datacontext нельзя.
J>Ну, можно написать же самому. Нужна штука, которой нужно передать список объектов, которые нужно залить в базу, она отсортирует операции update/delete/insert по связям и в нужной очереди зальёт. Стоп... Что-то мне это напоминает...
Неверно. Не надо никуда передавать объекты.

G>>В EF есть entitykey для этих целей.

G>>И даже без него операцию == можно определить так чтобы она нормально работала (по ключам).
J>Можно. Но нужно будет это делать самостоятельно.
Можно и не сравнивать сущности, а сравнивать их ключевые поля.
Переопределять равенство имеет смысл в случае составных ключей в POCO-сущностях.

G>>На самом деле привычка больше в способе работы: считать->изменить->записать. Естественно между двумя обращениями может много чего произойти, вот и городят optimistic concurrency.

J>Проблема optimistic concurency вызвана ограниченостью скорости света. Ее не городят специально, это природное явление.
На самом деле городят, потому что сама БД обеспечивает pessimistic concurrency.

G>>Если применить Command-query separation к работе с данными, то все операции можно будет разделить на два типа

G>>1)выборка без побочных эффектов, identity map и unit of work не нужны, и никакой контекст не нужен.
G>>2)операции, вызывающие изменения данных можно будет делать как отправку батча sql-команд на сервер, контекст тоже не нужен.

J>А чем это отличается от подхода "считали -> изменили -> записали"?

Все операции изменения данных выполняются в СУБД с блокировками.
Re[13]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 16:16
Оценка:
Здравствуйте, gandjustas, Вы писали:

J>>>>Собственно тебя никто и не заставляет юзать DataContext. Совсем от него отказаться нельзя, но можно же select-ить в ReadOnly, а апдейтить потом как угодно.

G>>>В том то и дело что заапдейтить без работы с объектами и datacontext нельзя.
J>>Ну, можно написать же самому. Нужна штука, которой нужно передать список объектов, которые нужно залить в базу, она отсортирует операции update/delete/insert по связям и в нужной очереди зальёт. Стоп... Что-то мне это напоминает...
G>Неверно. Не надо никуда передавать объекты.

Ок. Если нужно залить несколько разных объектов кто будет заниматься сортировкой операций insert/update/delete?

G>>>В EF есть entitykey для этих целей.

G>>>И даже без него операцию == можно определить так чтобы она нормально работала (по ключам).
J>>Можно. Но нужно будет это делать самостоятельно.
G>Можно и не сравнивать сущности, а сравнивать их ключевые поля.
G>Переопределять равенство имеет смысл в случае составных ключей в POCO-сущностях.

Я в другой ветке писал про это. Что если у нас два одинаковых объекты и мы поменяем только один?

G>>>На самом деле привычка больше в способе работы: считать->изменить->записать. Естественно между двумя обращениями может много чего произойти, вот и городят optimistic concurrency.

J>>Проблема optimistic concurency вызвана ограниченостью скорости света. Ее не городят специально, это природное явление.
G>На самом деле городят, потому что сама БД обеспечивает pessimistic concurrency.
Pessimistic — да, обеспечивает. На уровне одного соединения/транзакции. Как средствами СУБД обрабатывать классическую ситуацию: чувак открыл форму редактирования, ушел домой, а кому-то нужно что-то в ней этой же форме поправить?

G>>>Если применить Command-query separation к работе с данными, то все операции можно будет разделить на два типа

G>>>1)выборка без побочных эффектов, identity map и unit of work не нужны, и никакой контекст не нужен.
G>>>2)операции, вызывающие изменения данных можно будет делать как отправку батча sql-команд на сервер, контекст тоже не нужен.

J>>А чем это отличается от подхода "считали -> изменили -> записали"?

G>Все операции изменения данных выполняются в СУБД с блокировками.

Update() в LINQ тоже с блокировками выполняется и в одной транзакции. Странно, зачем там optimistic concurency?
Re[14]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.09 16:38
Оценка:
Здравствуйте, Jakobz, Вы писали:

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


J>>>>>Собственно тебя никто и не заставляет юзать DataContext. Совсем от него отказаться нельзя, но можно же select-ить в ReadOnly, а апдейтить потом как угодно.

G>>>>В том то и дело что заапдейтить без работы с объектами и datacontext нельзя.
J>>>Ну, можно написать же самому. Нужна штука, которой нужно передать список объектов, которые нужно залить в базу, она отсортирует операции update/delete/insert по связям и в нужной очереди зальёт. Стоп... Что-то мне это напоминает...
G>>Неверно. Не надо никуда передавать объекты.

J>Ок. Если нужно залить несколько разных объектов кто будет заниматься сортировкой операций insert/update/delete?

В каком порядке передали, в таком и выполнять.

G>>>>В EF есть entitykey для этих целей.

G>>>>И даже без него операцию == можно определить так чтобы она нормально работала (по ключам).
J>>>Можно. Но нужно будет это делать самостоятельно.
G>>Можно и не сравнивать сущности, а сравнивать их ключевые поля.
G>>Переопределять равенство имеет смысл в случае составных ключей в POCO-сущностях.
J>Я в другой ветке писал про это. Что если у нас два одинаковых объекты и мы поменяем только один?
Тот который укажем.

G>>>>На самом деле привычка больше в способе работы: считать->изменить->записать. Естественно между двумя обращениями может много чего произойти, вот и городят optimistic concurrency.

J>>>Проблема optimistic concurency вызвана ограниченостью скорости света. Ее не городят специально, это природное явление.
G>>На самом деле городят, потому что сама БД обеспечивает pessimistic concurrency.
J>Pessimistic — да, обеспечивает. На уровне одного соединения/транзакции. Как средствами СУБД обрабатывать классическую ситуацию: чувак открыл форму редактирования, ушел домой, а кому-то нужно что-то в ней этой же форме поправить?
Треназакцию держать не надо. Встроенные возможности контекства тоже не попогут (веб-приложение например).
Не факт что вообще concurrency тут неоходимо, вполне возможно last wins и все.

G>>>>Если применить Command-query separation к работе с данными, то все операции можно будет разделить на два типа

G>>>>1)выборка без побочных эффектов, identity map и unit of work не нужны, и никакой контекст не нужен.
G>>>>2)операции, вызывающие изменения данных можно будет делать как отправку батча sql-команд на сервер, контекст тоже не нужен.

J>>>А чем это отличается от подхода "считали -> изменили -> записали"?

G>>Все операции изменения данных выполняются в СУБД с блокировками.

J>Update() в LINQ тоже с блокировками выполняется и в одной транзакции. Странно, зачем там optimistic concurency?

Update() выполняется, а чтение+Update — нет, для этого и городится.
При этом во многих случаях где optimistic concurency действительно нужно возможностей контекста не хватает.
Re[15]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 17:12
Оценка:
Здравствуйте, gandjustas, Вы писали:

J>>Ок. Если нужно залить несколько разных объектов кто будет заниматься сортировкой операций insert/update/delete?

G>В каком порядке передали, в таком и выполнять.

Сортировать нужно в любом случае. Вопрос только кто будет этим заниматься.
Ну или можно constraint-ы в базе отключить.

G>>>>>В EF есть entitykey для этих целей.

G>>>>>И даже без него операцию == можно определить так чтобы она нормально работала (по ключам).
J>>>>Можно. Но нужно будет это делать самостоятельно.
G>>>Можно и не сравнивать сущности, а сравнивать их ключевые поля.
G>>>Переопределять равенство имеет смысл в случае составных ключей в POCO-сущностях.
J>>Я в другой ветке писал про это. Что если у нас два одинаковых объекты и мы поменяем только один?
G>Тот который укажем.

Ну ок, можно и так. Но мне кажется что приятно быть увереным что внутри контекста может быть только один объект для одного ID. А ну как не тот укажешь или что еще страшное случится?

G>>>>>На самом деле привычка больше в способе работы: считать->изменить->записать. Естественно между двумя обращениями может много чего произойти, вот и городят optimistic concurrency.

J>>>>Проблема optimistic concurency вызвана ограниченостью скорости света. Ее не городят специально, это природное явление.
G>>>На самом деле городят, потому что сама БД обеспечивает pessimistic concurrency.
J>>Pessimistic — да, обеспечивает. На уровне одного соединения/транзакции. Как средствами СУБД обрабатывать классическую ситуацию: чувак открыл форму редактирования, ушел домой, а кому-то нужно что-то в ней этой же форме поправить?
G>Треназакцию держать не надо. Встроенные возможности контекства тоже не попогут (веб-приложение например).

Почему встроеные возможности контекста не помогут? Вполне себе оно на вебе работает. Только нужно RowVersion в скрытое поле положить или как-то иначе сохранить, но это уже извините.

G>Не факт что вообще concurrency тут неоходимо, вполне возможно last wins и все.


Давай все-таки рассматривать ситуацию когда "last wins" недостаточно.

J>>Update() в LINQ тоже с блокировками выполняется и в одной транзакции. Странно, зачем там optimistic concurency?

G>Update() выполняется, а чтение+Update — нет, для этого и городится.

Выполняй чтение в одной транзакции с SubmitChanges(), в чем проблема?

G>При этом во многих случаях где optimistic concurency действительно нужно возможностей контекста не хватает.


Каких, например?
Re[16]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.09 17:31
Оценка:
Здравствуйте, Jakobz, Вы писали:

G>>>>>>В EF есть entitykey для этих целей.

G>>>>>>И даже без него операцию == можно определить так чтобы она нормально работала (по ключам).
J>>>>>Можно. Но нужно будет это делать самостоятельно.
G>>>>Можно и не сравнивать сущности, а сравнивать их ключевые поля.
G>>>>Переопределять равенство имеет смысл в случае составных ключей в POCO-сущностях.
J>>>Я в другой ветке писал про это. Что если у нас два одинаковых объекты и мы поменяем только один?
G>>Тот который укажем.

J>Ну ок, можно и так. Но мне кажется что приятно быть увереным что внутри контекста может быть только один объект для одного ID. А ну как не тот укажешь или что еще страшное случится?

Вообще говоря получение одной сущности двумя путями — признак хренового проектирования.

G>>>>>>На самом деле привычка больше в способе работы: считать->изменить->записать. Естественно между двумя обращениями может много чего произойти, вот и городят optimistic concurrency.

J>>>>>Проблема optimistic concurency вызвана ограниченостью скорости света. Ее не городят специально, это природное явление.
G>>>>На самом деле городят, потому что сама БД обеспечивает pessimistic concurrency.
J>>>Pessimistic — да, обеспечивает. На уровне одного соединения/транзакции. Как средствами СУБД обрабатывать классическую ситуацию: чувак открыл форму редактирования, ушел домой, а кому-то нужно что-то в ней этой же форме поправить?
G>>Треназакцию держать не надо. Встроенные возможности контекства тоже не попогут (веб-приложение например).

J>Почему встроеные возможности контекста не помогут? Вполне себе оно на вебе работает. Только нужно RowVersion в скрытое поле положить или как-то иначе сохранить, но это уже извините.

И этот же rowversion надо получать на клиентской стороне в момент окончания длительной операции.
Что ОРМы предлагают для этого? Только запрос писать? Так это я и без контекста могу.

G>>Не факт что вообще concurrency тут неоходимо, вполне возможно last wins и все.

J>Давай все-таки рассматривать ситуацию когда "last wins" недостаточно.
Давайте.

J>>>Update() в LINQ тоже с блокировками выполняется и в одной транзакции. Странно, зачем там optimistic concurency?

G>>Update() выполняется, а чтение+Update — нет, для этого и городится.
J>Выполняй чтение в одной транзакции с SubmitChanges(), в чем проблема?
Проблема в двух round-trip, когда достаточно одного.

G>>При этом во многих случаях где optimistic concurency действительно нужно возможностей контекста не хватает.

J>Каких, например?
Если правильность операции зависит не только от изменяемого объекта. Где-то в этой ветке уже приводили пример.
Re[16]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.03.09 18:21
Оценка:
Здравствуйте, Jakobz, Вы писали:

G>>Тот который укажем.


J>Ну ок, можно и так. Но мне кажется что приятно быть увереным что внутри контекста может быть только один объект для одного ID. А ну как не тот укажешь или что еще страшное случится?


Не. Приятно когда контекста нет вообще и о нем не болит голова. Хотим — запишем данные в БД, хотим пошлем их на фиг. Хотим — изменим сразу много записей в БД.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Некоторые мысли о LINQ
От: IT Россия linq2db.com
Дата: 25.03.09 19:10
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>А что ты понимаешь под базвордом "statefull-архитектура"?


Архитектуры построенные на хранении состояния.

J>Почему дизайн с person1 == person2 — не нормален?


Потому что в stateless системе я представить не могу где это может понадобиться. А если понадобится, то написать person1.ID == person2.ID я не переломлюсь. Так даже понятней будет.
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 19:13
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Хорошая логика. Типа "нет человека — нет проблем" Не будет датаконтекстов — не будет и удобств, которые они дают.



J>Я имел ввиду identity объектов:

J>1. select * from Persons where person_id = 1
J>2. юзер выбирает список персон
J>3. select * from Persons
J>Первая персона у нас теперь в виде объектов в двух экземплярах — из первого и второго запроса.
J>Не запутаешься с этим? Ничего что "==" для объектов нельзя будет использовать? Или будет собственный велик?
Отличный пример. Он показывает порочность использования "маппинга", как преобразования, меняющего идентичность.
Обрати внимание, что если ты не будешь выполнять маппинг, подобной проблемы просто не возникнет.
Попробуй выполнить эти два запроса в рамках SQL консоли. У тебя просто не будет ничего такого, что можно было бы сравнить "друг с другом".
Вот другой пример:
select Name from person where id = 1
update Person set Name = "Vasya" where id=1

Всё, у тебя нет никакого способа получить для id=1 не-васю, каким бы способом ты его не поселектил. Потому, что не существует никакой отдельной копии строки с id=1, которую можно было бы поменять. Ты всегда модифицируешь оригинал.
А для разведения конфликтов изменений, произведенных в разных соединениях, работает могучая транзакционность.

J>Откуда их станет меньше? Почему я не могу успешно управлять ими в LINQ to SQL?

Из-за отсутсивия "копий", которые могут быть изменены независимо.

J>Проблема в том, что эта проблема в очередной раз будет решаться руками или велосипедами.

Этой проблемы не будет вообще.
J>Не, я вообще не привык к комфорту. На проекте, на котором я уже пару лет занят — вообще датасеты и все руками. Но у нас специфика такая, что в основном с базой только на чтение работа идет.
Датасеты — это ухудшенный вариант OR-мапперов.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 19:17
Оценка:
Здравствуйте, IT, Вы писали:

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


J>>А что ты понимаешь под базвордом "statefull-архитектура"?


IT>Архитектуры построенные на хранении состояния.


J>>Почему дизайн с person1 == person2 — не нормален?


IT>Потому что в stateless системе я представить не могу где это может понадобиться. А если понадобится, то написать person1.ID == person2.ID я не переломлюсь. Так даже понятней будет.


Ну вот, здравствуйте! На RSDN все флеймы заканчиваются Хаскелем?
Напомнаю — мы говорим о технологии LINQ для императивного C#, призванного упростить работу с большим куском стейта — СУБД
Re[14]: Некоторые мысли о LINQ
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 25.03.09 19:21
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Ну вот, здравствуйте! На RSDN все флеймы заканчиваются Хаскелем?


При чем тут Хаскел?

J>Напомнаю — мы говорим о технологии LINQ для императивного C#


1) C# не только императивный
2) LINQ уж точно не императивная штука, а очень даже функциональная.
... << RSDN@Home 1.2.0 alpha 4 rev. 1138 on Windows Vista 6.1.7000.0>>
AVK Blog
Re[14]: Некоторые мысли о LINQ
От: IT Россия linq2db.com
Дата: 25.03.09 19:31
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Ну вот, здравствуйте! На RSDN все флеймы заканчиваются Хаскелем?


Шутку юмора не понял, ну да ладно.

J>Напомнаю — мы говорим о технологии LINQ для императивного C#, призванного упростить работу с большим куском стейта — СУБД


Это не просто кусок стейта, это и есть весь и только стейт. Ты же хочешь этот стейт хранить не только в БД, но и размазать его по серверам и клиентам. А потом долго и упорно его трекать.
Если нам не помогут, то мы тоже никого не пощадим.
Re[15]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 20:21
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Фишка в том, что датасеты и прочие механизмы прочитать-изменить-записать посвящены именно проблеме прямого управления данными.

S>Для управления в стиле действий, которые как раз хорошо ложатся на update, insert, delete, приходится изобретать многочисленные приседания.
S>Особенно забавно то, что для простых транзакций, с изменением одиночных объектов, identity tracking и change tracking не очень-то нужны — ты и так знаешь, какой именно объект ты пытаешься изменить. Эти механизмы становятся критически нужны в тех случаях, когда ты согласованно изменяешь набор "объектов", причем такой набор, который заранее плохо определен.

S>Так вот юмор как раз в том, что это именно та ситуация, для которой и создавался SQL. И "прокладка", которая сначала хорошо помогала реализовывать чужеродный для СУБД сценарий "сохранения объекта", теперь начинает мешать — и к ней нужна еще одна прокладка в виде кэша, а к нему точные change трекеры и прочие костыли.


S>Поэтому идеальная модель работы с данными должна давать оба способа — как "сохранение", которое пригодно для простых случаев прямого ввода, так и "действие", которое будет точно описывать трансформации с данными.


Да понимаю я это всё, понимаю.
Просто ты упускаешь следующие моменты:
— сложные сценарии обработки данных сложно писать на SQL. Если бы это было не так — писали бы всю логику на хранимках и не парились бы. И вот, чтобы обработать эти данные в C#, можно их таки вынуть, преобразовать в формат, понятный C#, обработать их, преобразовать обратно и положить. Да, не обязательно это делать. Можно работать напрямую на SQL, можно реализовывать какой-то реляционный DSL прямо в языке, и т.п. Но вот Linq to Sql, про который речь, это все-таки подход с преобразованием в объекты. Т.е. это ORM, со всеми его минусами и плюсами.
— усложним твой пример с банкоматом. Пусть он показывает текуший счет. И мы считаем, что человек принимает решение о переводе денег, основываясь на текущем счете: из 20штук занять другу 5 — одно, из 6 занять 5 — другое, самому кушать нужно. И мы тут же приходим обратно к обработке оптимистической конкуренции в той или иной форме. Не смотря на то, что "перевод денег" остается таким же атомарным действием. Пример можно сколь угодно усложнять. Главное тут то, что что-то из внешней среды принимает решение за конечное время, основываясь на потенциально устаревшей информации. Т.е. дело не в "концепции сохранения", проблема эта будет существовать при абсолютно любых условиях.
Re[13]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 20:44
Оценка:
Здравствуйте, gandjustas, Вы писали:

J>>Тут одна вешь, которую ты упускаешь, уходя всё дальше от темы: в большинстве случаев "отсоединение" сущностей просто необходимо.

G>Там где необходимо "отсоединение" там контексты Linq2SQL, EF, сессии NHibernate тоже не справляются и надо "отсоедиенный" набор данных поддерживать руками.
Вполне справляются. Автоматически они это не делают, но лучше уж так, чем никак.

Еще раз:
— identity tracking. Позволяет имитировать отсутствие identity у объектов внутри контекста. Позволяет дозапрашивать данные и не думать о том, что у нас могут появиться два разных объекта с одним и тем же.
— change tracking. Позволяет не писать на каждый чих db.НеЗабудьПроапдейтитьПотом(myObject).

Оба два — для удобства.
Оба — не обязательно юзать, они отключаются
Re[13]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 21:07
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Я тебя понимаю — я еще в долинковские времена наприседался с ORM, и самописанными в том числе, и все их прелести прекрасно осознаю. Linq — это шаг в правильную сторону, вот только надо бы шагнуть и второй ногой тоже. А то между ними как раз зависла суровая действительность, где вся мощь функциональной декомпозиции притянута вниз гирей two-way binding.


Я тоже понимаю о чем вы говорите. Но это всё очень далеко от практики.
Хорошие подходы: тащить код к данным, а не наоборот, писать на языке, удобным для работы со структурой данных, и т.п. Но они все как-то не совмещаются ни с SQL, ни с C#. Не сможешь ты прозрачно отобразить сколько-то сложный C#-код или какой-то DSL на нем, в полноценный SQL прямо на сервере. А если и сможешь — умрешь разбираться с проблемами производительности и блокировками.
Поэтому модель "оцепил что нужно — обработал — положил назад" — очень даже жизнеспособна. Хотя, конечно, эта вся гетерогенность в виде совершенно разных SQL и C#-или-что-еще-там местами напрягает, да.
Re[17]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 21:47
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Вот смотри, я делаю движение номер 1:

S>
S>var q = from Customers c select c;
S>

S>Пока ничего интересного не произошло. Но это как раз очень важно: эта строчка пока не означает, что мы "вытащили все данные миллионов кастомеров в C# и преобразовали их в формат, понятный C#"
S>Теперь я делаю движение номер 2:
S>
S>if (minRegistrationDate.HasValue)
S>  q = from q c where c.RegistrationDate >= RegistrationDate.Value
S>      select c;
S>

S>Потом я делаю движения номер 3, 4, 5, и так до 18ти.
S>На 19м я делаю return q.

Да это все понятно. Но опять же опустимся с небес на землю. Вот есть какая-то сложная операция, не влезающая в SQL. Например — поиск хорошего ресторана, до которого по трассе от заданой точки не дальше 5 км. Такой запрос не ляжет на LINQ. Мы можем заюзать его для извлечения минимума нужных данных, например можно вынуть все перекрестки и рестораны в квадрате 10x10 км — этого нам должно хватить. И потом — уточнить это все дело уже в коде. Там нам не нужно будет плясять с бубнами, заставляя SQL-сервер решать эту задачу, заодно и снимем с него вычислительную нагрузку.

Я хочу показать, что на простых примерах — да, select в LINQ решает простые проблемы от корки до корки и это клёво. А чуть дальше — и всё, приехали. И это — только запросы. Сценарии обработки информации могут быть намного сложнее.

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


Да понятно что размазывание состояния не бывает бесплатным. Речь о том, что без него далеко не всегда можно обойтись. А порой оно, создавая, конечно, свои проблемы, решает другие: масштабирируемость например может увеличить.

Кстати про аналогию между оптимистической и пессимистической блокировкой. Есть таки принципиальная разница. Например Вася и Дима открыли форму редактирования чего-то там. В пессимистическом варианте мы заблокируем полученые данные до того, как они оба эту форму не закроют. В оптимистическом — мы не дадим потом им сохранить изменения. Но далеко не факт, что они захотят что-то сохранять.
Re[15]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 21:48
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Я бы сказал что identity\change tracking — необходимые фичи современного ORM (хотя также необходима возможность их отключения для некоторых сценариев).

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

Видимо мы таки пришли к пониманию
Re[18]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.09 22:04
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Да это все понятно. Но опять же опустимся с небес на землю. Вот есть какая-то сложная операция, не влезающая в SQL. Например — поиск хорошего ресторана, до которого по трассе от заданой точки не дальше 5 км. Такой запрос не ляжет на LINQ. Мы можем заюзать его для извлечения минимума нужных данных, например можно вынуть все перекрестки и рестораны в квадрате 10x10 км — этого нам должно хватить. И потом — уточнить это все дело уже в коде. Там нам не нужно будет плясять с бубнами, заставляя SQL-сервер решать эту задачу, заодно и снимем с него вычислительную нагрузку.

Такой запрос написать можно (в MS SQL 2008), и я уверен что работать оно будет побыстрее, чем наколеночная реализация в клиетском коде.

J>Я хочу показать, что на простых примерах — да, select в LINQ решает простые проблемы от корки до корки и это клёво. А чуть дальше — и всё, приехали. И это — только запросы. Сценарии обработки информации могут быть намного сложнее.

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

Именно Linq позволяет с простотой использования стаически типизированного языка собирать sql запросы.

J>Да понятно что размазывание состояния не бывает бесплатным. Речь о том, что без него далеко не всегда можно обойтись. А порой оно, создавая, конечно, свои проблемы, решает другие: масштабирируемость например может увеличить.

Да ну?
stateless улучшает масштабируемость, но никак не размазанность состояния.

J>Кстати про аналогию между оптимистической и пессимистической блокировкой. Есть таки принципиальная разница. Например Вася и Дима открыли форму редактирования чего-то там. В пессимистическом варианте мы заблокируем полученые данные до того, как они оба эту форму не закроют. В оптимистическом — мы не дадим потом им сохранить изменения. Но далеко не факт, что они захотят что-то сохранять.

Левая аналогия. Работа БД — не открытие форм пользователем.
Даже если рассматривать пользователей, то оба могут открыть форму на чтение, но пока один правит (считаем что данные общие), другой не может увидеть ни актуальные данные, ни поменять что-то сам.
Re[15]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 22:07
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Я не понимаю — неужели Linq2Sql недостаточно убедительно демонстрирует отображение C# в полноценный SQL с блэкджеком и шлюхами?

S>Никакого сомнения нет в том, что всё это возможно (с некоторыми нюансами).

Linq2Sql демонстрирует отображение Linq в SQL, а не C# в SQL. Нет никаких сомнений что можно также завернуть и update-ы. Сомнения есть в том, что так можно завернуть решение диф. уравнений или поиск пути на графе. Так или иначе для решения сложных задач тебе придется вытаскивать данные на уровень приложения.

S>Всё как раз наоборот: проблемы производительности и блокировок — вторая натура "отсоединенной модели".


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

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


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

S>Лично меня напрягает только отсутствие полного контроля над событиями. В этом смысле EF всё-таки меньшее зло по сравнению с full blown ORM, но всё-таки дает некоторую излишнюю изоляцию от того, что происходит.


Ну это так везде. Чем выше абстракция — тем больнее с нее падать
Re[18]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 22:08
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Да это все понятно. Но опять же опустимся с небес на землю. Вот есть какая-то сложная операция, не влезающая в SQL. Например — поиск хорошего ресторана, до которого по трассе от заданой точки не дальше 5 км. Такой запрос не ляжет на LINQ.

Почему?

J>Мы можем заюзать его для извлечения минимума нужных данных, например можно вынуть все перекрестки и рестораны в квадрате 10x10 км — этого нам должно хватить. И потом — уточнить это все дело уже в коде.

А можно в студию пример вот этого "уточнить в коде"? Чтобы я проникся невозможностью свести дело к линку? Это раз.
J> Там нам не нужно будет плясять с бубнами, заставляя SQL-сервер решать эту задачу, заодно и снимем с него вычислительную нагрузку.
И там нам точно понадобятся какие-то датаконтексты с change tracking и identity map?
Или всё-таки хватит обычных иммутабельных объектов, иногда с именованными классами?

J>Я хочу показать, что на простых примерах — да, select в LINQ решает простые проблемы от корки до корки и это клёво. А чуть дальше — и всё, приехали. И это — только запросы.

Ну так никто и не требует передавать в сервер прямо всё. Вона, вставил где надо AsEnumerable — и велкам ту Linq2Objects.
Тут давеча ray tracer на линке пробегал — а ты "рестораны... перекрёстки..."

J> Сценарии обработки информации могут быть намного сложнее.



J>Да понятно что размазывание состояния не бывает бесплатным. Речь о том, что без него далеко не всегда можно обойтись.

Таких случаев значительно меньше, чем обратных.
J>А порой оно, создавая, конечно, свои проблемы, решает другие: масштабирируемость например может увеличить.
Да ну? Пока что я видел строго обратное явление: стейтлесс системы значительно сложнее масштабировать. В большинстве тривиальных случаев обработка "отсоединенных данных" приводит тупо к тому, что сиквел сервер по-прежнему делает тот же объем работы (в конце концов, у него главное — стоимость I/O, на его фоне закормить современный CPU задачка нетривиальная), но плюс к этому еще и сервер приложений нагревает воздух. А если сервер приложений случился стейтлес, тогда начинаются еще более интересные сценарии — банальный раунд робин не пойдет, нужно делать балансировку с client affinity, а она небесплатна; или таскать разделяемый кэш, что тоже небесплатно и так далее и так веселее. В итоге вместо линейного по затратам масштабирования получаем какой-то экспоненциальный рост стоимости решения.

J>Кстати про аналогию между оптимистической и пессимистической блокировкой. Есть таки принципиальная разница. Например Вася и Дима открыли форму редактирования чего-то там. В пессимистическом варианте мы заблокируем полученые данные до того, как они оба эту форму не закроют. В оптимистическом — мы не дадим потом им сохранить изменения. Но далеко не факт, что они захотят что-то сохранять.

Я в курсе
Автор: Sinclair
Дата: 27.08.02
разницы пессимистики и оптимистики.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 22:15
Оценка:
Здравствуйте, Jakobz, Вы писали:
J>Linq2Sql демонстрирует отображение Linq в SQL, а не C# в SQL. Нет никаких сомнений что можно также завернуть и update-ы. Сомнения есть в том, что так можно завернуть решение диф. уравнений или поиск пути на графе.
И насколько часто в задачах, связанных с СУБД, нужно заворачивать решение дифуров?
С поиском пути шансов встретиться больше; но всё же мне кажется, что для него один хрен датаконтекст мало полезен.

J>Так или иначе для решения сложных задач тебе придется вытаскивать данные на уровень приложения.

Это похоже на мантру. Мне вот почему-то кажется, что скорее для "сложных" задач придется втаскивать хранимки на CLR в SQL Server.

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

То-то и оно. От того, что ты не удерживаешь объект "лок" (каждый из которых весит около 80 байт), факт наличия блокировки никуда не девается.

J>Ну они не совсем выбрасываются. Они просто проходят тяжкий путь через веб-запросы и пользовательский браузер.

Совсем-совсем. Откуда в пользовательском браузере возьмутся объекты класса Customer?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 22:18
Оценка:
Здравствуйте, gandjustas, Вы писали:

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


G>Такой запрос написать можно (в MS SQL 2008), и я уверен что работать оно будет побыстрее, чем наколеночная реализация в клиетском коде.


На SQL написать можно, если припрет ускорить. А можно ли это написать на LINQ?

J>>Я хочу показать, что на простых примерах — да, select в LINQ решает простые проблемы от корки до корки и это клёво. А чуть дальше — и всё, приехали. И это — только запросы. Сценарии обработки информации могут быть намного сложнее.

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

Brainfuck тоже полон по Тьюрингу.

G>Да ну?

G>stateless улучшает масштабируемость, но никак не размазанность состояния.

Размазанность состояния не сама по себе улучшает. Просто если мы жертвуем "атомарностью" состояния, мы получаем много всяких других плюшек.

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

Ну да. Один открыл по глупости, другой ждет.

Кстати в MsSQL есть snapshot isolation level, который про оптимистическую конкуренцию как раз. А в тех же oraсle и firebird-е вообще весь принцип на multiversion concurency control-е. Так что даже внутри БД состояние вполне себе "размазывается" для повышения параллелизма.
Re[17]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 22:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>И насколько часто в задачах, связанных с СУБД, нужно заворачивать решение дифуров?

S>С поиском пути шансов встретиться больше; но всё же мне кажется, что для него один хрен датаконтекст мало полезен.
Мы вроде как уже не про DataContext, а про то — вытаскивать ли что-то на клиента, или обходиться LINQ-to-SQL и гипотетическим Linq-to-CRUD?

J>>Так или иначе для решения сложных задач тебе придется вытаскивать данные на уровень приложения.

S>Это похоже на мантру. Мне вот почему-то кажется, что скорее для "сложных" задач придется втаскивать хранимки на CLR в SQL Server.
Например вызовы каких-нибудь сторонних веб-сервисов для получения доп. данных — тоже на SQL-сервер пойдут?
Re[19]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 25.03.09 22:40
Оценка:
Здравствуйте, Sinclair, Вы писали:

J>>Да это все понятно. Но опять же опустимся с небес на землю. Вот есть какая-то сложная операция, не влезающая в SQL. Например — поиск хорошего ресторана, до которого по трассе от заданой точки не дальше 5 км. Такой запрос не ляжет на LINQ.

S>Почему?

А ты напиши. Меня вот гложут сомнения что это будет по-человечески выглядеть. Например: таблицы crossroads (id, x, y) и roads (firstCrossRoadId, secondCrossRoadId), найти кратчайший путь от одного перекрестка до другого.

S>И там нам точно понадобятся какие-то датаконтексты с change tracking и identity map?

S>Или всё-таки хватит обычных иммутабельных объектов, иногда с именованными классами?
Я вообще не про это пример приводил, если что.

J>>Я хочу показать, что на простых примерах — да, select в LINQ решает простые проблемы от корки до корки и это клёво. А чуть дальше — и всё, приехали. И это — только запросы.

S>Ну так никто и не требует передавать в сервер прямо всё. Вона, вставил где надо AsEnumerable — и велкам ту Linq2Objects.
S>Тут давеча ray tracer на линке пробегал — а ты "рестораны... перекрёстки..."

Это уже извраты. Хочется свежей функциональщины — есть для этого специальные языки.

J>> Сценарии обработки информации могут быть намного сложнее.

S>

S>Да ну? Пока что я видел строго обратное явление: стейтлесс системы значительно сложнее масштабировать. В большинстве тривиальных случаев обработка "отсоединенных данных" приводит тупо к тому, что сиквел сервер по-прежнему делает тот же объем работы (в конце концов, у него главное — стоимость I/O, на его фоне закормить современный CPU задачка нетривиальная), но плюс к этому еще и сервер приложений нагревает воздух. А если сервер приложений случился стейтлес, тогда начинаются еще более интересные сценарии — банальный раунд робин не пойдет, нужно делать балансировку с client affinity, а она небесплатна; или таскать разделяемый кэш, что тоже небесплатно и так далее и так веселее. В итоге вместо линейного по затратам масштабирования получаем какой-то экспоненциальный рост стоимости решения.


А SQL-сервера, видимо, можно бесплатно в любом количестве расставлять с линейной масштабируемостью?
Re[20]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 23:39
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>А ты напиши. Меня вот гложут сомнения что это будет по-человечески выглядеть. Например: таблицы crossroads (id, x, y) и roads (firstCrossRoadId, secondCrossRoadId), найти кратчайший путь от одного перекрестка до другого.

Ну, как только ты приведешь код, который делает это "на C#" — так я сразу же перепишу его на linq

J>Я вообще не про это пример приводил, если что.

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

Видишь, как длинно? Сейчас ты мне пытаешься обосновать последний (то есть первый) шаг в этой цепочке: нужду тащить данные в C#. Ну, так я не против — только примеры, которые ты приводишь недостаточно убедительны для дальнейших шагов. То есть ок, вот мы взяли запрос, отмапили его в некоторые объекты анонимного класса, и навернули над ними некоторую строго императивную обработку. Для всего этого Linq прекрасно подходит.

Но вот что дальше — вот это вопрос. Тебе сейчас кажется, что и изменения тебе будет удобнее вносить прямо в объекты. А мне вот кажется, что удобнее будет по частям строить "запрос на модификацию" — пусть построение этого запроса будет головоломно сложным, зато потом на сервер он уедет единым батчем.

J>Это уже извраты. Хочется свежей функциональщины — есть для этого специальные языки.

Это не извраты. Это всего лишь привычка выполнять декомпозицию задачи определенным способом. Вон, глянь в блоге Липперта как он решает задачку из игры Эрудит — найти все 8-буквенные слова из словаря, которые можно построить из заданных 6ти букв. Спорим, что твоя первая идея алгоритма не будет выражена в линке

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

Ну, пока что ты не продемонстрировал никаких способов снижения нагрузки на SQL Server. Поэтому именно он по-прежнему остается лимитирующим фактором в отсоединенной модели; а сервера приложений только воздух греют.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.09 23:39
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Мы вроде как уже не про DataContext, а про то — вытаскивать ли что-то на клиента, или обходиться LINQ-to-SQL и гипотетическим Linq-to-CRUD?

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


S>>Это похоже на мантру. Мне вот почему-то кажется, что скорее для "сложных" задач придется втаскивать хранимки на CLR в SQL Server.

J>Например вызовы каких-нибудь сторонних веб-сервисов для получения доп. данных — тоже на SQL-сервер пойдут?
А они тут при чем? Сбегал в сервисы — подготовил батч — отправил батч.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[20]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.03.09 08:46
Оценка:
Здравствуйте, Jakobz, Вы писали:

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


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


G>>Такой запрос написать можно (в MS SQL 2008), и я уверен что работать оно будет побыстрее, чем наколеночная реализация в клиетском коде.


J>На SQL написать можно, если припрет ускорить. А можно ли это написать на LINQ?

Ускорить как? Хинтами — нет, вряд ли в Linq будут database-specific средства. Вынести в процедуру — спокойно, иногда даже без изменений клиентского кода.
Ускорение работы обычно строится на правильной расстановке индексов и построении условий чтобы индексы работали, а также нужна правильная проекция.

Я на Linq писал такие запросы, которые сам бы никогда ручками в SQL не написал.

J>>>Я хочу показать, что на простых примерах — да, select в LINQ решает простые проблемы от корки до корки и это клёво. А чуть дальше — и всё, приехали. И это — только запросы. Сценарии обработки информации могут быть намного сложнее.

G>>Нынешний SQL вроде как полн по тьюрингу, значит на нем все написать можно.
G>>Другое дело что средств языка SQL для борьбы со сложностью не хватает.
J>Brainfuck тоже полон по Тьюрингу.
И на нем тоже можно сделать все. Только не пишут именно по причине слабости языка. Вот c SQL такая же история.

G>>Да ну?

G>>stateless улучшает масштабируемость, но никак не размазанность состояния.
J>Размазанность состояния не сама по себе улучшает. Просто если мы жертвуем "атомарностью" состояния, мы получаем много всяких других плюшек.
Как раз жертва атомарностью — помещение состояния еще куда-то кроме БД.

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

J>Ну да. Один открыл по глупости, другой ждет.
У меня был случай когда я банально не мог сделать коммит в SVN в течение часа. Пытаюсь закоммитить, мне говорит что надо поапдейтиться, апдейчусь, собираю проект, пытаюсь закоммитить, а кто-то уже успел до меня... и по-кругу.
Оптимистичная блокировка помогает только при слабой нагрузке и большом времени удержания.
Когда работаем с данными, обрабатывая один HTTP запрос к примеру, то оптимистичная блокировка нафиг не нужна, лучше использовать пессимистичную блокировку в БД.

J>Кстати в MsSQL есть snapshot isolation level, который про оптимистическую конкуренцию как раз. А в тех же oraсle и firebird-е вообще весь принцип на multiversion concurency control-е. Так что даже внутри БД состояние вполне себе "размазывается" для повышения параллелизма.

Пробовали snapshot пускать под высокой нагрузкой? Поддержание снапшота дороже чем блокировок, при этом все проблемы перекладываются на клинтов СУБД.
Re[12]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 09:00
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Да, если у тебя есть детерменированная операция, db = f(db) — ты можешь ее записать в одной транзакции, и это будет правильно. Тебе ничего не нужно "отсоединять", мэппить в объекты, select-ить из базы чтобы сделать update и заниматься прочей чепухой.


Именно. И именно этого нет в linq. Зато в linq есть DataContext который противоречит подходу предполагающему использовать DML-запросы.

J>И вот именно эти задачи решает Linq to sql. Замечу — это не какой-то волшебный инструмент, который принес реляционную алгебру в ООП (как мне показалось именно этого хотел от него VladD2).


Где я такое говорил?

J>Еще в Linq to sql есть DataContext, с которого начался спор. Эта штука частично решает/упрощает некоторые задачи и, в общем, могла бы "быть попроще". Но, на мой взгляд, сильного оверхеда она не приносит, а удобства у нее есть. Например, она сглаживает проблему с identity. И сама запоминает какие объекты менялись, чтобы потом нам не вспоминать что апдейтить. Я не вижу в этих удобствах ничего плохого. В любом случае от этих удобств никто не запрещает отказываться — на то ReadOnly и прочии фичи.


Ёлы, палы. Ну, сколько можно объяснять? DataContext и технология кэширования которая за ним стоит — это тупиковый подход. Он мешает использованию DML-подхода.

DML-подход не мешает написанию простенького фрэймворка который бы позволял бы сохранять изменения данных производимые путем изменения свойств объектов хранящих эти данных. Для этого всего лишь нужно сгенерировать код аналогичный тому что генерирует linq-овский генератор кода. Но сама запись должна осуществляться без кэширования и в рамках текущей транзакции (явной или не явной созданной по средствам менеджера распределенных транзакций — это не важно).

Тогда мы сможет написать код вроде:
var query = from c in customers where c.ID = 123 select c;
var customer = query.First();

customer.Name = "New name";
customer.Phones.Add("(495) 123-45-67");

using (var tran = BD.BeginTran())
  tran.SaveObjects(customer);
// или как-то так:
// BD.SaveInNewTran(customer)

То есть очень похоже на то что происходит с DataContext.
Но при этом на не нужно отслеживать идентичность объектов, производить кэширование изменений (а значит и синхронизацию кэша) и т.п.
Все что нам нужно — это иметь объект который хранит идентификатор записи в БД, исходные данные изменяемые в через объект и изменения. Этого достаточно чтобы сформировать SQL-запрос который запишет изменения в БД.

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

J>Почему я тут так подробно это расписываю? Потому что разговор ушел куда-то в полный астрал. Мы уже, вон, до Хаскеля дошли. Непонятно где Немерле только отстало


Дык это ты его уводишь. Тебе уже несколько человек обяснили, что они имеют в виду, а ты выслушиваешь их и гнешь свою линию.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 09:56
Оценка:
Здравствуйте, Jakobz, Вы писали:

G>>Там где необходимо "отсоединение" там контексты Linq2SQL, EF, сессии NHibernate тоже не справляются и надо "отсоедиенный" набор данных поддерживать руками.

J>Вполне справляются. Автоматически они это не делают, но лучше уж так, чем никак.

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

J>Еще раз:

J>- identity tracking. Позволяет имитировать отсутствие identity у объектов внутри контекста. Позволяет дозапрашивать данные и не думать о том, что у нас могут появиться два разных объекта с одним и тем же.

Задолбал. Тебе уже 100 раз повторили, что запрашивать данные и так можно. А записывать их можно и без контекста с трекингами.

J>- change tracking. Позволяет не писать на каждый чих db.НеЗабудьПроапдейтитьПотом(myObject).


А зачем такой бред писать? Если объект один, то на потом его откдадывать не надо. А если у нас массовые изменения, то у нас просто не будет объектов. Будет просто список изменений.

J>Оба два — для удобства.

J>Оба — не обязательно юзать, они отключаются

У тебя мозг уже работает только в условиях одной парадигмы. Объяснить тебе что-то невозможно, так как ты просто не хочешь воспринять наличие другой парадигмы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Некоторые мысли о LINQ
От: Aen Sidhe Россия Просто блог
Дата: 26.03.09 10:06
Оценка:
Здравствуйте, VladD2, Вы писали:

J>>- change tracking. Позволяет не писать на каждый чих db.НеЗабудьПроапдейтитьПотом(myObject).


VD>А зачем такой бред писать? Если объект один, то на потом его откдадывать не надо. А если у нас массовые изменения, то у нас просто не будет объектов. Будет просто список изменений.


А можно где-нибудь посмотреть на пример такого фреймворка? Или почитать?

J>>Оба два — для удобства.

J>>Оба — не обязательно юзать, они отключаются

VD>У тебя мозг уже работает только в условиях одной парадигмы. Объяснить тебе что-то невозможно, так как ты просто не хочешь воспринять наличие другой парадигмы.


Ну, тут есть другие люди, они читают. Я вот пока не до конца понял, как это будет работать
С уважением, Анатолий Попов.
ICQ: 995-908
Re[20]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.03.09 10:06
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>Выделенное — наверное имелось ввиду стейтфул.
Совершенно верно. Спать не реже одного раза в 24 часа — крайне полезная практика.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 10:20
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Всё как раз наоборот: проблемы производительности и блокировок — вторая натура "отсоединенной модели".


Ага. Только не "отсоединенной модели", а модели с датаконтекстами, идентити трекингами и т.п.
А "отсоединенная модель" — это датасеты которые отлично совместимы с DML-подходом.
В ней датасет — это структура данных позволяющая перетащить данные куда надо, изменить их там скопом, а потом отослать на сервер где вполне примитивным алгоритмом эти изменения превращаются в набор DML-вызовов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 26.03.09 10:27
Оценка:
Здравствуйте, VladD2, Вы писали:

G>>>Там где необходимо "отсоединение" там контексты Linq2SQL, EF, сессии NHibernate тоже не справляются и надо "отсоедиенный" набор данных VD>Задолбал. Тебе уже 100 раз повторили, что запрашивать данные и так можно. А записывать их можно и без контекста с трекингами.


Я не тебе отвечал вообще-то и тебя не задалбывал. Задаете вопрос зачем identity tracking, я отвечаю.
Записывать можно и без контекста и без трекинга. А можно — с контекстом и трекингом.

J>>- change tracking. Позволяет не писать на каждый чих db.НеЗабудьПроапдейтитьПотом(myObject).


VD>А зачем такой бред писать? Если объект один, то на потом его откдадывать не надо. А если у нас массовые изменения, то у нас просто не будет объектов. Будет просто список изменений.


J>>Оба два — для удобства.

J>>Оба — не обязательно юзать, они отключаются

VD>У тебя мозг уже работает только в условиях одной парадигмы. Объяснить тебе что-то невозможно, так как ты просто не хочешь воспринять наличие другой парадигмы.


Нет. Просто у меня мозг работает ближе к практике. Я понимаю что вы хотите. Но мне непонятны детали. Давай поговорим про конкретику:
1. как должно выглядеть в коде то, о котором вы говорите? Возьмем, например, update. Видимо там должно быть выражение, которое поставить в where и какой-то набор выражений про то, что сделать со столбцами. При чем для каждого выражения для каждого столбца должен быть доступ к контексту всей строки. Приведи хоть примерчик в псевдокоде. И как быть с update из другого select-а?
2. очевидно что программу из одних select-ов и update-ов не напишешь. Между ними данные должны попадать в код и как-то обрабатываться. Например у нас есть три колонки a, b и c. Нам нужно сделать какие-то вычисления и положить результат в колонки d и e. Предположим что для этого задействуется большое количество C#-кода. И что переписать это в форме запроса в базу нельзя — например d и e запрашиваются у стороннего веб-сервиса.
Как это все будет выглядеть? Отдельно будут объекты с полями a, b и c, полученые из базы и отдельно — объекты с d и e для сохранения, так? Анонимные типы нельзя передавать между методами, поэтому про них забываем. Получается что для каждой нужной комбинации полей строки придется создавать свой объект?
3. как быть, если в update что-то сложнее, чем встроеные в sql функции? Что должен сделать LINQ, если он не может выполнить на БД какой-нибудь гиперболический косинус? Тащить все в код, там перефигачивать и заливать назад?
Re[16]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 10:37
Оценка:
Здравствуйте, Jakobz, Вы писали:

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


S>>Я не понимаю — неужели Linq2Sql недостаточно убедительно демонстрирует отображение C# в полноценный SQL с блэкджеком и шлюхами?

S>>Никакого сомнения нет в том, что всё это возможно (с некоторыми нюансами).

J>Linq2Sql демонстрирует отображение Linq в SQL, а не C# в SQL.


Linq даже переводится как "запросы интегрированные в язык". Linq — это теперь часть C# и Жлабэйскика.
Так что начинай свыкаться с этой мыслью.

J>Нет никаких сомнений что можно также завернуть и update-ы.


Вообще-то есть. Linq — это встроенный ДСЛ. В Шарпе и Васике нет средств встаивания ДСЛ-ей пользователями.
Просто мощности этих языков недостаточно чтобы встроить поддержку таких ДСЛ-ей универсальными средствами. Но есть Хаскель и Немерле которые это сделать позволяют.
Так что сначала мы увидим поддержку в этих языках, и в виде ДСЛ-я основанного на ФВП (т.е. без поддержки синтаксиса) в Шарпе и Васике. А потом такую поддержку добавят и в эти языки (если к тому времени в них не добавят макросы с помощью которых можно будет сделать это универсально).

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


У тебя каша в голове. Ты смешиваешь алгоритмы и DSL-и. Алгоритмы не требуют наличия DSL-ей. Возможно для некоторых алгоритмов задачи проще описывать в виде некоторых ДСЛ-ей, но пареллелей между алгоритмами и DSL-ями это провести не дает.

Тот же поиск пути в графе выражается функцией принимающей граф, и два его узла.

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

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


Каааша. Ужасная каша в голове. Заучил какие-то догмы и оперируешь ими.

J>Ну это так везде. Чем выше абстракция — тем больнее с нее падать


Неееааа!
Тут ты ошибашся. Просто для обработки данных в БД не нужно использовать неподходящую для этого абстракцию — полноценные объекты. Для этого лучше использовать функциональный подход адаптированный к императивной сущности БД — DML-операторы. И лучше если они будут статически типизированными как linq.

ФП как раз идеален для обработки наборов данных. Линг отлично демонстрирует, что приемы ФП позволяют стереть границу межу языком программирования и СУБД, но пока что только для чтения данных.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 26.03.09 10:48
Оценка:
Здравствуйте, VladD2, Вы писали:

J>>Linq2Sql демонстрирует отображение Linq в SQL, а не C# в SQL.


VD>Linq даже переводится как "запросы интегрированные в язык". Linq — это теперь часть C# и Жлабэйскика.

VD>Так что начинай свыкаться с этой мыслью.

Linq — это часть, подмножество C#.

VD>Каааша. Ужасная каша в голове. Заучил какие-то догмы и оперируешь ими.


А мне вот кажется что ты слишком далеко в астрал залез. Я там ниже про конкретику написал — давай там продолжим разговор.
Re[16]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.03.09 10:57
Оценка:
Здравствуйте, VladD2, Вы писали:

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


S>>Всё как раз наоборот: проблемы производительности и блокировок — вторая натура "отсоединенной модели".


VD>Ага. Только не "отсоединенной модели", а модели с датаконтекстами, идентити трекингами и т.п.

VD>А "отсоединенная модель" — это датасеты которые отлично совместимы с DML-подходом.
VD>В ней датасет — это структура данных позволяющая перетащить данные куда надо, изменить их там скопом, а потом отослать на сервер где вполне примитивным алгоритмом эти изменения превращаются в набор DML-вызовов.

Я че-то перестал понимать.
Если в датасете поменять (названия) таблицы на списки сущностей, строки на объекты, то получится тоже самое что и в контексте.
Re[20]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 11:00
Оценка:
Здравствуйте, Jakobz, Вы писали:

S>>Тут давеча ray tracer на линке пробегал — а ты "рестораны... перекрёстки..."


J>Это уже извраты. Хочется свежей функциональщины — есть для этого специальные языки.


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

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

SQL же после появления CTE стал полным по Тьюрингу без каких либо оговорок. На нем теперь черта лысого можно расчитать, не то что какие-то там пути.

Я и в до CTE-шные времена одним запросом считал оборотную ведомость по предприятию.

Так что мощи SQL более чем достаточно для любых применений. Но нужно уметь писать функционально.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Некоторые мысли о LINQ
От: Undying Россия  
Дата: 26.03.09 11:00
Оценка:
Здравствуйте, Jakobz, Вы писали:

J> Почему дизайн с person1 == person2 — не нормален?


Потому что предполагает, что человек в любом месте программы имеет одинаковое представление. В то время как в реальности в одном месте программы от человека нужно только ФИО, в другом — только адрес, в третьем — вся доступная информация о человеке, включая явки, пароли и адрес любовницы. Поэтому сравнивать представления человека не имеет смысла, нужно сравнивать идентификаторы.
Re[16]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 11:12
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

AS>А можно где-нибудь посмотреть на пример такого фреймворка? Или почитать?


Если говорить о типзированном решение встроенном в ООЯ, то таких я не видел пока. Мы как раз и говорим, что хорошо было бы линк доработать напильником до этого состояния.

А если же говорить о похожих вещах, то наверно, как не странно ближе всего к этому подходу будут сами СУБД и подход с использованием датасетов (ADO.NET) или отсоедененных рекордсетов (ADO КОМовское, не нет которое).

AS>Ну, тут есть другие люди, они читают. Я вот пока не до конца понял, как это будет работать


Ну, так в корневом сообщении темы вроде как все разъяснено. Что конкретно не ясно?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.03.09 11:13
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Нет. Просто у меня мозг работает ближе к практике. Я понимаю что вы хотите. Но мне непонятны детали. Давай поговорим про конкретику:

J>1. как должно выглядеть в коде то, о котором вы говорите? Возьмем, например, update. Видимо там должно быть выражение, которое поставить в where и какой-то набор выражений про то, что сделать со столбцами. При чем для каждого выражения для каждого столбца должен быть доступ к контексту всей строки. Приведи хоть примерчик в псевдокоде. И как быть с update из другого select-а?
Какой синтаксис пожно придумать я не знаю, но вполне можно описать методы.

Update<T>(Expression<Func<T,T>>,IQueryable<T>)
Первый параметр соотвественно описывает преобразование строк, второй — выборку для которой выполняется преобразование (фактически из нее только предложение where берется).

Insert<T>(Table<T>, IQueryable<T>)
Delete<T>(IQueryable<T>)
Это еще проще.

J>2. очевидно что программу из одних select-ов и update-ов не напишешь. Между ними данные должны попадать в код и как-то обрабатываться. Например у нас есть три колонки a, b и c. Нам нужно сделать какие-то вычисления и положить результат в колонки d и e. Предположим что для этого задействуется большое количество C#-кода. И что переписать это в форме запроса в базу нельзя — например d и e запрашиваются у стороннего веб-сервиса.

J>Как это все будет выглядеть? Отдельно будут объекты с полями a, b и c, полученые из базы и отдельно — объекты с d и e для сохранения, так? Анонимные типы нельзя передавать между методами, поэтому про них забываем. Получается что для каждой нужной комбинации полей строки придется создавать свой объект?
Такое никак не решается, надо явно городить транзакцию.
Но гораздо лучше поменять логику приложения чтобы вставка осуществлялась так, чтобы было a,b,c,d,e вместе.
Вообще говоря работа с данными с помощью только DML приводит к другому построению логики.
То есть у вас не возникнет многих проблем, о которым вы сейчас можете написать.

J>3. как быть, если в update что-то сложнее, чем встроеные в sql функции? Что должен сделать LINQ, если он не может выполнить на БД какой-нибудь гиперболический косинус? Тащить все в код, там перефигачивать и заливать назад?

Не надо тащить все в код приложения, лучше засунуть SQL CLR функции на сервер.

Вот то что я себе сейчас с трудом представляю как делать в DML: сомещение операций добавления и апдейта.
Например на форме мы добавляем, меняем или удаляем какие-то пункты списка. Потом нам все изменения надо записать в базу при нажатии кнопки "сохранить".
В таком случае мне кажется то UoW будет решать, поэтому совсем отказываться от него не стоит.
но уж точно он не будет основным способом работы с данными.
Re[17]: Некоторые мысли о LINQ
От: Aen Sidhe Россия Просто блог
Дата: 26.03.09 11:44
Оценка:
Здравствуйте, VladD2, Вы писали:

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


AS>>А можно где-нибудь посмотреть на пример такого фреймворка? Или почитать?


VD>А если же говорить о похожих вещах, то наверно, как не странно ближе всего к этому подходу будут сами СУБД и подход с использованием датасетов (ADO.NET) или отсоедененных рекордсетов (ADO КОМовское, не нет которое).


Хм. Ну, т.е. обычные списки данных. Понятно.

AS>>Ну, тут есть другие люди, они читают. Я вот пока не до конца понял, как это будет работать


VD>Ну, так в корневом сообщении темы вроде как все разъяснено. Что конкретно не ясно?


Я имел ввиду — как работать с БД без DataContext'ов? Код, который будет заниматься сохранением данных в РСУБД будет где? И как он будет работать? Я либо туплю, либо просто не знаю, но мне на ум только ActiveRecord приходит.
С уважением, Анатолий Попов.
ICQ: 995-908
Re[19]: Некоторые мысли о LINQ
От: Aen Sidhe Россия Просто блог
Дата: 26.03.09 11:56
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Aen Sidhe, Вы писали:



AS>>Я имел ввиду — как работать с БД без DataContext'ов? Код, который будет заниматься сохранением данных в РСУБД будет где? И как он будет работать? Я либо туплю, либо просто не знаю, но мне на ум только ActiveRecord приходит.

G>Ну обычный DML работает через Connection и ниче.
G>В принципе для более сложной системы DataContext будет чуть более сложной версией коннекшена.

А, вон оно в чём дело.

G>Сейчас же объекты контекстов сочетают в себе еще и identity\change tracking, средства ленивой и отложенной загрузки, а также управление всем этим барахлом.


Меня эта ленивая загрузка, всовываемая написателями ОРМ налево и направо уже изрядно достала.

ЗЫ: спасибо за объяснение, теперь понятно.
С уважением, Анатолий Попов.
ICQ: 995-908
Re[18]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 12:16
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

AS>Я имел ввиду — как работать с БД без DataContext'ов? Код, который будет заниматься сохранением данных в РСУБД будет где? И как он будет работать? Я либо туплю, либо просто не знаю, но мне на ум только ActiveRecord приходит.


А как раньше работали? SQL-я за глаза хватает. Раньше он в язык не вписывался, а теперь вписывается...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[20]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 12:21
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

VD>>А как раньше работали? SQL-я за глаза хватает. Раньше он в язык не вписывался, а теперь вписывается...


AS>Раньше люди топорами брились. Не удобно.


В том то все и дело, что (если уж прибегать к аналогиям) топор — это датаконтексты с трекингом, так как эта идеология подразумевает обработку отдельных деревьев (объектов). А SQL — это как раз станок с ЧПУ и автоматической подачей тех самых бревен. В нем можно за раз целый лес обработать.

Потому мне никогда и не было понятно, зачем люди так даунгрэйтнулись — перешли от декларативных запросов к возней с отдельными объектами.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[21]: Некоторые мысли о LINQ
От: Aen Sidhe Россия Просто блог
Дата: 26.03.09 12:26
Оценка:
Здравствуйте, VladD2, Вы писали:

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


VD>>>А как раньше работали? SQL-я за глаза хватает. Раньше он в язык не вписывался, а теперь вписывается...


AS>>Раньше люди топорами брились. Не удобно.


VD>В том то все и дело, что (если уж прибегать к аналогиям) топор — это датаконтексты с трекингом, так как эта идеология подразумевает обработку отдельных деревьев (объектов). А SQL — это как раз станок с ЧПУ и автоматической подачей тех самых бревен. В нем можно за раз целый лес обработать.


Зачастую мне надо сделать из одного бревна пару стульев и столешницу (работа с одной сущностью "документ"). Станок мне не нужен. В другом случае мне надо работать с лесом ("data mining") — вот тут уже можно и нужно юзать станки с ЧПУ.

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


Чистый SQL минимум в половине случаев не удобен. Я думаю, я не буду повторяться про отсутствие compile-time проверок и т.д. Основная проблема для меня лично сейчас состоит в том, что для написания простой тулзы мне надо либо возиться с SQL и по сто раз лепить CRUD-операции, либо танцевать вокруг DataContext'ов. Второй вариант пока проще.
С уважением, Анатолий Попов.
ICQ: 995-908
Re[22]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 12:44
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

AS>Зачастую мне надо сделать из одного бревна пару стульев и столешницу (работа с одной сущностью "документ"). Станок мне не нужен. В другом случае мне надо работать с лесом ("data mining") — вот тут уже можно и нужно юзать станки с ЧПУ.


Вообще-то в современном мире стулья и столы делают как раз на станках. Но эти аналогии уже как-то очень далеко ушли от темы.

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


AS>Чистый SQL минимум в половине случаев не удобен.


Это придумали люди которые его не понимали.

AS> Я думаю, я не буду повторяться про отсутствие compile-time проверок и т.д.


Дык это не проблемы SQL-я. SQL вполне себе статически типизированный язык...

AS>Основная проблема для меня лично сейчас состоит в том, что для написания простой тулзы мне надо либо возиться с SQL и по сто раз лепить CRUD-операции, либо танцевать вокруг DataContext'ов. Второй вариант пока проще.


В просто не умеете его готовить (с) реклама.
Точнее просто SQL пока что не завернут в используемый тобой язык так как нужно. Точнее линк как раз завертывает его в язык, но только на половину. И мы как раз ведем речь о том, чтобы довести начатое до конца и завернуть его полностью.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 26.03.09 13:18
Оценка:
VD>>>У тебя мозг уже работает только в условиях одной парадигмы. Объяснить тебе что-то невозможно, так как ты просто не хочешь воспринять наличие другой парадигмы.

J>>Нет.


VD>Уверяю тебя. Ты знаком хотя бы с одним функциональным языком? Чувствую, что нет.


Знаком с Haskell.

VD>Так вот попробуй изучить. Уверяю тебя, что крышу будет рвать не по детски. А меж тем ничего сложного там нет. Просто несоответствие межд тем как ты видишь мир вычислений и тем как ее представляет модель ФП.

VD>Вот та же байда и здесь.

Я не вижу прямой связи между ФП и тем, о чем мы сейчас говорим. В функциональном языке тоже можно вынуть список Customer-оа, переработать его в другой список Customer-ов и потом запихнуть update-ами в базу. И даже DataContext там может пригодиться.
Причем функция process :: Customer -> Customer никакими автомагическими путями в SQL не преобразуется, да и невозможно это в общем случае.

J>>Просто у меня мозг работает ближе к практике.


VD>В чем это заключается?


В том, что я пытаюсь идеи с "чистой" моделью работы с базой мысленно применить к тем задачам, с которыми я часто встречаюсь, и я не вижу каких-то повсеместных плюсов в этом подходе. Где-то "чистая" модель была бы к месту, особенно в простых сценариях типа "добавить запись в журнал" или что-то типа того. А где-то — подход Linq подошел бы лучше.

J>>Я понимаю что вы хотите. Но мне непонятны детали. Давай поговорим про конкретику:


VD>ОК


J>>1. как должно выглядеть в коде то, о котором вы говорите? Возьмем, например, update. Видимо там должно быть выражение, которое поставить в where и какой-то набор выражений про то, что сделать со столбцами. При чем для каждого выражения для каждого столбца должен быть доступ к контексту всей строки. Приведи хоть примерчик в псевдокоде.


VD>Если снова возникает вопрос, а как защититься от случайного переписывания данных, то это можно сделать так:

VD>
VD>var cutomer1 = ...;
VD>var oldName = cutomer1.SelectedData_Name; // данные когда-то полученные с сервера для свойства Name
VD>update set c.Name = "Новое имя" set c.Bonus = c.Bonus + 1; 
VD>   from c in customers 
VD>   where c is cutomer1
VD>     and c.Name == oldName; // старое 
VD>


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

J>>Как это все будет выглядеть? Отдельно будут объекты с полями a, b и c, полученые из базы и отдельно — объекты с d и e для сохранения, так?


VD>Да. Первым запросом мы выберем нужные данные "from x in xs select a, b, c...". Затем обработаем их и запишем назад с помощью update.


Т.е. будет класс A{a,b,c} и класс B{d, e}. Может быть это и правильно концептуально, но не жирновато ли? А если потом еще C{b,c,d,e} и F{a,d,e} потребуются?

J>>Анонимные типы нельзя передавать между методами, поэтому про них забываем. Получается что для каждой нужной комбинации полей строки придется создавать свой объект?


VD>Если надо обработать только b и d, то и передай своей функции их. Ты же сам сказал, что обработка возможна только в потребительском коде.


Если их два, то может и ок. Но даже два параметра таскать между функциями — геморно.
Я бы лучше воспользовался отмэпленым объектом. Пусть там лишние поля будут, хрен с ними.

VD>Мне проблемы анонимных типов вообще фиолетовы. Я в основном пишу на Немерле, а там есть кортежи которые проблем с передачей между функциями не имеют.


А если нужно будет еще один параметр добавить? И хорошо бы — в середину кортежа, для красоты
Re[18]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.03.09 13:32
Оценка:
Здравствуйте, Jakobz, Вы писали:


J>Я не вижу прямой связи между ФП и тем, о чем мы сейчас говорим. В функциональном языке тоже можно вынуть список Customer-оа, переработать его в другой список Customer-ов и потом запихнуть update-ами в базу. И даже DataContext там может пригодиться.

Еще раз. Пока вы не откажетесь от способа работы "вынуть, обработать, положить" ничего хорошего не выйдет.

J>Причем функция process :: Customer -> Customer никакими автомагическими путями в SQL не преобразуется, да и невозможно это в общем случае.

В общем случае не возможно, а во многих частных очень даже. В Linq ведь работает.
Re[18]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 13:35
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Знаком с Haskell.


Видимо не очень глубоко.

J>Я не вижу прямой связи между ФП и тем, о чем мы сейчас говорим.


Линк был разработан одним из создателей Хакеля и в линке были применены подходы ДСЛ-естроенпия
опробированные в хаскеле.

J>В функциональном языке тоже можно вынуть список Customer-оа, переработать его в другой список Customer-ов и потом запихнуть update-ами в базу. И даже DataContext там может пригодиться.


Так и делали в HaskellDB. Только DataContext там не было.

J>Причем функция process :: Customer -> Customer никакими автомагическими путями в SQL не преобразуется, да и невозможно это в общем случае.


Гы-гы. Ошибаешься.
Курим http://haskelldb.sourceforge.net/

J>>>Просто у меня мозг работает ближе к практике.


VD>>В чем это заключается?


J>В том, что я пытаюсь идеи с "чистой" моделью работы с базой мысленно применить к тем задачам, с которыми я часто встречаюсь, и я не вижу каких-то повсеместных плюсов в этом подходе. Где-то "чистая" модель была бы к месту, особенно в простых сценариях типа "добавить запись в журнал" или что-то типа того. А где-то — подход Linq подошел бы лучше.


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

J>Ну ок. Такое было бы иногда полезно. Чаще всего было бы полезно в плане проапдейтить часть полей в строке.


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

А вот идентити трекинг как раз противоречит этому подходу.

VD>>Да. Первым запросом мы выберем нужные данные "from x in xs select a, b, c...". Затем обработаем их и запишем назад с помощью update.


J>Т.е. будет класс A{a,b,c} и класс B{d, e}. Может быть это и правильно концептуально, но не жирновато ли? А если потом еще C{b,c,d,e} и F{a,d,e} потребуются?


Не обязательно класс. Это могут быть и отдельные объекты (или примитивные данные).
Но еще раз повторюсь, я бы предпочел добавить функцию в СУБД.

VD>>Если надо обработать только b и d, то и передай своей функции их. Ты же сам сказал, что обработка возможна только в потребительском коде.


J>Если их два, то может и ок. Но даже два параметра таскать между функциями — геморно.

J>Я бы лучше воспользовался отмэпленым объектом. Пусть там лишние поля будут, хрен с ними.

Ну, будет гемерно заведешь объект под эти цели. В конце концов это уже проблема не linq-dml, а C#-а. Не находишь?

VD>>Мне проблемы анонимных типов вообще фиолетовы. Я в основном пишу на Немерле, а там есть кортежи которые проблем с передачей между функциями не имеют.


J>А если нужно будет еще один параметр добавить? И хорошо бы — в середину кортежа, для красоты


А кортежам по фигу. Они и вложенными могут быть, и расширять их очень легко, и описать их тип не проблема (перечисляешь через * другие типы и все, например "int * strong * Customer").
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[19]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 26.03.09 14:38
Оценка:
Здравствуйте, VladD2, Вы писали:

J>>Причем функция process :: Customer -> Customer никакими автомагическими путями в SQL не преобразуется, да и невозможно это в общем случае.


VD>Гы-гы. Ошибаешься.

VD>Курим http://haskelldb.sourceforge.net/

restr =
withDB $ \db ->
do rows <- query db $
do result <- table P.farmers
restrict (result!P.farm_id .==. constant 0)
return result
mapM_ (putStrLn .showP) rows

и где тут автомагические преобразования? Строят как и в Linq модель выражения и по ней лепят Sql. Никакой магии.


VD>Ну, вот видишь?

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

Можно, я и не спорил. Я просто говорил что это может быть удобнее.
Re[20]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.03.09 15:40
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>и где тут автомагические преобразования? Строят как и в Linq модель выражения и по ней лепят Sql. Никакой магии.


А ты хотел чуда?
Это наука, а не оккультные науки.
Это и есть прототип линка. Только Хаскелю не потребовалось вводить в язык новые сущности, чтобы можно было эту поддержку реализовать.

VD>>Ну, вот видишь?

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

J>Можно, я и не спорил. Я просто говорил что это может быть удобнее.


Что?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Некоторые мысли о LINQ
От: Sergey T. Украина http://overstore.codeplex.com
Дата: 27.03.09 15:49
Оценка:
Здравствуйте, Tissot, Вы писали:

T> ...

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

Итак, основной спор помниться был о массовых апдейтах, и почему в ЛИНК нет синтаксиса для "массовых апдейтов", и почему скрипт транзакции лучше, чем UoW.

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

Никакая база данных и никакой линк не сможет сформировать текст апдейт запроса так, чтобы база данных подхватила изменения локальных объектов. А это значит, что Апдейт в ЛИНКЕ
мог бы выглядеть в нескольких вариантах:
а) Типизированное выражение
update c in collection set new { Id = c.Id, Name = c.ItemName} where c.Id == 12

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

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

б) Типизированное выражение, которое не работает с экземплярами объектов, что-то типа
void Update<T>(Expression<Func<T, T>> changes, Expression<Predicate<T>> where)

Однако, проблема с невалидностью контекста после этого таки остается.

Далее, отказавшись от Unit of Work в линке мы для сохранения объектов вынуждены использовать такой же кастрированный апдейт. Причем, сохранять каждый объект отдельно и в цикле, сами отслеживая его изменения. Чем не единица работы своими руками?

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

А ежели надо скрипт транзакций — так пожалуйста, хранимые процедуры именно для этой цели и существуют.
There is no such thing as the perfect design.
Re[8]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.03.09 17:35
Оценка:
Здравствуйте, IT, Вы писали:

IT>Непонятно, если есть контекст. Если же выкинуть контекст не после операции, а вообще, то всё становится понятно и логично.


Добавлю, что тот что называется "юнит оф ворк" и так есть ни что иное как несколько изменений производимых в рамках одной транзакции.
Если потребуется реализовать паттерн записывающий изменения списка объектов, то не сложно будет сделать автоматический генератор update-запросов который сформирует эти запросы и выполнит их в рамках одной транзакции.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.03.09 17:52
Оценка:
Здравствуйте, Sergey T., Вы писали:

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


T>> ...

ST>Я сразу извиняюсь, что а) отвечаю вам, потому б) что возможно кого-то повторю, ибо до конца не дочитал, не вытерпел

ST>Итак, основной спор помниться был о массовых апдейтах, и почему в ЛИНК нет синтаксиса для "массовых апдейтов", и почему скрипт транзакции лучше, чем UoW.


ST>Я полностью согласен с поклонниками скриптов транзакций, но они забывают (забывали, по крайней мере, на первой странице) одну простую вещь: для того, чтобы скрипт транзакций отработал, все объекты из контекста нужно сохранить в базу данных.

При таком подходе у нас просто не будет объектов в контексте. Вообще не будет.

ST>Далее, отказавшись от Unit of Work в линке мы для сохранения объектов вынуждены использовать такой же кастрированный апдейт. Причем, сохранять каждый объект отдельно и в цикле, сами отслеживая его изменения. Чем не единица работы своими руками?

Отслеживание изменений — необходимость при работе с объектами. Если отказываемся от UoW то у нас и логика будет по-другом строиться.
Нам в принципе не нужны будут циклы, вся массовая обработка будет заключаться именно в выполнении запроса.

А уже на основе этой системы можно реализовать и UoW, только зачем...

ST>Насколько я понимаю, в ЛИНК отказались от массовых операций обновления именно по причине того, что часть ЛИНК которая для SQL задумывалась именно для облегчения операций массовых неалгоритмических обновлений данных. То есть грубо говоря, показав пользователю список товаров для редактирования, вы не сможете составить апдейт запрос иначе как проапдейтив каждый элемент отдельно. А это и есть единица работы.

Для чего он задумывался вообще непонятно.
Вероятнее всего Linq2SQL был всего лишь proof of concept идеи с Expression Tree. О грамотной проработке его как ORM или как средства реляцонной работы с данными никто и не задумывался. Слизали несколько наиболее востребованных фич с существующих ORM и забили.

ST>А ежели надо скрипт транзакций — так пожалуйста, хранимые процедуры именно для этой цели и существуют.

Проблема по большей части в SQL, он не проверяется при компиляции приложения, у него мало средст для динамической генерации запросов и мало средств для борьбы со сложностью.
Re[19]: Некоторые мысли о LINQ
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 28.03.09 09:02
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Линк был разработан одним из создателей Хакеля и в линке были применены подходы ДСЛ-естроенпия

VD>опробированные в хаскеле.

В Haskell eDSL строится на комбинаторах/операторах и ленивости, LINQ же — добавление новой конструкции в язык. Совершенно разные подходы.

VD>Так и делали в HaskellDB. Только DataContext там не было.


+1. В чистом языке DataContext как бы вообще не нужен.

J>>Причем функция process :: Customer -> Customer никакими автомагическими путями в SQL не преобразуется, да и невозможно это в общем случае.


VD>Гы-гы. Ошибаешься.

VD>Курим http://haskelldb.sourceforge.net/

Неправда твоя. Query строится вполне определёнными комбинаторами, Customer -> Customer действительно в SQL никак не преобразуется.

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


Мне эта идея очень нравится.
Re[20]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.03.09 19:51
Оценка:
Здравствуйте, lomeo, Вы писали:

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


VD>>Линк был разработан одним из создателей Хакеля и в линке были применены подходы ДСЛ-естроенпия

VD>>опробированные в хаскеле.

L>В Haskell eDSL строится на комбинаторах/операторах и ленивости, LINQ же — добавление новой конструкции в язык. Совершенно разные подходы.


Что ты со мной споришь? Ссылку дали. Читай.

И LINQ, и HaskellDB оба основаны на лябдах. Другое дело, что для LINQ был сделан полноценный синтаксис и сам набор примитивов расширили введя OrderBy и GroupBy.

Понятно, что в Хаскеле это было сделано имеющимися срдствами, в C# расширили язык. Ну, и что? В итоге в C# получилось лучше.

VD>>Так и делали в HaskellDB. Только DataContext там не было.


L>+1. В чистом языке DataContext как бы вообще не нужен.


Нет в природе чистых языков. Изменение данных в БД самая что ни на есть императивная операция. И пофигу где это делается в Хаскеле или Шарпе. Просто разные средства применяются. В одном случае нужна монада IO, а во втором нет.

DataContext же — это подход при котором такое изменение делается не явно, а сам DataContext средство объеденить изменения в одну транзакцию. Если бы в Хаскеле выбрали бы такой же пордход, то и аналог DataContext у них появился бы.

VD>>Гы-гы. Ошибаешься.

VD>>Курим http://haskelldb.sourceforge.net/

L>Неправда твоя. Query строится вполне определёнными комбинаторами, Customer -> Customer действительно в SQL никак не преобразуется.


Ты почитай, а потом будешь вещать. Они генерирует SQL по EDSL и выполняют его на сервере. 1 в 1 как в линк.

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


L>Мне эта идея очень нравится.


Если бы были аргументы, то можно было бы хоть что-то сказать. А так... Твои проблемы. Не нравится, так не нравится.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.03.09 19:53
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Я че-то перестал понимать.

G>Если в датасете поменять (названия) таблицы на списки сущностей, строки на объекты, то получится тоже самое что и в контексте.

Нет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.03.09 20:14
Оценка:
Здравствуйте, VladD2, Вы писали:

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


G>>Я че-то перестал понимать.

G>>Если в датасете поменять (названия) таблицы на списки сущностей, строки на объекты, то получится тоже самое что и в контексте.

VD>Нет.

Конкретнее?
Re[19]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.03.09 20:47
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Я че-то перестал понимать.

G>>>Если в датасете поменять (названия) таблицы на списки сущностей, строки на объекты, то получится тоже самое что и в контексте.

VD>>Нет.

G>Конкретнее?

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

Единственное — LINQ всегда возвращает плоский списко, а датасеты могли хранить релияционный набор данных. Но я думаю, что как раз это совершенно не обязательная возможность. В конце концов всегда можно сделать надстройку над плоскими таблицами я-ля датасет (со связями, индексами и т.п.).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[20]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.03.09 21:21
Оценка:
Здравствуйте, VladD2, Вы писали:

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


G>>>>Я че-то перестал понимать.

G>>>>Если в датасете поменять (названия) таблицы на списки сущностей, строки на объекты, то получится тоже самое что и в контексте.

VD>>>Нет.

G>>Конкретнее?

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

Эта "важная черта" как раз обеспечивается change\identity — трекингом, тем против чего вы боретесь в случае Linq. Только Linq2SQL\EF этот трекинг делают неявно, в отличие от датасетов.
В следующей версии EF будет ObjectSet, который позволит передавать данные в другую область, сейчас можно пользоваться EntityBag.
А вот когда появится DML с помощью Linq — неизвестно, может и не появится вообще.

VD>Единственное — LINQ всегда возвращает плоский списко, а датасеты могли хранить релияционный набор данных. Но я думаю, что как раз это совершенно не обязательная возможность. В конце концов всегда можно сделать надстройку над плоскими таблицами я-ля датасет (со связями, индексами и т.п.).

ИМХО если нужен отсоедиеннный набор данных с реляционными фичами, то лучше использовать локальную БД (sqlce) с любой технологией доступа к данным, и что-нибудь вроде Sync Services для синхронизации.
Re[21]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.03.09 23:08
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Эта "важная черта" как раз обеспечивается change\identity — трекингом, тем против чего вы боретесь в случае Linq. Только Linq2SQL\EF этот трекинг делают неявно, в отличие от датасетов.


Никакого identity-трекинга датасеты не обеспечивают. По определению.
Что же до change-трекинга, то с некоторой натяжкой можно назвать этим мудреным словом список изменений (diff). Но суть совершенно разная. В датасете всего лишь хранится список изменений исходных данных. Никаких синхронизаций с каким-либо локальным или глобальным кэшем при этом не происходит. Это всего лишь способ обеспечить редактрирование некоторых данных на удаленном компьютере и передачу изменений обратно на сервер.

G>В следующей версии EF будет ObjectSet, который позволит передавать данные в другую область, сейчас можно пользоваться EntityBag.


Это все очень мудрено. А главено на фиг не нужно.

G>А вот когда появится DML с помощью Linq — неизвестно, может и не появится вообще.


Мы по разному смотрим на мир. Ты как наблюдатель. Я как созидатель. Не сделает Майкрософт, сделаем мы сами. Универсальный linq-провайдер уже разрабатывает IT. Докрутим его провайдер и будет делать все что нужно. Там нет каких-то идеологических сложностей.

G>ИМХО если нужен отсоедиеннный набор данных с реляционными фичами, то лучше использовать локальную БД (sqlce) с любой технологией доступа к данным, и что-нибудь вроде Sync Services для синхронизации.


Честно говоря сомневаюсь, что такая функциональность вообще серьезно нужна. Но уж к использованию локальной БД — это точно отношения не имеет. Передать БД по сети нельзя (глупо), а датасет можно (на то он и придуман был).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[21]: Некоторые мысли о LINQ
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 31.03.09 05:26
Оценка:
Здравствуйте, VladD2, Вы писали:

L>>В Haskell eDSL строится на комбинаторах/операторах и ленивости, LINQ же — добавление новой конструкции в язык. Совершенно разные подходы.

VD>Что ты со мной споришь? Ссылку дали. Читай.

Полагаю, я всё там прочитал гораздо раньше и внимательнее тебя ;-)

VD>И LINQ, и HaskellDB оба основаны на лябдах. Другое дело, что для LINQ был сделан полноценный синтаксис и сам набор примитивов расширили введя OrderBy и GroupBy.

VD>Понятно, что в Хаскеле это было сделано имеющимися срдствами, в C# расширили язык. Ну, и что? В итоге в C# получилось лучше.

Просто в Хаскель для того же самого не надо расширять язык :-)

То, что они оба основаны на лямбдах не отменяет того простого факта, что подходы к "DSL-строению" у них разные.

VD>DataContext же — это подход при котором такое изменение делается не явно, а сам DataContext средство объеденить изменения в одну транзакцию. Если бы в Хаскеле выбрали бы такой же пордход, то и аналог DataContext у них появился бы.


Я об identity.

VD>>>Гы-гы. Ошибаешься.

VD>>>Курим http://haskelldb.sourceforge.net/
L>>Неправда твоя. Query строится вполне определёнными комбинаторами, Customer -> Customer действительно в SQL никак не преобразуется.
VD>Ты почитай, а потом будешь вещать. Они генерирует SQL по EDSL и выполняют его на сервере. 1 в 1 как в линк.

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

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


Правда.

L>>Мне эта идея очень нравится.

VD> Если бы были аргументы, то можно было бы хоть что-то сказать. А так... Твои проблемы. Не нравится, так не нравится.

Влад, ты очень, нет, очень-очень-очень невнимательно читаешь. Посмотри, пожалуйста, выделенное. Из-за этой невнимательности ты приводишь некорректные аргументы. Некорректные аргументы не могут внушать доверие к твоей идее, они даже могут работать против тебя.

С HaskellDB вообще интересная история. Давным-давно мы с тобой спорили о LINQ/Query monad. И сейчас ты сам же посылаешь меня читать про то, о чём я тогда говорил тебе. Хм.
Re[22]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 31.03.09 07:38
Оценка:
Здравствуйте, VladD2, Вы писали:

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


G>>Эта "важная черта" как раз обеспечивается change\identity — трекингом, тем против чего вы боретесь в случае Linq. Только Linq2SQL\EF этот трекинг делают неявно, в отличие от датасетов.


VD>Что же до change-трекинга, то с некоторой натяжкой можно назвать этим мудреным словом список изменений (diff). Но суть совершенно разная. В датасете всего лишь хранится список изменений исходных данных. Никаких синхронизаций с каким-либо локальным или глобальным кэшем при этом не происходит. Это всего лишь способ обеспечить редактрирование некоторых данных на удаленном компьютере и передачу изменений обратно на сервер.

Весь "кеш" находится в самом датасете, а в Linq2SQL\EF — в контексте.
Мне обе идеи не нравятся. У датасета нельзя оторвать change-tracking и работать только с данными, а в Linq2SQL\EF нельзя оторвать changetracking от контекста, чтобы можно было граф объектов передавать куда-нить и редактировать.

G>>В следующей версии EF будет ObjectSet, который позволит передавать данные в другую область, сейчас можно пользоваться EntityBag.


VD>Это все очень мудрено. А главено на фиг не нужно.

ObjectSet реализует туже идею что и Dataset только с объектами.

G>>А вот когда появится DML с помощью Linq — неизвестно, может и не появится вообще.

VD>Мы по разному смотрим на мир. Ты как наблюдатель. Я как созидатель. Не сделает Майкрософт, сделаем мы сами. Универсальный linq-провайдер уже разрабатывает IT. Докрутим его провайдер и будет делать все что нужно. Там нет каких-то идеологических сложностей.
Я сам хотел сделать что-то подобное, чтобы работало через edm. Но поковырялся в edm, понял насколько оно сырое, решил отложить затею.
Re[22]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.03.09 11:07
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Просто в Хаскель для того же самого не надо расширять язык


Это все замечание? Тогда согласен. Но Шарп же уже расширили. Немерле, например, расширять не пришлось. 3 макроса и золотой ключик у нас в кармане.

L>То, что они оба основаны на лямбдах не отменяет того простого факта, что подходы к "DSL-строению" у них разные.


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

Просто сравни сами запросы и тебе станет все очевидно. На Хаскеле sql-ем и не пахнет. Это какой-то ДСЛ который представляет запросы в виде какого-то АСТ. В Шарпе же реализовали почти SQL.

VD>>DataContext же — это подход при котором такое изменение делается не явно, а сам DataContext средство объеденить изменения в одну транзакцию. Если бы в Хаскеле выбрали бы такой же пордход, то и аналог DataContext у них появился бы.


L>Я об identity.


Что ты identity?

L>Не поверишь, я этим даже когда то пользовался — это чтобы ты меня десять раз читать не посылал. И — да, они генерируют SQL по eDSL, я с этим спорил?


Конечно спорил! Ты прочти свои предыдущие сообщения.

L>>>Мне эта идея очень нравится.

VD>> Если бы были аргументы, то можно было бы хоть что-то сказать. А так... Твои проблемы. Не нравится, так не нравится.

L>Влад, ты очень, нет, очень-очень-очень невнимательно читаешь. Посмотри, пожалуйста, выделенное. Из-за этой невнимательности ты приводишь некорректные аргументы. Некорректные аргументы не могут внушать доверие к твоей идее, они даже могут работать против тебя.


Да, есть такое. Извини.

L>С HaskellDB вообще интересная история. Давным-давно мы с тобой спорили о LINQ/Query monad. И сейчас ты сам же посылаешь меня читать про то, о чём я тогда говорил тебе. Хм.


Ну, насчет монад я бы и сейчас поспорил бы. Мне кажется хаскелистам везде монады мерещатся. Понятно, что Хаскеле монады — это единственный способ связать два вычисления в цепочку. Но в других языках есть и другие средства. Выражение "императивный аналог монад" примененное Меером меня вообще порадовало.

ЗЫ

Вообще, о чем мы спорим то? Мне показалось, что ты с чем-то не согласен.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[23]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.03.09 11:15
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Весь "кеш" находится в самом датасете, а в Linq2SQL\EF — в контексте.


Нет в датасетах кэша. Это просто данные. Главное отличие от кэша — может существовать множество несинхронизируемых копий.

G>Мне обе идеи не нравятся. У датасета нельзя оторвать change-tracking и работать только с данными,


А что мешает этому? Не используй изменения и все.

G>а в Linq2SQL\EF нельзя оторвать changetracking от контекста, чтобы можно было граф объектов передавать куда-нить и редактировать.


В том-то и проблема.

G>ObjectSet реализует туже идею что и Dataset только с объектами.


Тогда это только другое название.

G>Я сам хотел сделать что-то подобное, чтобы работало через edm. Но поковырялся в edm, понял насколько оно сырое, решил отложить затею.


Вот как раз все эти edm мы отправим в топку. Это путь в сторону Гибернэйта. А мы хотели бы получить нечто-то воде доведенного до ума linq2sql. Задачи: 1) получить независимый от СБУД провйдер, 2) реализовать DML.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[23]: Некоторые мысли о LINQ
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 31.03.09 12:48
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Конечно спорил! Ты прочти свои предыдущие сообщения.


Речь шла о Customer -> Customer, из которого ну никак ты не получишь SQL.

VD>Вообще, о чем мы спорим то? Мне показалось, что ты с чем-то не согласен.


Я не спорил, поправлял. А так я со всем согласен
Re[24]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 31.03.09 15:04
Оценка:
Здравствуйте, VladD2, Вы писали:

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


G>>Весь "кеш" находится в самом датасете, а в Linq2SQL\EF — в контексте.

VD>Нет в датасетах кэша. Это просто данные. Главное отличие от кэша — может существовать множество несинхронизируемых копий.
Это вопрос веры. Создайте несколько контекстов и у вам с будет несколько несинхронизированных "кешей".

G>>Мне обе идеи не нравятся. У датасета нельзя оторвать change-tracking и работать только с данными,

VD>А что мешает этому? Не используй изменения и все.
Тогда смысл датасета пропадает. Если не изменять данные, то проще работать с графом объектов, чем со слепком слаюотипизированных данных из БД.

G>>а в Linq2SQL\EF нельзя оторвать changetracking от контекста, чтобы можно было граф объектов передавать куда-нить и редактировать.

VD>В том-то и проблема.
угу.

G>>ObjectSet реализует туже идею что и Dataset только с объектами.

VD>Тогда это только другое название.
Не только, в ObjectSet будут объекты, а не реляционные данные.

G>>Я сам хотел сделать что-то подобное, чтобы работало через edm. Но поковырялся в edm, понял насколько оно сырое, решил отложить затею.

VD>Вот как раз все эти edm мы отправим в топку. Это путь в сторону Гибернэйта.
Почему?

VD>А мы хотели бы получить нечто-то воде доведенного до ума linq2sql. Задачи: 1) получить независимый от СБУД провйдер,

Это уже есть, провайдеры EF принимают на вход деревья выражений DbCommandTree, работающих с типами из edm.
Только edm на мой взгляд пока еще очень убого.

2) реализовать DML.
А вот этого нет.
Re[25]: Некоторые мысли о LINQ
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 31.03.09 18:03
Оценка:
Здравствуйте, gandjustas, Вы писали:

L>>Речь шла о Customer -> Customer, из которого ну никак ты не получишь SQL.

G>Да ну?

Если ты перечитаешь 3-4 поста вверх по ветке, то увидишь, что речь шла о том, что "невозможно это в общем случае". И о том, что за примером того, что это всё таки возможно, VladD2 отослал к HaskellDB. Ты отвечаешь совсем не на то. Невнимательное чтение — источник флейма.

G>Наколеночное решение за 15 минут.


Спасибо, интересно.
Re[24]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.03.09 19:19
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Речь шла о Customer -> Customer, из которого ну никак ты не получишь SQL.


Я не понимаю почему не о Customer -> string * int или еще о чем-то подобном.
Я не пойму почему из функции Customer -> Customer не получить SQL.
И я вообще не понимаю откуда появилась эта Customer -> Customer.
В общем, мая твоя не потимать.

VD>>Вообще, о чем мы спорим то? Мне показалось, что ты с чем-то не согласен.


L>Я не спорил, поправлял. А так я со всем согласен


Тем более.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[25]: Некоторые мысли о LINQ
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 01.04.09 15:24
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Я не понимаю почему не о Customer -> string * int или еще о чем-то подобном.


Ну так речь об UPDATE, насколько я понимаю.

VD>Я не пойму почему из функции Customer -> Customer не получить SQL.


Расскажи как — я знаю только дикие способы вроде сравнения конечного и начального объектов, или передачи объекта с тем же интерфейсом, что и кастомер, но который будет при изменении свойств сохранять эти изменения. У обоих решений -- куча недостатков. Ну, а то, что предложил gandjustas сломается, как только у нас появится логика (ветвление/циклы) или если мы передадим реальную функцию, а не выражение.
Re[26]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.04.09 16:05
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Расскажи как — я знаю только дикие способы вроде сравнения конечного и начального объектов, или передачи объекта с тем же интерфейсом, что и кастомер, но который будет при изменении свойств сохранять эти изменения. У обоих решений -- куча недостатков. Ну, а то, что предложил gandjustas сломается, как только у нас появится логика (ветвление/циклы) или если мы передадим реальную функцию, а не выражение.

Стоп.
Давайте сделаем наоборот, напишите такой Upddate statement (без всякой императивщины), который нельзя выразить в чистом функциональном стиле на любом языке
Вряд ли у вас получится.
Re[27]: Некоторые мысли о LINQ
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 01.04.09 18:39
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Стоп.

G>Давайте сделаем наоборот

А зачем?
Re[28]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.04.09 19:19
Оценка:
Здравствуйте, lomeo, Вы писали:

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


G>>Стоп.

G>>Давайте сделаем наоборот

L>А зачем?

Затем что цель именно в этом. Не надо выражать операции какого-либо языка в SQL, надо выразить SQL DML в некоторых конструкциях языка.
Re[27]: Некоторые мысли о LINQ
От: Lloyd Россия  
Дата: 01.04.09 19:32
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Давайте сделаем наоборот, напишите такой Upddate statement (без всякой императивщины), который нельзя выразить в чистом функциональном стиле на любом языке


С простыми update-ами как здесь
Автор: gandjustas
Дата: 31.03.09
понятно.
Но как на C# будет выглядеть, например
UPDATE Person
SET Age = DATEDIFF(y, GETDATE(), BirthInfo.birthDate)
FROM Person
JOIN BirthInfo ON BirthInfo.PersonID = Person.ID
Re[28]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.04.09 20:09
Оценка:
Здравствуйте, Lloyd, Вы писали:

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


G>>Давайте сделаем наоборот, напишите такой Upddate statement (без всякой императивщины), который нельзя выразить в чистом функциональном стиле на любом языке


L>С простыми update-ами как здесь
Автор: gandjustas
Дата: 31.03.09
понятно.

L>Но как на C# будет выглядеть, например
L>
L>UPDATE Person
L>SET Age = DATEDIFF(y, GETDATE(), BirthInfo.birthDate)
L>FROM Person
L>JOIN BirthInfo ON BirthInfo.PersonID = Person.ID
L>

Для update from можно придумать метод update c другой сигнатурой или использовать подзапросы для решения таких задач.
Re[29]: Некоторые мысли о LINQ
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 01.04.09 20:59
Оценка:
Здравствуйте, gandjustas, Вы писали:

L>>А зачем?

G>Затем что цель именно в этом. Не надо выражать операции какого-либо языка в SQL, надо выразить SQL DML в некоторых конструкциях языка.

Цель — по заданному SQL генерить конструкции языка? По моему, ровно наоборот :-)
Re[30]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 02.04.09 21:26
Оценка:
Здравствуйте, lomeo, Вы писали:

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


L>>>А зачем?

G>>Затем что цель именно в этом. Не надо выражать операции какого-либо языка в SQL, надо выразить SQL DML в некоторых конструкциях языка.

L>Цель — по заданному SQL генерить конструкции языка? По моему, ровно наоборот


Еще раз. Цель — выразить SQL DML в конструкциях языка, по научному — найти сьюрьективное отображение некоторого подмножества языка в SQL DML.
Re[31]: Некоторые мысли о LINQ
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 06.04.09 11:28
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Еще раз. Цель — выразить SQL DML в конструкциях языка, по научному — найти сьюрьективное отображение некоторого подмножества языка в SQL DML.


Зачем вообще говорить о сюрьективном отображении, если даже DML-и разные для разных БД?
Если же нам достаточно инъекции, то DML не надо выражать в конструкциях языка, а надо получать его из этих самых конструкций.
Ч.т.д.
Re[28]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.04.09 03:32
Оценка:
Здравствуйте, Lloyd, Вы писали:

А что тут такого военного? Смотри, всё, что нам нужно — это коллекция записей {Id, Age}.
Получать ее Linq уже умеет, не так ли?
Теперь осталось добавить в него update statement, куда можно скормить эту коллекцию и объяснить "для каждого Person с заданным Id установи Age в переданный Age".
Инфраструктура должна уметь отличать ситуацию, когда источник — соответствующий IQueryable, который можно вычислить на стороне сервера, от ситуации, когда это, к примеру, List<Tuple<...>>, и нужно породить батч одиночных update Person.

Это заодно даёт ответ на вопрос "что делать, если преобразование невыразимо в SQL".
Ну там, MD5 пытаемся посчитать от фамилии, или еще что. Точно так же, как сейчас, Linq будет выкидывать исключение о том, что не удалось построить SQL запрос, и программисту придется принудительно материализовать промежуточный запрос, выполнить преобразование, и отдать обратно результат (в виде батча апдейтов одиночных записей).
Целостность будет гарантироваться тем, что мы выполняем всё в рамках одной транзакции.
Это не так здорово, как выполнить всё полностью на сервере, но всё еще, имхо, лучше, чем подход с датасетами.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[29]: Некоторые мысли о LINQ
От: Lloyd Россия  
Дата: 08.04.09 06:16
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А что тут такого военного? Смотри, всё, что нам нужно — это коллекция записей {Id, Age}.

S>Получать ее Linq уже умеет, не так ли?
S>Теперь осталось добавить в него update statement, куда можно скормить эту коллекцию и объяснить "для каждого Person с заданным Id установи Age в переданный Age".

Меня интересует как может выглядеть подобный зарос в синтаксисе C#, а не принцип.
Все варианты, которые мне приходят в голову, мягко говоря не очень удобные.
Re[30]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.04.09 06:53
Оценка:
Здравствуйте, Lloyd, Вы писали:
L>Меня интересует как может выглядеть подобный зарос в синтаксисе C#, а не принцип.
В гипотетическом синтаксисе?
from .... 
... 
update ... set

L>Все варианты, которые мне приходят в голову, мягко говоря не очень удобные.
Ну, пока что шарп ухитрился остаться очень близким к оригинальному SQL. Варианты сиквела (с точностью до порядка clause) меня вполне устраивают.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[31]: Некоторые мысли о LINQ
От: Lloyd Россия  
Дата: 08.04.09 10:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

L>>Меня интересует как может выглядеть подобный зарос в синтаксисе C#, а не принцип.

S>В гипотетическом синтаксисе?
S>
S>from .... 
S>... 
S>update ... set 
S>


Нет, в синтаксисе C#

L>>Все варианты, которые мне приходят в голову, мягко говоря не очень удобные.

S>Ну, пока что шарп ухитрился остаться очень близким к оригинальному SQL. Варианты сиквела (с точностью до порядка clause) меня вполне устраивают.

LINQ оказался пожалуй даже лучше, чем SQL. Очень удобно то, что можно манипулировать самим запросом без его непосредственного исполнения, добавлять условия фильтрации, ограничивать получаемые поля и т.д.
Как такой же гибкости можно добиться и в update-ах мне не совсем понятно. В частности, было бы удобно достраивать список обновляемых в update-е полей в зависимости от каких-то условий, например, прав пользователя. Что-то типа реляционной алгебры, но не для select-а, а для update-а.
Re[8]: Некоторые мысли о LINQ
От: Sergey T. Украина http://overstore.codeplex.com
Дата: 24.04.09 11:11
Оценка:
Здравствуйте, gandjustas, Вы писали:

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


ST>>Я сразу извиняюсь, что а) отвечаю вам, потому б) что возможно кого-то повторю, ибо до конца не дочитал, не вытерпел

ST>>Итак, основной спор помниться был о массовых апдейтах, и почему в ЛИНК нет синтаксиса для "массовых апдейтов", и почему скрипт транзакции лучше, чем UoW.
ST>>Я полностью согласен с поклонниками скриптов транзакций, но они забывают (забывали, по крайней мере, на первой странице) одну простую вещь: для того, чтобы скрипт транзакций отработал, все объекты из контекста нужно сохранить в базу данных.
G>При таком подходе у нас просто не будет объектов в контексте. Вообще не будет.

ST>>Далее, отказавшись от Unit of Work в линке мы для сохранения объектов вынуждены использовать такой же кастрированный апдейт. Причем, сохранять каждый объект отдельно и в цикле, сами отслеживая его изменения. Чем не единица работы своими руками?

G>Отслеживание изменений — необходимость при работе с объектами. Если отказываемся от UoW то у нас и логика будет по-другом строиться.
G>Нам в принципе не нужны будут циклы, вся массовая обработка будет заключаться именно в выполнении запроса.

G>А уже на основе этой системы можно реализовать и UoW, только зачем...

Согласен с вами, однако в вашем посте ключевое слово "массовая". Если нет "массовой", а другими словами "однотипной" обработки множества объектов — нет апдейта, а есть апдейты.

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

Я вообще конечно двумя руками "за" "типизированные апдейты" и трансляцию кода С# в SQL. Только вот для такой большой части типовых сценариев "прочитал из базы, передал клиенту (через сервис), дал поредактировать пользователю, залил обратно (через тот же сервис), залил в базу" не получится сделать выражение (expression) апдейта. А получится — в случае, если нет контекста — CUD запросы по числу объектов. Потом оно начнет тормозить на больших объемах, потом введется признак редактирования объекта, потом IsDirty перекочует во внешний объект — и здравствуй, контекст. Но суть в том, что это будут те же яйца, только в профиль, поскольку редактирование набора объектов пользователями — это явно не однотипная обработка, и здесь типизированный апдейт никак не применишь.

С другой стороны, код на C#, который при определенных условиях выполняется средствами СУБД — это здорово.

В дополнение хочу заметить, что задача ОРМ не только "подружить данные и объекты", но еще и подружить реляционную структуру данных с иерархической структурой объектов. Имея две таблицы Order и OrderItem, и имея два класса OrderItem и class Order { public Collection<OrderItem> Items {get;} ...}, в которые в основном превращаются данные такого рода.
There is no such thing as the perfect design.
Re[9]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.04.09 11:38
Оценка:
Здравствуйте, Sergey T., Вы писали:

ST>Я вообще конечно двумя руками "за" "типизированные апдейты" и трансляцию кода С# в SQL. Только вот для такой большой части типовых сценариев "прочитал из базы, передал клиенту (через сервис), дал поредактировать пользователю, залил обратно (через тот же сервис), залил в базу" не получится сделать выражение (expression) апдейта.

Почему не получится? Я препятствий не вижу.

ST>А получится — в случае, если нет контекста — CUD запросы по числу объектов.

По числу добавленных\измененных\удаленных объектов. Клиент вполне может передавать списки удаляемых\обновляемых\вставляемых объетов.
Кроме того чаще всего пользователь работает с одим объектом или одним списком объектов.

ST>Потом оно начнет тормозить на больших объемах, потом введется признак редактирования объекта, потом IsDirty перекочует во внешний объект — и здравствуй, контекст. Но суть в том, что это будут те же яйца, только в профиль, поскольку редактирование набора объектов пользователями — это явно не однотипная обработка, и здесь типизированный апдейт никак не применишь.

В таком случае и ORMы со всеми фичами мало чего дают.

ST>В дополнение хочу заметить, что задача ОРМ не только "подружить данные и объекты", но еще и подружить реляционную структуру данных с иерархической структурой объектов. Имея две таблицы Order и OrderItem, и имея два класса OrderItem и class Order { public Collection<OrderItem> Items {get;} ...}, в которые в основном превращаются данные такого рода.

Маппинг — ортогональная задача.
Re[6]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.09 15:53
Оценка:
Здравствуйте, no4, Вы писали:

no4>А нельзя ли как-то это совместить? С одной стороны данные важны. С другой стороны, хотелось бы манипулировать более высокоуровневыми абстракциями чем Entities.


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

no4>Например, сделать объектно-ориентированный язвк, чтобы он:

no4> * был декларативныой
no4> * поддерживал транзакции

Оба пункта противоречат императивной природе ООП.

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