Здравствуйте, Tissot, Вы писали:
T>Я не меняю условия задачи.
Меняешь.
T> Вариант, когда в одной бизнес-операции выполняются несколько update-ов одной сущности считаю вполне жизненным.
Вполне. Но во-первых это совсем не означает, что будет именно одна БД транзакция, а во-вторых никто не заставляет делать между этими изменениями тяжелые вычисления.
T>Не, так легко ты не отделаешься. Учебников мною прочитано предостаточно, но информации о том, чтобы СУБД отпускала блокировки до окончания танзакции, я слышу в первый раз.
Значит фигово читал. Это умеют делать все СУБД, в зависимости от уровня изоляции, а например MSSQL умеет вообще не накладывать блокировки при выполнении стейтмента в RC — оптимизация такая.
Вообще современные СУБД довольно продвинутые конструкции и наивно было бы полагать, что ты сумеешь справиться лучше.
T>Ну идея сама по себе была ясна и из первого поста
Складывается впечатление, что не очень.. )
T>Используйте ef
Что мне это даст, кроме возни с тремя моделями, вместо одной?
T>Кэш неявный только когда ты о нем не знаешь.
Тогда, когда у меня нет над ним явного контроля.
T>Изучайте получше инструмент, которым пользуетесь.
А я и не пользуюсь.. Я пользуюсь теми инструментами, которые делают то что надо мне.
Здравствуйте, Tissot, Вы писали:
T>Да ну?
Ну да.
T> Как это они могут выть ортогональными, если вопрос по сути является вопросом о том, куда помещать бизнес-логику.
Это с чего это ты взял? Куда помещать бизнес-логику совершенно не зависит от того, используешь ты domain model или нет. И помимо domain model существует множество других подходов к архитектуре, где логика может быть как в БД, так и вне ее. Стыдно такое не знать, человеку регулярно следящему за тенденциями. =)
T>Тут уж либо он в базах/запросах, либо в domain model.
Так, ты что под domain model понимаешь?
T>А в это время другие мыши пробуют все вокруг, не подозревая даже о том, что кто-то им от души подсыпал крысиного яда. Удачи.
Что-то я не заметил, что ты все вокруг пробуешь, ты, похоже, где-то серебряную пулю откопал.. )
T>Мне не уловить ход твоих мыслей. Как из проработанности следует что это является фуфелом?
Так, что народ уже наелся этого по самые гланды и накопив опыт, и стряхнув лапшу с ушей, начинает понимать, что его накормили чем-то не тем.
T>Не, EJB был оверкилом, он как раз сильно ограничивал возможности использования ООП.
Он то, как раз, был пожалуй самым "ООП" шным, в том виде, как принято понимать ООП. Ну и наелись в результате..
T>В реальной жизни ты разбиваешь задачи на долее мелкие и дашь их разным людям и не факт, что исполнитель второй задачи будет знать, что те данные, которые он меняет, были изменены чуть выше по коду первым исполнителем.
То есть, у тебя один разработчик пишет начало транзакции, а другой ее коммитит?
T>Я правильно тебя понимаю, что ты не считаешь упомянутую мною Axapta крупным приложением? А что по твоему мнению ты относишь к числу таковых?
Я не считаю Аксапту ни крупным приложением, ни образцом правильно спроектированного приложения, и ее упоминание вообще ни как не относится к теме данного разговора, если ты сам не учавствовал именно в разработке самой Аксапты, причем в роли человека принимающего ключевые решения в архитектуре.
А-то, так я тоже могу заявить, что мы с Антоном(Sinclair) уже много лет носим гордое звание Microsoft MVP в компетенции Solution Architect, и только на этом основании давить тебя своим авторитетом и опытом. Но очевидно, что ни к какому конструктиву это не приведет.
Поэтому такого рода аргументацию я и называю дешевыми понтами.
Здравствуйте, Tissot, Вы писали:
T>По данному вопросу наши мысли совпадают
Просто у тебя свои не получается сформулировать.. Ок, понятно, но что же ты тогда спорить полез? =)
Здравствуйте, IB, Вы писали:
T>>Раз уж мы аппелируем к большинству, то это большинство какраз-таки пользуется разными Hibernate-ами вовсю. IB>Во-первых H — это не OOBD, во-вторых, H можно использовать очень по разному ну и, наконец, в третих, "большинство" — это тоже сильное преувеличение.
По поводу первых двух пунктов — согласен.
По поводу третьего — думаю, если взять общее число тех, кто знает о hibernte-е (или других мапперах) и имеет возможность его использовать, большинство его использует.
T>>Наследование. Отношения многие ко многим. IB>Это все отлично выражается в ER, стыдно не знасть.
Наследование само по себе (без наличия виртуальных методов) ценности не несет.
Многие-ко-многим выражается через два отношения один-ко-многим. С этим элементарно неудобно работать
T>>Методы. Интерфейсы. IB>А это вообще никакого отношения к данным не имеет.
Зато имеет к ООП.
T>>Большое количество однородных объектов. В качества примера можно привести например миграцию данных с одной схемы базы на другую. IB>Тогда ты фигню сказал. UoW сливает везде, где обьектов больше одного.
Здравствуйте, IB, Вы писали:
T>> Вариант, когда в одной бизнес-операции выполняются несколько update-ов одной сущности считаю вполне жизненным. IB>Вполне. Но во-первых это совсем не означает, что будет именно одна БД транзакция, а во-вторых никто не заставляет делать между этими изменениями тяжелые вычисления.
Я привел пример в другой ветке.
T>>Не, так легко ты не отделаешься. Учебников мною прочитано предостаточно, но информации о том, чтобы СУБД отпускала блокировки до окончания танзакции, я слышу в первый раз. IB>Значит фигово читал. Это умеют делать все СУБД, в зависимости от уровня изоляции, а например MSSQL умеет вообще не накладывать блокировки при выполнении стейтмента в RC — оптимизация такая.
Можно подкрепить высказывание ссылочкой? Спасибо.
IB>Вообще современные СУБД довольно продвинутые конструкции и наивно было бы полагать, что ты сумеешь справиться лучше.
Я и не собираюсь справляться лучше. ORMapper в конечном итоге говорит и сервером на SQL, а значит все средства остаются в силе.
T>>Ну идея сама по себе была ясна и из первого поста IB>Складывается впечатление, что не очень.. )
Ясна.
T>>Используйте ef IB>Что мне это даст, кроме возни с тремя моделями, вместо одной?
Отсутствие ленивой загрузки.
T>>Кэш неявный только когда ты о нем не знаешь. IB>Тогда, когда у меня нет над ним явного контроля.
Над чем у тебя нет явного контроля в том же LINQ2SQL-е. Он же тупой как пробка. Не над чем там контроль держать.
Здравствуйте, 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-кубы. В этом весь поинт и был.
Здравствуйте, IB, Вы писали:
T>>По данному вопросу наши мысли совпадают IB>Просто у тебя свои не получается сформулировать.. Ок, понятно, но что же ты тогда спорить полез? =)
Ведите себя прилично, не надо переходить на личности.
Здравствуйте, VGn, Вы писали:
T>>Зря, если бы читали, то таких выводов бы не делали.
VGn>Читал. Просто примеры вызвали более явное отторжение.
Да примеры во всех книжках такое впечатление оставляют. Если писать хороший, качественный пример, иллюстрирующий правильные подходы, то он полкнижки займет, его и читать никто не будет.
VGn>По вопросу примеров корпоративного кода это практически стандартный ответ на форуме. VGn>Да и смотреть там в общем и нечего: архитектуру по коду не понять, тем более что на уровне кода абсолютно все достаточно здоровые корпоративные системы, которые я видел, написаны через жопу (конечно я не имею в виду свой собственный код и код своей команды )
Кода не надо. Это неинтересно. Лучше какие-нибудь статьи про правильную по вашему мнению архитектуру.
T>Кода не надо. Это неинтересно. Лучше какие-нибудь статьи про правильную по вашему мнению архитектуру.
Серебряной пули нет. Архитектура хороша тогда, когда она доказано хороша для вашего проекта. Просто нужно более ответственно относиться к декомпозиции бизнес-логики по уровням ответственности и более осторожно относиться ко всяческим прокси (Не наступайте на грабли MS. Они за вас шишку уже получили.)
Здравствуйте, 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 в таком случае требуется только модифицировать запросы.
Здравствуйте, 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 поля.
Здравствуйте, 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, его элементарно может не быть.
Здравствуйте, VGn, Вы писали:
T>>>>Методы. Интерфейсы. IB>>>А это вообще никакого отношения к данным не имеет. T>>Зато имеет к ООП.
VGn>Значит всё-таки ООП — твой супермолоток?
Здравствуйте, 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 в таком случае требуется только модифицировать запросы.
Здравствуйте, 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, его элементарно может не быть.
Именно поэтому проверки делаются везде. Но откинет неправльный результат самая первая, поэтому на базу нагрузки не будет.
Здравствуйте, Tissot, Вы писали:
T>>>Мне даже пример пришел в голову, все с тем же резервированием по накладной.
T>>>Первоначальная постановка: T>>>По нажатию на кнопочку "Резерв." в форме заказа зарезервировать остатки на складе и послать во внешнюю систему (веб-сервис) запрос на упаковку. T>>>Решение: задача разбивается на 2 более мелких: 1) изменить остатки 2) послать запрос на упаковку.
T>>>CR (через полгода): T>>>При резервировании заказа заказ должен сохранять в одном из полей номер запроса на упаковку (номер возвращается веб-сервисом).
G>>Варианты G>>1)В первоначальной задаче операция изменения остатков не зависит от результата выполнения запроса. Операции запускаются параллельно. T>Не верное предположение. Если отгружать нечего, то и упаковывать нечего.
См. ниже.
G>>CR делает эти операции зависимыми, тогда сначала выполняется запрос (ниче не поделаешь, пользователю придется ждать), а потом сохранение данных. T>Даже если склад пустой? Чего упаковывать-то?
Если склад пустой, то оператор не сможет выбрать позиции для резервирования, транзакция не пойдет.
G>>Так как изменнеие остатков выполняется несколькими операциями insert и update, то это вполне можно сделать в одном батче без предварительного чтения и без длительного удержания блокировок.
G>>2)В первоначальной задаче операция изменения остатков и выполнение запроса составляют бизнес-транзакцию. Тогда изначально будет сначала выполняться запрос, а потом изменнеие остатков. Для реализации CR в таком случае требуется только модифицировать запросы.
Здравствуйте, gandjustas, Вы писали:
G>>>CR делает эти операции зависимыми, тогда сначала выполняется запрос (ниче не поделаешь, пользователю придется ждать), а потом сохранение данных. T>>Даже если склад пустой? Чего упаковывать-то? G>Если склад пустой, то оператор не сможет выбрать позиции для резервирования, транзакция не пойдет.
Здравствуйте, Tissot, Вы писали:
T>Здравствуйте, gandjustas, Вы писали:
G>>>>CR делает эти операции зависимыми, тогда сначала выполняется запрос (ниче не поделаешь, пользователю придется ждать), а потом сохранение данных. T>>>Даже если склад пустой? Чего упаковывать-то? G>>Если склад пустой, то оператор не сможет выбрать позиции для резервирования, транзакция не пойдет.
T>Резервируют не позиции, а заказ.
Тут уже показывайте схему данных, формализованный бизнес-процесс, как работает сервис и какие тербования предьявляются к программе.
Здравствуйте, 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, то их можно расположить в бизнесе, что на мой взгляд, удобнее.