13

Вот сценарий:Рекомендации по POCO Validation с ASP.NET MVC/Entity Framework

  • ASP.NET Web Application MVC2
  • Entity Framework 4 (Pure, контекст пользовательских данных Poco в)
  • Repository Pattern
  • Единица работы шаблон
  • Dependency Injection
  • Service Layer посредническую Controller -> Repository

Итак, в основном, все классные вещи. :)

Поток событий для основной работы пользовательского интерфейса ("Добавление Post"):

  1. контроллер вызывает Add (Post) метод на уровне услуг
  2. Service слой вызывает Add (T) на хранилище
  3. Repository вызовы AddObject (T) на пользовательском контексте данных
  4. контроллер вызывает Comm it() на единице работы

Теперь, я пытаюсь выяснить, где я могу проверить.

На данном этапе, мне нужно два типа проверки:

  1. Простые, независимо ПОКА проверка, такие как «пост должен иметь название». Это кажется естественным для Data Annotations на POCO.
  2. Сложная проверка бизнеса, такая как «невозможно добавить комментарий к заблокированному сообщению». Это невозможно сделать с помощью аннотаций данных.

Теперь, я читал «Программирование Entity Framework, Second Edition» Джули Лерман (которое отлично BTW), и искали в закреплять в SavingChanges случае для того, чтобы выполнить «в последнюю минуту» валидация , Это было бы хорошим способом убедиться, что валидация всегда происходит всякий раз, когда я делаю «что-то» (добавление, изменение, удаление), но это также немного поздняя IMO (поскольку элементы уже находятся в диспетчере состояний) - так что я могу делать, если проверка не удалась, удалить их?

Я мог бы, конечно, реализовать свой интерфейс POCO (скажем, «IValidatable») и вызвать метод на этом интерфейсе во время этого события.

Но это кажется «слишком поздно» для подтверждения бизнеса - это консенсус?

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

Другой кривой мяч для вас - как вы знаете, ПОКО с EF означает ПОКО имеют все свойства на БД - так что я мог бы иметь свойство «сообщения дан», с Get/Set аксессорах (как потребности EF чтобы получить/установить эти свойства).

Но проблема в том, что «Почтовый идентификатор» - это идентификатор , так как я могу защитить поле от того, чтобы быть установленным? Например, если я (по некоторым причинам) сделайте следующее:

var post = service.FindSingle(10); 
post.PostId = 10; 
unitOfWork.Commit(); 

Это будет бросать SqlException. Как я могу предотвратить это? Я не могу «спрятать» свойство (сделать его приватным или даже внутренним), поскольку POCO находятся в отдельной сборке в репозитории.

Примечание по проверке - я планирую создавать пользовательские исключения (исходя из Исключения). Поэтому, когда проверка не выполняется, мне нужно бросить эти исключения.

Таким образом, я могу закодировать что-то вроде этого на мой контроллер:

[HttpPost] 
public ActionResult AddPost(Post post) 
{ 
    try 
    { 
     IUnitOfWork uow = new UnitOfWork(); 
     postService.Add(post); 
     uow.Commit(); 
    } 
    catch(InvalidPostOperation ipo) 
    { 
     // add error to viewmodel 
    } 
} 

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

Таким образом, чтобы предотвратить это, чтобы быть «повсюду» вопрос, вот мои вопросы:

  1. Простая проверка ПОКО - это должно быть сделано с аннотациями данных? Плюсы/минусы/подводные камни?
  2. При каких обстоятельствах (если таковые имеются) мы должны подключаться к событию EF Data Context для подтверждения, чтобы связать его с SavingChanges?
  3. Где я должен выполнять комплексную проверку бизнеса? В службе explicity или метод на POCO (который я могу позвонить из службы). Как создать интеллектуальную/многоразовую схему?
  4. Как мы можем «спрятать» автогенерируемые свойства POCO от подделки?

Любые мысли были бы наиболее ценными.

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

Спасибо.

EDIT

Ниже ответ полезно, но я до сих пор (в идеале) ищет больше мыслей. Кто-нибудь еще?

+0

Слишком много вопросов в одном, но относительно № 3, имейте в виду, что проверка чувствительна к контексту (или основана на задачах). Заманчиво создать свойство 'IsValid' на вашем' Post', но где-то вдоль строки вам понадобится 'IsValidForDraft', который используется для сохранения черновиков, которым не хватает определенной информации. И, конечно же, POCO не должен знать концепцию «проекта публикации». :) – bzlm

+1

Да ладно, почему голосование закрывается? Я понимаю его «длинный» вопрос. Но вот почему у меня есть 4 вопроса в конце. Просто потому, что я спрашиваю 4 вещи, не означает, что это Q заслуживает голосования, чтобы закрыться за то, что он «слишком расплывчатый». Все 4 q относятся к одной теме. – RPM1984

+0

@bzlm - да, ваша точка зрения. :) – RPM1984

ответ

1
  1. Хорошо, как вы сказали, DataAnnotations не подходит для всех ситуаций. Минусы - это, в основном, сложная валидация (множественное свойство и многократное свойство другого объекта).
  2. Если бы я был вами, я бы оставил работу по проверке бизнеса/домена из уровня данных (EF) максимально возможной. Если есть сценарий проверки уровня данных, то в порядке (например, проверка сложных отношений между родителями и дочерними элементами - это чисто материал базы данных).
  3. Да, комплексная проверка бизнеса должна выполняться на уровне обслуживания или в объектах модели (в комплекте с помощью частичных классов или с использованием метода наследования: интерфейсы/производные классы). Там спорят об этом между людьми ActiveRecord, людьми с шаблонами репозитория и людьми с DDD, но пойдите с тем, что работает для вас, просто и обеспечит быстрое развертывание и обслуживание недорогих приложений. Это простой example of how you might attach more complex validation to domain objects, но по-прежнему совместим с интерфейсом DataAnnotations и, таким образом, является «MVC friendly».
  4. Хороший вопрос. -не я не нашел решение, на 100% доволен. Я играл с идеей частных сеттеров, и это не здорово. Быстро прочитайте об этом summarized Evans DDD book. Это замечательное быстрое чтение, и это может дать некоторое представление о цели и различии между объектами модели и объектами Value. Именно здесь я думаю, что дизайн объекта будет смягчать проблемы, связанные с тем, что у вас есть свойство «подделывать» (как вы его называете), но не фиксируя видимость свойства. То есть другое решение могло бы быть в другом месте. Надеюсь это поможет.
+0

Спасибо, я загружаю и смотрю на эту книгу. Я достаточно доволен базовыми аннотациями данных в POCO, более заинтересованными в комплексной проверке. Этот пример очень интересный (и умный) будет учитывать это. С 4) не может сделать его закрытым.Как я уже сказал, POCO находятся в одной сборке (нет EF ref), а EF/repo находится в другом. Поэтому он должен быть общедоступным. Я думал, что есть способ сказать, что «сеттер доступен только для конкретной сборки». Дело в том, что я хочу, чтобы репозиторий «установил» доступ к свойству PostId. – RPM1984

+0

Этот модификатор видимости, который вы думаете о 'Internal', и это только для классов, я думаю (98%?). Не свойства. Извините, я не мог больше помочь с №4, поэтому я предложил книгу. У меня такие же проблемы. Это может помочь одна вещь? Вы считали, что не имеете его в отдельной сборке? Раньше у меня были все мои решения с отдельными проектами Data, Service, Test и MVC/Web, пока я не решил, что слишком много накладных расходов на обслуживание. Теперь у меня есть Data/Model/Service все в одном проекте/сборке. Легче для меня, и я все равно могу получить то же логическое разделение, которое мне нужно. Попробуй. –

+0

Я мог ошибаться, [вы можете установить член типа в 'Internal'] (http://msdn.microsoft.com/en-us/library/7c5ka91b.aspx) –

1

Эй, возможно, немного поздно, но здесь идет так или иначе ...

Все зависит от вашей архитектуры, то есть ли там логическое Разделение, в вашем приложении: пользовательский интерфейс, Service Layer, Repository Layer. Если вы подключаетесь к событию «Сохранить», как именно это будет сделано? Из того, что я заметил, вы бы назвали репозиторий Layer for Persistance только правильно? Однако вы подключаетесь к событию сохранения, давая контроль обратно на уровень обслуживания/бизнес-уровень, чем бы то ни было, заставляя сохранить заново?

Я лично считаю, что уровень обслуживания/бизнес-уровень должен позаботиться об этом в завершении, тогда скажите, эй mr repo layer -> сохранить этот объект.

Что касается валидации, то с пользовательским интерфейсом следует использовать аннотации данных, поэтому простая валидация, такая как [Обязательный] и т. Д., Это будет полезно при проверке на стороне клиента, но сложная бизнес-логика или комплексная проверка должны быть подключены к служебному уровню/бизнес-уровень, таким образом, он может использоваться повторно для всех объектов/объектов/POCOS и т. д.

Что касается предотвращения того, что некоторые частные поля не подделаны ... только разрешите вашему уровню обслуживания/бизнес-уровню фактически установить объект, который (да, я имею в виду :) ...) ручное кодирование, я чувствовал, что это самый безопасный вариант для меня в любом случае, так как я буду просто делать:

var updatedpost = _repo.GetPost(post.postid); 
updatedpost.comment = post.comment; 
updatedpost.timestamp = datetime.now; 

Вид расточительного, но в этом случае ваш слой buseinss получает контроль, однако это только мой опыт. Возможно, я ошибаюсь, я много читал в привязке к модели, validaiton и других материалах, однако, похоже, были случаи, когда вещи никогда не работают ожидается, например [Обязательный] атрибут (см. Статью Брэда Уилсона).

Смежные вопросы