Здравствуйте, gandjustas, Вы писали:
G>>>А почему формальное описание не может служить метаданными? A>>А тогда о чём ты споришь? Я именно это с самого начала и предлагаю. G>Так оно и так используется (в Linq2SQL сейчас есть, в EF будет), правда в ограниченном объеме.
Нет, это генерация run-time или одноразовая типа add reference. Я о compile-time генерации говорю.
G>Это нужно очень крутое описание чтобы сгенерировать кучу методов GetById, GetAll, FindByDickLength итп.
Вовсе нет. Достаточно уметь генерировать все типичные методы. Нетипичные, это либо попытка запихать логику в БД и надо от этого избавляться, либо разного рода отчёты и с этим справится Query Object.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, gandjustas, Вы писали:
G>>Так и пусть целостность данных на уровне БД будет, и не надо BL усложнять. И волки сыты и овцы — целки.
A>Если ты позволяешь GetById возвращать null, ты усложняешь BL обработкой этого случая либо скрываешь ошибку необработкой.
Я этого не предлагаю. Я предлагаю возвращать выборку, а уже BL уже будет обработка случая пустой выборки — это супер-мега ошибка или нормальный случай. Код будет такой же, только переедет на тот уровень где ему положено обитать. DAL в этом случае упростится.
Так что все будут в выйгрыше.
A>>>Разница такая, что его не имеют права вызывать с Id которого нет в базе. Если подобное случилось, значит где-то баг, который надо исправить. G>>Почему не имеют? Это же просто метод доступа к данным, какая вообще разница зачем его вызывают? Как обрабаотывать случай отсутсвия в базе записи с нужным ID — уже дело BL, причем способ обработки сильно зависит от варианта использования. A>BL не должен содержать код обработки нецелостных данных.
Не должен, пусть целостность данных обеспецивает БД.
A>>>Открою секрет — в базе данных есть индексы. Нельзя одинаково эффективно выполнять выборку по разным условиям. Поэтому, надо явно выделять эффективные случаи в специализированные методы доступа. G>>Вау, оказывается DAL — это premature optimization для работы с БД? A>Нет.
Почему? предыдущее сообщение показывает обратное.
A>Но DAL не может состоять из одного только метода Query.
Да, нужны еще update, insert, delete. Этого достаточно.
A>>>Если этого не делать, получается абсолютно некотроллируемый рост похожих запросов. Оптимизировать базу под все из них невозможно, а если подумать, все и не нужны вовсе. G>>А под все оптимизировать и не надо, надо только под тормозящие. Для этого профайлер в зубы и смотрим, обычно в программе меньше пяти Особо Торозящих Запросов. A>Тормозящие понятие относительное. Ты этоо измеряешь, может, в секундах, а я сталкивался с творениями любителей HQL и прочих "вкусностей", которые так сильно тормозили, что приходилось менять бизнес-процессы. Оптимальные запросы должны быть выделены. Это не прихоть, а практическая необходимость.
То что кто-то написал хреновый запрос является аргументом?
Вообще говоря я видел много примеров когда использование Linq2SQL и EF увеличивало производитльность работы с данными, и только один пример обратного эффекта (исключительно вина программиста)
A>>>Только вот в твоём варианте, какие лучше нигде в интерфейсе DAL не светится. G>>Не надо преждевременной оптимизацие заниматься. A>Она не преждевременная, так как схема БД (включая индексы) уже есть.
Ага, значит кто-то до вас уже соптимизировал БД
Здравствуйте, MozgC, Вы писали:
MC>Здравствуйте, gandjustas, Вы писали:
G>>Как обрабаотывать случай отсутсвия в базе записи с нужным ID — уже дело BL, причем способ обработки сильно зависит от варианта использования. MC>Нет, целостность данных — должна контролироваться в DAL и БД. Отствие записи с нужным ID — это исключительная ситуация, и DAL в таком случае должен выбрасывать исключение. И вот дальше уже да, дело бизнес-логики как обрабатывать это исключение.
Я предлагаю не выбрасывать исключение из DAL, а заниматься обработкой случая пустой выборки по месту в BL (возможно с выбрасыванем исключения).
Вполне возможно что отсуствие запси с нужным ID — нормальная ситуация в одном случае и ошибочная в другом, вы что будете делать? Писать два DAL метода с одинаковыми запросами?
Здравствуйте, adontz, Вы писали:
A>...Читать таблицу именно как серию запросов GetRelatedX плохо по соображениям производительности.
Ром. Попробуй встяхнуть головой и представить, что можно жить без методов GetRelatedX вообще. Вместо этого можно прямо в запросе использовать JOIN.
У тебя же нет проблем при вынимании аналогичных данных средствами SQL в БД? Ну, а откуда же они берутся когда запрос становится описанным в ООЯ вроде C#?
A>Вот, об этом я и говорю. Тут пометили руками, там пометили. В итоге куча разбросанных по всему коду пометок. Не хорошо это.
Не пометил, а указал. Написал: ...select new { c.Name, c.Amount } и получил только два нужных поля.
Ты вообще, linq-ом то пользовался?
A>Тем не менее, с бизнес-сущностями Linq не работает и то что возвращает Linq всё равно надо пересобирать.
А надо? Зачем вообще эти бизнес-сущности. Тебе данные надо обрабатывает или об объектах думать?
Зачем тебе вообще нужны объекты для хранения данных вынутых из БД?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, gandjustas, Вы писали:
G>То что кто-то написал хреновый запрос является аргументом?
Вообще говоря да, потому что средства разработки не подсказывали хороших запросов, оставляя на совести программиста знание всех тонкостей схемы БД.
A>>Она не преждевременная, так как схема БД (включая индексы) уже есть. G>Ага, значит кто-то до вас уже соптимизировал БД
Просто создал. На самом деле всё гораздо хуже. Если в результате оптимизации какие-то индексы будут убраны, то какие-то запросы перестанут быть супербыстрыми и спецметоды для них больше не будут генерироваться. Таким образом о проблеме я узнаю не тогда, когда позвонит клиент и скажет, что начало тормозить то, что раньше не тормозило, а на этапе компиляции.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, gandjustas, Вы писали:
G>>>>А почему формальное описание не может служить метаданными? A>>>А тогда о чём ты споришь? Я именно это с самого начала и предлагаю. G>>Так оно и так используется (в Linq2SQL сейчас есть, в EF будет), правда в ограниченном объеме.
A>Нет, это генерация run-time или одноразовая типа add reference. Я о compile-time генерации говорю.
О генерации чего вы сейчас говорите?
G>>Это нужно очень крутое описание чтобы сгенерировать кучу методов GetById, GetAll, FindByDickLength итп. A>Вовсе нет. Достаточно уметь генерировать все типичные методы. Нетипичные, это либо попытка запихать логику в БД и надо от этого избавляться, либо разного рода отчёты и с этим справится Query Object.
Критерий "типичности" метода в студию.
Здравствуйте, adontz, Вы писали:
G>>DAL в виде GetByIi, GetAll и прочих методов создается как раз чтобы сконцентрировать этот sacral knoweledge в одном месте. Это позволяет программисту понимать что происходит, но не дает никаких гарантий (не проверяется при компиляции).
A>Вот. А если использовать генерацию кода, то вероятность рассинхронизации названия и смысла падает до нуля.
Тебе намекают, что все эти GetById и GetAll — просто не нужны, если есть возможность использовать типизированные запросы прямо в языке на котором описывается бизнес-логика. И DAL как таковой не нужен, так как срывать становится не чего.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, gandjustas, Вы писали:
G>>То что кто-то написал хреновый запрос является аргументом? A>Вообще говоря да, потому что средства разработки не подсказывали хороших запросов, оставляя на совести программиста знание всех тонкостей схемы БД.
Это опять пахнет прездевременной оптимизацией. Пусть программист пишет как получится, потом можно оптимизировать если будет медленно.
A>>>Она не преждевременная, так как схема БД (включая индексы) уже есть. G>>Ага, значит кто-то до вас уже соптимизировал БД A>Просто создал. На самом деле всё гораздо хуже. Если в результате оптимизации какие-то индексы будут убраны, то какие-то запросы перестанут быть супербыстрыми и спецметоды для них больше не будут генерироваться. Таким образом о проблеме я узнаю не тогда, когда позвонит клиент и скажет, что начало тормозить то, что раньше не тормозило, а на этапе компиляции.
Само наличие индектов еще не сделает запрос супербыстрым.
Кстати как будете обеспечивать синхронность базы и кода у клиента? Вдруг "грамотный" админ залезет в базу и грохнет индекс?
Здравствуйте, MozgC, Вы писали:
MC>Нет, целостность данных — должна контролироваться в DAL и БД. Отствие записи с нужным ID — это исключительная ситуация, и DAL в таком случае должен выбрасывать исключение. И вот дальше уже да, дело бизнес-логики как обрабатывать это исключение.
Предположим... У нас есть веб-страничка в которой список тем. Ты хочешь прочесть тело сообщения, но сообщение к этому времени уже удалил модератор. Что тут исключительного?
Почему нельзя сделать метод или запрос который просто вернет некий признак отсутствия данных?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Ром. Попробуй встяхнуть головой и представить, что можно жить без методов GetRelatedX вообще. Вместо этого можно прямо в запросе использовать JOIN. VD>У тебя же нет проблем при вынимании аналогичных данных средствами SQL в БД? Ну, а откуда же они берутся когда запрос становится описанным в ООЯ вроде C#?
JOIN тут никак не поможет. Объясняю данный пример подробно. Есть таблицы А и B вида
id | name
1 | first
2 | second
3 | third
а так же таблица A2B вида
aId | dId
1 | 1
1 | 2
2 | 1
2 | 3
3 | 1
3 | 5
Если читать её не целиком, а кусками (не важно по aID будет выборка или по bID) ты в самом лучшем случае замедлишь всё в O(ln(n)) раз.
A>>Вот, об этом я и говорю. Тут пометили руками, там пометили. В итоге куча разбросанных по всему коду пометок. Не хорошо это. VD>Не пометил, а указал. Написал: ...select new { c.Name, c.Amount } и получил только два нужных поля. VD>Зачем тебе вообще нужны объекты для хранения данных вынутых из БД?
Затем чтобы, например, прибайндить IBindingList<мои объекты> сразу в несколько View. И чтобы они обновлялись нормально, без "паркинсона" на кнопке F5, а для этого, кстати, нужен INotifyPropertyChanged и вообще много разных мелких инфраструктурных штучек. А ещё, могу захотеть кешировать, причём даже не весь объект, а его часть. Если чтение производится где попало через Query, мне это вряд ли удасться сделать.
Здравствуйте, Tom, Вы писали:
Tom>Хорошо, пункт один — императивная логика. Мне правда пока не совсем понятно почему в TSQL её лучше не использовать, но возможно позже понимание придёт.
Отладка. Если есть проблема, то пройтись по шагам по такой логике будет проблематично. Если же SQL генерируется, то в конце концов ты получаешь один единственный скрипт, который можно прогнать и увидеть есть ли в нём проблемы.
Tom>Что ещё можно сделать что бы улучшить этот код. Влад например предлагал устранить временные таблицы и курсоры. насчёт курсоров конечно понятно что лучше без них. Насчёт временных таблиц я пока не уверен что тотальное их устранение улучшит понимание кода.
Временные таблицы точно также затрудняют анализ скрипта, но с ними всё же как-то можно бороться.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, SleepyDrago, Вы писали:
SD>Так что согласны вы с Tom или нет предложить вам ему нечего тк у него основная масса логики в базе. Вариант "просто переписать все на С#/Linq" любым разумным менеджером будет послан, разве что систему будут утилизировать и будет финансирование "с чистого листа".
Тому самому себе предложить нечего. Легаси код нужно прежде всего завернуть в новые обёртки и как раз здесь ему всё давно предложили.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, gandjustas, Вы писали:
A>>Нет, это генерация run-time или одноразовая типа add reference. Я о compile-time генерации говорю. G>О генерации чего вы сейчас говорите?
Как схемы БД, так и кода для работы с БД. Да, вот забыл упомянуть, что делать с row level security? Боюсь, если хранимки не генерировать, будет беда.
G>>>Это нужно очень крутое описание чтобы сгенерировать кучу методов GetById, GetAll, FindByDickLength итп. A>>Вовсе нет. Достаточно уметь генерировать все типичные методы. Нетипичные, это либо попытка запихать логику в БД и надо от этого избавляться, либо разного рода отчёты и с этим справится Query Object. G>Критерий "типичности" метода в студию.
Строго формального критерия нет. Практически все Insert/Update/Delete типичные. Есть исключения, но они крайне редки. Выборки, если это Select All или Select by Foreign Key, тоже типичные.
Здравствуйте, IT, Вы писали:
IT>Временные таблицы точно также затрудняют анализ скрипта, но с ними всё же как-то можно бороться.
Вообще временные таблицы иногда могут помочь упростить запрос.
Здравствуйте, adontz, Вы писали:
A>Стоп, а разве я описываю объектную модель? Вовсе нет. Я описываю сущности. Как может специалист предметной области не разбираться в сущностях?
Специалист предметной области может разобраться в том, что такое сущность. Но только при одном условии, если сущность называть Data Type и представлять их в виде таблицы в ворде с колонками типа Name, Type (не int, string, data, а число, строка, дата), Range, Validation Rules и т.п.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, VladD2, Вы писали:
A>JOIN тут никак не поможет. Объясняю данный пример подробно. Есть таблицы А и B вида A>
A>id | name
A> 1 | first
A> 2 | second
A> 3 | third
A>
A>а так же таблица A2B вида A>
A>aId | dId
A> 1 | 1
A> 1 | 2
A> 2 | 1
A> 2 | 3
A> 3 | 1
A> 3 | 5
A>
A>Если читать её не целиком, а кусками (не важно по aID будет выборка или по bID) ты в самом лучшем случае замедлишь всё в O(ln(n)) раз.
А с какой целью её читать вообще?
A>>>Вот, об этом я и говорю. Тут пометили руками, там пометили. В итоге куча разбросанных по всему коду пометок. Не хорошо это. VD>>Не пометил, а указал. Написал: ...select new { c.Name, c.Amount } и получил только два нужных поля. VD>>Зачем тебе вообще нужны объекты для хранения данных вынутых из БД?
A>Затем чтобы, например, прибайндить IBindingList<мои объекты> сразу в несколько View. И чтобы они обновлялись нормально, без "паркинсона" на кнопке F5, а для этого, кстати, нужен INotifyPropertyChanged и вообще много разных мелких инфраструктурных штучек. А ещё, могу захотеть кешировать, причём даже не весь объект, а его часть. Если чтение производится где попало через Query, мне это вряд ли удасться сделать.
View, f5... надеюсь это не о вебе.
Здравствуйте, VladD2, Вы писали:
VD>Предположим... У нас есть веб-страничка в которой список тем. Ты хочешь прочесть тело сообщения, но сообщение к этому времени уже удалил модератор. Что тут исключительного? VD>Почему нельзя сделать метод или запрос который просто вернет некий признак отсутствия данных?
Я бы вызвал исключение, а уже бизнес-логика бы решила что делать с тем, что такой темы нет.
Вообще так можно про все сказать "что тут исключительного". К примеру пытаемся прочитать файл, а такого файла нет (его уже пользователь удалил), ну а что тут исключительного, давайте признак возвращать.
Здравствуйте, gandjustas, Вы писали:
G>Само наличие индектов еще не сделает запрос супербыстрым.
Зная какие есть индексы, можно предсказать какие выборки будут супербыстрыми. Никакой магиитут нет.
G>Кстати как будете обеспечивать синхронность базы и кода у клиента? Вдруг "грамотный" админ залезет в базу и грохнет индекс?
А что, ваш метод защищает от "грамотного" админа? Да и вообще, насколько актуальна эта проблема?
Здравствуйте, VladD2, Вы писали:
VD>Предположим... У нас есть веб-страничка в которой список тем. Ты хочешь прочесть тело сообщения, но сообщение к этому времени уже удалил модератор. Что тут исключительного?
Сам факт модерирования исключителен
VD>Почему нельзя сделать метод или запрос который просто вернет некий признак отсутствия данных?
По-моему, в твоём примере налицо race condition. Надо либо запретить удалять из базы данных (я за этот метод), а только помечать сообщение как удалённое, либо смириться с тем что DAL кинет исключение, потому что блокировать ресурс-сообщение нельзя. В BL его можно обработать, а можно даже не обрабатывать. В конце концов я могу прямо в URL вбить номер несуществующего сообщения.