Друзья, объясните бестолковому, как правильно производить валидацию с учетом того, что используется Domain Model или хотя бы Table Module. В поиск просьба носом не тыкать: там я уже все почитал, что нашел.
Проблема: есть пользовательский ввод. Этот ввод нужно валидировать, причем не только на форматы и длины строк (это-то примитивно и нормально решается UI) но и диапазоны (в процедуре проверки которых может участвовать множество объектов), и валидные переходы (например, состояний объекта) и т.д. Понятное дело, требуется гибкость на том уровне, что пользователю по его команде сразу показать все его ошибки (естественно, если проверки определены; так например не стоит же говорить о несоблюдении диапазонов если формат данных неверный), с другой стороны — крайне разумно выглядит отсутствие дублирования кода (ведь объект домена, по идее, не должен позволять перевести себя в некорректное состояние, то есть уже в UI без дублирования не вынесешь).
Если не жалко, поделитесь идеями, как организовать подобную функциональность, либо ткните пальчиком в книжку, где доходчиво написано.
Здравствуйте, Козьма Прутков, Вы писали:
КП>Друзья, объясните бестолковому, как правильно производить валидацию с учетом того, что используется Domain Model или хотя бы Table Module. В поиск просьба носом не тыкать: там я уже все почитал, что нашел. КП>Проблема: есть пользовательский ввод. Этот ввод нужно валидировать, причем не только на форматы и длины строк (это-то примитивно и нормально решается UI) но и диапазоны (в процедуре проверки которых может участвовать множество объектов), и валидные переходы (например, состояний объекта) и т.д. Понятное дело, требуется гибкость на том уровне, что пользователю по его команде сразу показать все его ошибки (естественно, если проверки определены; так например не стоит же говорить о несоблюдении диапазонов если формат данных неверный), с другой стороны — крайне разумно выглядит отсутствие дублирования кода (ведь объект домена, по идее, не должен позволять перевести себя в некорректное состояние, то есть уже в UI без дублирования не вынесешь). КП>Если не жалко, поделитесь идеями, как организовать подобную функциональность, либо ткните пальчиком в книжку, где доходчиво написано.
КП>Заранее спасибо.
AV>такой код генерится для каждого контрола на форме (плюс если поле не стринговое то проверяется возможность парсинга, например Int32.Parse (...) ).
Да, верно, это форматы, обязательность и т.д., то есть простые первичные проверки (ну, обязательность, кстати, может быть и не простой, например, зависеть от статуса некоторого объекта и выполняемой команды пользователя). А как быть с диапазонами, валидация которых происходит по некоторым правилам, которые могут и измениться (не переписывать же их во всех местах реализации, в самом деле)?
), формируется примерно такой код на уровне UI:
AV>>[c#] AV>> protected virtual string Category_IsValidate() AV>> { AV>> string strResult = ""; AV>> if (textboxCategory.Text == "") AV>> { AV>> strResult = "Поле не может быть пустым!"; AV>> return strResult; //это, по моему, лишнее: даже если проверок несколько, проще воспользоваться else if(...) AV>> } AV>> return strResult; AV>> }
Да, проверок может быть несколько, а if .. else — имхо, смотрится еще хуже, чем два подряд return; да и, честно говоря, приведенный алгоритм легче генерировать, чем то, что предлагаете вы.
<skipped>
КП>Да, верно, это форматы, обязательность и т.д., то есть простые первичные проверки (ну, обязательность, кстати, может быть и не простой, например, зависеть от статуса некоторого объекта и выполняемой команды пользователя). А как быть с диапазонами, валидация которых происходит по некоторым правилам, которые могут и измениться (не переписывать же их во всех местах реализации, в самом деле)?
я не очень понимаю, что вы хотите, вот ваша фраза: валидация которых происходит по некоторым правилам эти правила не поддаются алгоритмизации? или вот: А как быть с диапазонами, валидация которых происходит по некоторым правилам, которые могут и измениться (не переписывать же их во всех местах реализации, в самом деле)? можно, например, сделать некую функцию проверки для каждого аттрибута сущности, и может даже вынести ее в отдельную dll, и использовать ее во всех местах, а исправлять только в одном.
Здравствуйте, AlexandrV, Вы писали:
AV>Да, проверок может быть несколько, а if .. else — имхо, смотрится еще хуже, чем два подряд return; да и, честно говоря, приведенный алгоритм легче генерировать, чем то, что предлагаете вы.
спорить не стану, благо генератор и сам писал, и не один, так что проблема знакома. Просто есть некоторое соображение "единственного return'а" — это упрощает отладку если нужно узнать, что функция возвращает, не ползая по ее телу отладчиком.
AV>я не очень понимаю, что вы хотите, вот ваша фраза: валидация которых происходит по некоторым правилам эти правила не поддаются алгоритмизации? или вот: А как быть с диапазонами, валидация которых происходит по некоторым правилам, которые могут и измениться (не переписывать же их во всех местах реализации, в самом деле)? можно, например, сделать некую функцию проверки для каждого аттрибута сущности, и может даже вынести ее в отдельную dll, и использовать ее во всех местах, а исправлять только в одном.
нет, конечно же все алгоритмизируется, иначе это было бы невозможно автоматизировать
Это уже теплее, я бы даже сказал, похоже на правду. Вот только пример бы кто-нить привел... с учетом иерархических зависимостей процедур валидации (если одна не прошла, то 5 других делать бессмысленно), достаточно большого количества объектов предметной области (ну, положим, 50), каждый из которых имеет по десятку свойств.
Здравствуйте, Козьма Прутков, Вы писали:
КП>Друзья, объясните бестолковому, как правильно производить валидацию с учетом того, что используется Domain Model или хотя бы Table Module. В поиск просьба носом не тыкать: там я уже все почитал, что нашел. КП>Проблема: есть пользовательский ввод. Этот ввод нужно валидировать, причем не только на форматы и длины строк (это-то примитивно и нормально решается UI) но и диапазоны (в процедуре проверки которых может участвовать множество объектов), и валидные переходы (например, состояний объекта) и т.д. Понятное дело, требуется гибкость на том уровне, что пользователю по его команде сразу показать все его ошибки (естественно, если проверки определены; так например не стоит же говорить о несоблюдении диапазонов если формат данных неверный), с другой стороны — крайне разумно выглядит отсутствие дублирования кода (ведь объект домена, по идее, не должен позволять перевести себя в некорректное состояние, то есть уже в UI без дублирования не вынесешь). КП>Если не жалко, поделитесь идеями, как организовать подобную функциональность, либо ткните пальчиком в книжку, где доходчиво написано.
Я уже очень давно пытаюсь понять как бы правильней это сделать и постоянно упираюсь в сложность решения. Но вот в последнее время я более менее доработал видимую картину и начал реализовывать.
Во первых, я ввел понятие элементарной частицы (элемент) и уровень (Scope) данных элементов определяет общее состояние всех элементов на уровне. Уровни объединяются в пространства и дальше оперируем с пространством как с формой для ввода данных, где элементы — это контролы этой формы. Контролы, могут находится на разных уровнях — например уровень ошибок, уровень незаполненных данных и уровень успешно заполненных контролов.
Перемещать контролы с уровня на уровень должен специальный инспектор с помощью инспекций (проверок). Можно это делать как в рантайме по таймеру, так и по нажатии на кнопку.
Рендерер, который прорисовывает форму (пространство) рисует контролы с оформлением заданным, на уровне. Ввод продолжается до тех пор, пока все контролы не перейдут на успешный уровень.
Но данное решение пока применимо для клиентов и на Web труднопереносимо в плане runtime проверки и т.д.
Здравствуйте, aefimov, Вы писали:
A>Я уже очень давно пытаюсь понять как бы правильней это сделать и постоянно упираюсь в сложность решения. Но вот в последнее время я более менее доработал видимую картину и начал реализовывать.
A>Во первых, я ввел понятие элементарной частицы (элемент) и уровень (Scope) данных элементов определяет общее состояние всех элементов на уровне. Уровни объединяются в пространства и дальше оперируем с пространством как с формой для ввода данных, где элементы — это контролы этой формы. Контролы, могут находится на разных уровнях — например уровень ошибок, уровень незаполненных данных и уровень успешно заполненных контролов.
A>Перемещать контролы с уровня на уровень должен специальный инспектор с помощью инспекций (проверок). Можно это делать как в рантайме по таймеру, так и по нажатии на кнопку.
A>Рендерер, который прорисовывает форму (пространство) рисует контролы с оформлением заданным, на уровне. Ввод продолжается до тех пор, пока все контролы не перейдут на успешный уровень.
A>Но данное решение пока применимо для клиентов и на Web труднопереносимо в плане runtime проверки и т.д.
A>Спасибо!
за что?
Да, идея интересная... Она по-моему применима и для веба в случае, если инспекции — по нажатию на кнопку, точнее, по запросу (не на всякую кнопку нужно инспектировать) с реакцией на результаты инспекции. А инспекторы — это не контроллеры? Их отношение один-к-одному с формами?
Я, честно говоря, нашел недосказанность в своем вопросе: мне было интересно также рассмотреть вариант, при котором источников изменений несколько (допустим, веб-приложение и веб-сервис): ситуация гипотетическая, но понимание не помешает. А в этой ситуации все страшнее: сама бизнес-энтити (БЭ) должна знать (возможно, опосредованно), что правильно, а что нет (этакой Defensive programming). Соответственно, нужны какие-то валидаторы, которыми можно пользоваться и в самой БЭ, и в UI (ну, или иных источниках изменений для предварительной проверки корректности данных, прежде чем совать их в БЭ). То есть UI просит валидатор, уточняет у него правомерность действия, которое хочет совершить, и в случае ок уже корежит БЭ.
гипотетическая, но понимание не помешает. А в этой ситуации все страшнее: сама бизнес-энтити (БЭ) должна знать (возможно, опосредованно), что правильно, а что нет (этакой Defensive programming). Соответственно, нужны какие-то валидаторы, которыми можно пользоваться и в самой БЭ, и в UI (ну, или иных источниках изменений для предварительной проверки корректности данных, прежде чем совать их в БЭ). То есть UI просит валидатор, уточняет у него правомерность действия, которое хочет совершить, и в случае ок уже корежит БЭ.
в UI формато зависимая валидация а в BL Логико зависимая. и UI пишет в BL без предварительного разрешения (например байндингом, если формат введенных данных правильный) а при ошибке проверки уже в BL возникает exception, который и обрабатывается.
а логическая проверка может быть реализована в set-ах get-ах свойств БЭ.
Здравствуйте, AlexandrV, Вы писали:
AV>Здравствуйте, Козьма Прутков, Вы писали:
AV><skipped>
AV>в UI формато зависимая валидация а в BL Логико зависимая. и UI пишет в BL без предварительного разрешения (например байндингом, если формат введенных данных правильный) а при ошибке проверки уже в BL возникает exception, который и обрабатывается. AV>а логическая проверка может быть реализована в set-ах get-ах свойств БЭ.
Согласен. Но:
1) Допустим, операция не простая, требует изменения состояния нескольких объектов. При этом ошибка (связанная с некорректными данными) обнаруживается где-то посередине и летит исключение: в каком состоянии находятся данные? Понятное дело в неконсистентном.
2) Обычно пользователь хочет знать полный список допущенных им ошибок. В этом сценарии это трудновато получить: ну не тыкаться же с каждым изменением в БЭ, подставив ухо с готовностью к удару и коллекционируя синяки чтобы потом их скопом показать (это наиболее актуально в вебе; так демонстрирует результаты валидация в ASP.NET). Конечно, есть смысл постулировать: мелочь мы показываем скопом, а логические ошибки — по одиночке. Но для пользователя это разделение далеко не очевидно
Здравствуйте, Козьма Прутков, Вы писали:
КП>Здравствуйте, AlexandrV, Вы писали:
AV>>Здравствуйте, Козьма Прутков, Вы писали:
AV>><skipped>
AV>>в UI формато зависимая валидация а в BL Логико зависимая. и UI пишет в BL без предварительного разрешения (например байндингом, если формат введенных данных правильный) а при ошибке проверки уже в BL возникает exception, который и обрабатывается. AV>>а логическая проверка может быть реализована в set-ах get-ах свойств БЭ.
КП>Согласен. Но: КП>1) Допустим, операция не простая, требует изменения состояния нескольких объектов. При этом ошибка (связанная с некорректными данными) обнаруживается где-то посередине и летит исключение: в каком состоянии находятся данные? Понятное дело в неконсистентном.
делаем самое простое, что приходит в голову: откат транзакции. и вообще, кажется вы меня просто хотите запутать — может пример привели бы?
КП>2) Обычно пользователь хочет знать полный список допущенных им ошибок. В этом сценарии это трудновато получить: ну не тыкаться же с каждым изменением в БЭ, подставив ухо с готовностью к удару и коллекционируя синяки чтобы потом их скопом показать (это наиболее актуально в вебе; так демонстрирует результаты валидация в ASP.NET). Конечно, есть смысл постулировать: мелочь мы показываем скопом, а логические ошибки — по одиночке. Но для пользователя это разделение далеко не очевидно
в том варианте что я сказал, так вполне можно реализовать, а именно:
— для каждого атрибута свой метод проверки
— и плюс общий метод проверки всего объекта
Здравствуйте, Козьма Прутков, Вы писали:
КП>А инспекторы — это не контроллеры? Их отношение один-к-одному с формами?
Нет, это именно еще один уровень. Контроллер отвечает за получение данных и транспортировку их куда нужно.
Получить данные он может только после того, как инспектор их проверит.
Я думаю правильней на каждый редактор (форму) создавать отдельного инспектора с заданным набором инспекций. Однако это не отменяет существование одного большого с инспекциями на все случае жижни для всех форм.
КП>Я, честно говоря, нашел недосказанность в своем вопросе: мне было интересно также рассмотреть вариант, при котором источников изменений несколько (допустим, веб-приложение и веб-сервис): ситуация гипотетическая, но понимание не помешает. А в этой ситуации все страшнее: сама бизнес-энтити (БЭ) должна знать (возможно, опосредованно), что правильно, а что нет (этакой Defensive programming). Соответственно, нужны какие-то валидаторы, которыми можно пользоваться и в самой БЭ, и в UI (ну, или иных источниках изменений для предварительной проверки корректности данных, прежде чем совать их в БЭ). То есть UI просит валидатор, уточняет у него правомерность действия, которое хочет совершить, и в случае ок уже корежит БЭ.
Ясно. Я тоже сталкнулся с тем вопросом — "когда заканчивать проверки". UI уровень, бизнес уровень и т.д. Но честно говоря, я пришел к тому, что проверять нужно только то, что вводит пользователь — ему это понятней. Т.е. только уровень отпользователя и до формирования валидных данных. Все остальное, ИМХО, должно отдаваться на усмотрение базы данных. Бесконечно проверяя "правильность данных" можно заткнуться в слишком сложной логике этих проверок, многие из которых должны делаться внутри БД. Это необходимо еще и по тому, что налицие бизнес проверок в коде приведет к нестабильности всяких импортов и т.д., т.е. когда с базой назнут работать напрямую.
Поэтому, я считаю, что в коде должна быть проверка UI и все — остальное в базе + перехват этих ошибок и вывод их пользователю.
предлагаю сразу перейти на ты: проще и привычнее.
AV>делаем самое простое, что приходит в голову: откат транзакции. и вообще, кажется вы меня просто хотите запутать — может пример привели бы?
увольте, ни малейшего желания кого-либо запутать у меня и в мыслях не было. Транзакций пока нет: все в памяти, иначе и не спрашивал бы. То есть ситуация: есть сложная БЭ (этакой класс, с кучей свойств, коллекций аналогичных сложных объектов и т.п.) Форма для редактирования. Пользователь вводит некие данные и жмет ОК. Мне требуется внести запрошенные пользователем изменения в данные БЭ (или ассоциированных с нею БЭ) и выйти либо сказать, что не так. Сохраняться в БД это будет потом, минут через 10, например, когда пользователь налазается вволю по разным ассоциированным сущностям, поправит в них данные и т.д. Реального примера нету: хочу понять концептуально. Пример даже придумать не получается, видимо, крайне нетипичная ситуация. Все, что приходят в голову, проверяются достаточно просто прежде, чем запускать каскадное изменение данных. Но что, если проверка нетривиальная?
КП>>2) Обычно пользователь хочет знать полный список допущенных им ошибок. В этом сценарии это трудновато получить: ну не тыкаться же с каждым изменением в БЭ, подставив ухо с готовностью к удару и коллекционируя синяки чтобы потом их скопом показать (это наиболее актуально в вебе; так демонстрирует результаты валидация в ASP.NET). Конечно, есть смысл постулировать: мелочь мы показываем скопом, а логические ошибки — по одиночке. Но для пользователя это разделение далеко не очевидно
AV>в том варианте что я сказал, так вполне можно реализовать, а именно: AV>- для каждого атрибута свой метод проверки AV>- и плюс общий метод проверки всего объекта
вот тут мне не все ясно:
1) правильно я понимаю, что на каждое свойство есть метод а-ля bool canAssignStartDate(DateTime value)?
2) это подразумевает, что вызов этого метода сообщит, находится ли объект в валидном и консистентном состоянии, верно? То есть подразумевается, что его в неконсистентное состояние можно перевести.
<skipped>
AV>>в том варианте что я сказал, так вполне можно реализовать, а именно: AV>>- для каждого атрибута свой метод проверки AV>>- и плюс общий метод проверки всего объекта
КП>вот тут мне не все ясно: КП>1) правильно я понимаю, что на каждое свойство есть метод а-ля bool canAssignStartDate(DateTime value)? КП>2) это подразумевает, что вызов этого метода сообщит, находится ли объект в валидном и консистентном состоянии, верно? То есть подразумевается, что его в неконсистентное состояние можно перевести.
вообще-то наверное, не совсем так, скорей так:
class C
{
public C
{
}
protected string strA = "";
public string A
{
get { return strA; }
set
{
ValidateA( value ); // здесь будет exception в случае чего не правильного
strA = value;
}
public void ValidateA()
{
// проверка value на правильность и корректность
// если не правильно и не корректно то exception
}
public void Validate()
{
ValidateA( strA );
}
}
}
КП>Да, чувствую, замучил я народ глупостями
да нет, все нормально, объясняя другому и сам лучше понимаешь.
Здравствуйте, Козьма Прутков, Вы писали:
КП>Здравствуйте, AlexandrV, Вы писали:
КП>предлагаю сразу перейти на ты: проще и привычнее.
AV>>делаем самое простое, что приходит в голову: откат транзакции. и вообще, кажется вы меня просто хотите запутать — может пример привели бы? КП>увольте, ни малейшего желания кого-либо запутать у меня и в мыслях не было. Транзакций пока нет: все в памяти, иначе и не спрашивал бы. То есть ситуация: есть сложная БЭ (этакой класс, с кучей свойств, коллекций аналогичных сложных объектов и т.п.) Форма для редактирования. Пользователь вводит некие данные и жмет ОК. Мне требуется внести запрошенные пользователем изменения в данные БЭ (или ассоциированных с нею БЭ) и выйти либо сказать, что не так. Сохраняться в БД это будет потом, минут через 10, например, когда пользователь налазается вволю по разным ассоциированным сущностям, поправит в них данные и т.д. Реального примера нету: хочу понять концептуально. Пример даже придумать не получается, видимо, крайне нетипичная ситуация. Все, что приходят в голову, проверяются достаточно просто прежде, чем запускать каскадное изменение данных. Но что, если проверка нетривиальная?
<skipped>
а похоже я уже и ответил, в предыдущем ответе на этот топик. или нет?
Здравствуйте, Козьма Прутков, Вы писали:
КП>Если не жалко, поделитесь идеями, как организовать подобную функциональность...
Прежде всего я бы рассмотрел различные стадии валидации и почему они необходимы, а уже потом её реализацию.
К сожалению, валидацию не получается делать в одном месте за один раз по ряду причин, поэтому обычно она разбивается на несколько уровней.
1. Базовая валидация допустимых параметров вводимых значений. Сюда входит проверка обязательности и длин полей, формат вводимых данных. Основное назначение данного уровня — минимизировать возможность неправильного ввода, исключить походы на сервер (в случае Web) и предоставить пользователю информацию о некорректно-введённых значениях.
2. Проверка валидности бизнес-энтити как единого целого. Этот уровень повторяет все проверки предыдущего, плюс добавляет проверки комбинации полей объекта. Например, если вводимый адрес принадлежит US, то Zip код должен быть 5 или 9 символов, если это Россия, то размер почтового индекса должен равняться 6-ти.
3. Проверка валидности объекта в пределах системы. Включает все предыдущие проверки, плюс всевозможные проверки на непротиворечивость объекта в системе. Например, тот же адрес обычно проверятся на существование такового с помощью специализированных систем. Email пользователя не должен дублироваться в системе и т.п.
4. Проверка целостности данных перед их сохранением в базе данных. Обычно с успехом выполняется средствами самой БД.
Теперь о реализации. С (4) всё понятно. Использвание констрейнов, пользовательских типов, уникальных индексов и FK решают эту проблему. Частично, например, в случае с e-mail, сюда можно перенести проверки 3-го уровня. В случае обычного UI (не-Web) приложения обычно удаётся совместить 1-й и 2-й уровни. Для Web-приложений 1-й (обычно не полностью) выполняется в браузере, 2-й и 3-й уровни можно совместить, если не используется выделенный сервер приложений. Если используется, то 2-й в Web-приложении, 3-й в сервере приложений.
Реализация 2-го и 3-го уровня обычно делается ручками. Ничего здесь автоматизировать, к сожалению, не получается. Причём 2-й следует делать как часть самого бизнес-объекта, а 3-й как метод бизнес логики. А вот с 1-м, который как правило самый занудный всё гораздо интереснее. Лучшая, на мой взгляд, реализация данного уровня — это применение атрибутов (речь, конечно идёт о .NET). В этом случае, т.к. мы фактически расширяем метадату объекта, удаётся по большей части автоматизировать проверки на UI, т.е. не только свести саму реализацию валидации объекта к описанию в виде атрибутов, но и натренировать UI компоненты понимать эти атрибуты.
Таким образом, 1-й и 2-й уровень удаётся инкапсулировать в самом объекте. 3-й уровень представляет собой один метод бизнес логики. 4-й реализуется средствами самой БД.
В общем, как-то так
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>К сожалению, валидацию не получается делать в одном месте за один раз по ряду причин, поэтому обычно она разбивается на несколько уровней.
Отлично. Ясно и по полочкам.
Да, с форматами и длинами я пожалуй спорить не буду: такие вещи крайне редко меняются, особенно форматы .
Рассмотрим веб-приложение (ибо сложнее), но аналогично и винформовое. Пусть по первоначальным требованиям поле Заказчик обязательное. Ок, сделали. Через 3 месяца оказывается, что оно не является обязательным. И мы шагом марш по всем уровням валидации это дело править. Или я чего-то не понял?
Таперь рассмотрим винформс-приложение (в веб-приложении решается написанием метода установки пары значений). Вот подвязана у нас к свойствам Country и ZipCode (он же индекс для примера) пара контролов. По идее, если пользователь меняет один из них, то нужно проверить их пару. Так что пользователь, однажды введя US/12345 уже никогда не введет RU/131000, ибо перекрестные комбинации невалидны. Ну, либо позволить перевести БО в неконсистентное состояние, что вряд ли очень хорошо.
Здравствуйте, Козьма Прутков, Вы писали:
КП>Рассмотрим веб-приложение (ибо сложнее), но аналогично и винформовое. Пусть по первоначальным требованиям поле Заказчик обязательное. Ок, сделали. Через 3 месяца оказывается, что оно не является обязательным. И мы шагом марш по всем уровням валидации это дело править. Или я чего-то не понял? КП>Таперь рассмотрим винформс-приложение (в веб-приложении решается написанием метода установки пары значений). Вот подвязана у нас к свойствам Country и ZipCode (он же индекс для примера) пара контролов. По идее, если пользователь меняет один из них, то нужно проверить их пару. Так что пользователь, однажды введя US/12345 уже никогда не введет RU/131000, ибо перекрестные комбинации невалидны. Ну, либо позволить перевести БО в неконсистентное состояние, что вряд ли очень хорошо.
Ты говоришь о валидации непосредственно во время ввода, о валидации каждого введённого символа. Мне эта практика кажется крайне порочной как раз по причинам, которые ты описываешь. Формы, которые думают что они умней меня всегда раздражают. Валидация значений и их комбинаций должна делаться при сабмите формы. Во время ввода можно проверять только формат, типа ничего не давать пользователю вводить кроме цифр и т.п.
Что же касается первого вопроса об изменениях по всем уровням валидации, то здесь я видимо не совсем ясно выразился. Говоря "этот уровень повторяет все проверки предыдущего" я не имел ввиду дублирование кода, я имел ввиду его повторное использование. Например, имеем вот такой класс Address:
public class Address : BizEntityBase
{
[MaxLength(35), Required] public string Address1;
[MaxLength(35) ] public string Address2;
[MaxLength(35), Required] public string City;
[MaxLength(35), Required] public string Region;
[ Required] public string PostalCode;
[ Required] public CountryCode CountryCode;
public override void Validate()
{
// 1-й уроовень.
//base.Validate();
// 2-й.
//switch (CountryCode)
{
case CountryCode.US:
if (PostalCode.Length != 5 || PostalCode.Length != 9)
throw new Exception("Zip must be 5 or 9 digits.");
break;
case CountryCode.RU:
if (PostalCode.Length != 6)
throw new Exception("Почтовый индекс должен содержать 6 цифр.");
break;
}
}
}
Здесь в одном месте реализованы 1-й и 2-й уровни валидации. Третий в бизнес объекте:
public class AddressService : ServiceBase
{
public void AddAddress(Address address)
{
// 1-й, 2-й.
//
address.Validate();
// 3-й. Вызываем код проверки адреса на существование.
// Используем софт компании Address Validation, Inc.
//new Agents.AddressValidator().Validate(address);
// Сохраняем обхект в БД.
//new AddressDataAccessor().AddAddress(address);
}
}
4-й в БД.
IF EXISTS (SELECT * FROM sysobjects WHERE type = 'U' AND name = 'Address')
BEGIN
PRINT 'Dropping Table Address'
DROP Table Address
END
GO
PRINT 'Creating Table Address'
GO
CREATE TABLE dbo.Address
(
AddressID int IDENTITY (1,1) NOT NULL CONSTRAINT PK_Address PRIMARY KEY CLUSTERED,
Address1 nvarchar(35) NOT NULL,
Address2 nvarchar(35),
City nvarchar(35) NOT NULL,
Region nvarchar(35) NOT NULL,
PostalCode nvarchar(11) NOT NULL,
CountryCode udt_CountryCode
) ON [PRIMARY]
GRANT SELECT ON Customer TO PUBLIC
GO
Теперь, допустим, нам нужно одно из полей сделать необязательным. Сколько нужно сделать изменений? Правильно, две. Первое — убрать Required атрибут в классе, второе — NOT NULL в SQL скрипте. Готовоо.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Ты говоришь о валидации непосредственно во время ввода, о валидации каждого введённого символа. Мне эта практика кажется крайне порочной как раз по причинам, которые ты описываешь. Формы, которые думают что они умней меня всегда раздражают. Валидация значений и их комбинаций должна делаться при сабмите формы. Во время ввода можно проверять только формат, типа ничего не давать пользователю вводить кроме цифр и т.п.
Боже упаси! Как ты мог так плохо обо мне подумать! Просто насколько я помню в винформах при подвязке свойств к контролам "сбрасывание" значений в свойства происходит по одному, соответственно, либо страна либо индекс будет присвоен первым, и проверить это нельзя. Но это бог с ним, издержки технологии...
IT>Что же касается первого вопроса об изменениях по всем уровням валидации, то здесь я видимо не совсем ясно выразился. Говоря "этот уровень повторяет все проверки предыдущего" я не имел ввиду дублирование кода, я имел ввиду его повторное использование. Например, имеем вот такой класс Address:
<skipped />
IT>Теперь, допустим, нам нужно одно из полей сделать необязательным. Сколько нужно сделать изменений? Правильно, две. Первое — убрать Required атрибут в классе, второе — NOT NULL в SQL скрипте. Готовоо.
Класс. Но тут как раз и происходит та проблема, о которой я говорил: ты можешь перевести объект в неконсистентное состояние. То есть легко сунуть ему новую страну, а потом сразу в БД.
Ладно, я приблизительно понял твою мысль. Спасибо.
Здравствуйте, Козьма Прутков, Вы писали:
КП>Класс. Но тут как раз и происходит та проблема, о которой я говорил: ты можешь перевести объект в неконсистентное состояние. То есть легко сунуть ему новую страну, а потом сразу в БД.
Сразу в бд неполучится, т.к. насколько я понимаю AddressService.AddAddress должен быть единтвенным доступным способом сохранить объект, а он делает валидацию.
Но проблему это все равно не решает, так как с объектом еще необходимо работать и программно (из бинзес логики). И когда я передаю такой объект, например, параметром в какую-нибудь функцию, то я хочу, чтобы он был в валидном состоянии. А проверять каждый раз — это лучше сразу застрелиться.
Поэтому лучше, чтобы объект был написан таким образом, чтобы не было возможности перевести его в невалидное состояние. Ведь именно для этого и придумана инкапсуляция и свойства с сеттерами, не так ли?
Таким образом получается, что для работы с формами лучше иметь бизнес объекты с:
— наличием конструктора с определенной сигнатурой, например, конструктора без параметров, чтобы форма (или другой сервис) могла без проблем создавать новые объекты
— полями (без сеттеров), чтобы форма могла присваивать значения в любой последовательности
— и функцией validate, которая вызывается формой или другими сервисами автоматически.
А для программной работы лучше иметь визнес объекты, написанные по всем правилам ООП:
— с такими конструкторами, какие необходимы логически
— со свойствами
— и т.д.
Получается противочечие .
Я вот пишу движок для всего этого (времени много, начальство одобряет). Есть свой язык, своя VM. И если представить, что можно реализовать любые экзотические конструкции в языке, специально для объявления и работы с бизнес объектами, какие-бы вы предпочли? Так, чтобы удобно было и для форм и для бизнес логики? Есть идеи? .
Здравствуйте, stalcer, Вы писали:
S>Получается противочечие .
Никакого противоречия нет. На разных уровнях разная бизнес-логика. И поэтому объект проходя по уровню либо меняет свой вид, или предлагает интерфейс, которым могут воспользоваться объекты бизнес логики нескольких уровней. Поэтому бизнес-объект и не делают сверх-навороченным.
S>Я вот пишу движок для всего этого (времени много, начальство одобряет). Есть свой язык, своя VM. И если представить, что можно реализовать любые экзотические конструкции в языке, специально для объявления и работы с бизнес объектами, какие-бы вы предпочли? Так, чтобы удобно было и для форм и для бизнес логики? Есть идеи? .
Бизнес-правила разные для форм и для бизнес-логики. Игорь хорошо это описал. Даже если ты описываешь операцию валидирования, многие операции можно выполнить только на 3 и 4 уровне. Если, конечно, тебе не хватает функциональности System.Data.DataSet.