Рекомендации по проверке POCO с ASP.NET MVC / Entity Framework - PullRequest
13 голосов
/ 07 октября 2010

Вот сценарий:

  • Веб-приложение ASP.NET MVC2
  • Entity Framework 4 (чистый POCO, пользовательский контекст данных)
  • Шаблон репозитория
  • Единица работы
  • Внедрение зависимостей
  • Контроллер-посредник сервисного уровня -> Репозиторий

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

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

  1. вызовы контроллера метод Add (Post) на уровне обслуживания
  2. Вызовы сервисного уровня Добавить (T) в хранилище
  3. Вызовы репозитория AddObject (T) в пользовательском контексте данных
  4. вызовы контроллера Commit () на единицу работы

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

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

  1. Простая, независимая проверка POCO, такая как «сообщение должно иметь заголовок». Это выглядит естественным для аннотаций данных на POCO.
  2. Сложная проверка бизнеса, например "невозможно добавить комментарий к заблокированной записи". Это не может быть сделано аннотациями данных.

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

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

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

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

Еще один изогнутый шар для вас - как вы знаете, POCO с EF означают, что POCO имеют все свойства в БД - поэтому у меня может быть свойство "PostID" с аксессорами get / set ( как EF нужно получить / установить эти свойства).

Но проблема в том, что "PostID" - это столбец удостоверения , так как я могу защитить поле от установки расширенного набора? Например, если я (по какой-то причине) сделаю следующее:

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
   }
}

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

Итак, чтобы этот вопрос не был «повсеместным», вот мои вопросы:

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

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

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

Спасибо.

EDIT

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

Ответы [ 2 ]

1 голос
/ 27 января 2011

Эй, возможно, немного поздно, но все равно все пойдет ...

Все зависит от вашей архитектуры, т. Е. Есть ли логическое разделение в вашем приложении: пользовательский интерфейс, уровень службы, уровень хранилища.Если вы подключаетесь к событию Save, как именно это будет сделано?Из того, что я заметил, вы бы правильно назвали хранилище Layer for Persistance?Тем не менее, вы цепляетесь за событие сохранения, возвращая контроль сервисному уровню / бизнес-уровню, как бы то ни было, затем принудительно сохраняете право?

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

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

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

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

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

1 голос
/ 07 октября 2010
  1. Ну, как вы сказали, DataAnnotations подходит не для всех ситуаций.Минусы - это, в основном, сложная проверка (несколько объектов и несколько объектов).
  2. Если бы я был вами, я бы максимально исключил проверку бизнеса / домена из уровня данных (EF).Если есть сценарий проверки на уровне данных, то все в порядке (например, проверка сложных родительских / дочерних отношений - это чисто БД).
  3. Да, комплексная проверка бизнеса должна проводиться на уровне обслуживания или в модели.Объекты (прикрепленные, через частичные классы или некоторый подход наследования: интерфейсы / производные классы).Есть споры об этом между людьми из ActiveRecord, людьми из Repository Pattern и людьми из DDD, но выберите то, что работает для вас, просто и позволит быстрое развертывание и низкую стоимость обслуживания приложений.Это простой пример того, как вы можете прикрепить более сложную проверку к доменным объектам , но при этом он все еще совместим с интерфейсом DataAnnotations и, таким образом, является "дружественным к MVC".
  4. Хороший вопрос.- пока я не нашел решения, которым я на 100% доволен.Я играл с идеей частных сеттеров, и это не здорово.Быстро прочитайте эту обобщенную книгу Эванса DDD .Это отличное быстрое чтение, и оно может дать некоторое представление о цели и разнице между объектами модели и объектами значений.Вот где я думаю, что объектный дизайн уменьшит проблемы, которые возникают у вас с изменением свойства (как вы его называете), но без исправления видимости свойства.То есть другое решение может лежать в другом месте.Надеюсь, это поможет.
...