Здесь сценарий:
- Веб-приложение ASP.NET MVC2
- Entity Framework 4 (чистый POCO, настраиваемый контекст данных)
- Шаблон хранилища
- Единица измерения работы
- Инъекция зависимостей
- Сервисный уровень посредника Контроллер → Репозиторий
Итак, в основном, все классные вещи.:)
Поток событий для основной операции пользовательского интерфейса ( "Добавление сообщения" ):
- Контроллер вызывает метод Добавить (сообщение) на уровне службы
- Звонки уровня обслуживания Добавить (T) в репозитории
- Репозиторий вызывает AddObject (T) в контексте пользовательских данных
- Контроллер вызывает Commit() на блоке работы
Теперь я пытаюсь выяснить, где я могу поместить мою проверку.
На этом этапе мне нужны два типа проверки:
- Простая независимая проверка POCO, такая как "почта должна иметь заголовок". Это кажется естественным подспорьем для аннотаций данных в POCO.
- Сложная проверка бизнеса, такая как "нельзя добавлять комментарий к заблокированному сообщению". Это невозможно сделать с помощью аннотаций данных.
Теперь, я читал "Программирование Entity Framework, второе издание" Джули Лерман (что отличное BTW), и я искал привязку к SavingChanges, чтобы выполнить проверку "последней минуты". Это было бы хорошим способом убедиться, что проверка всегда происходит всякий раз, когда я делаю "что-то" (добавление, изменение, удаление), но также немного поздняя IMO (поскольку элементы уже находятся в диспетчере состояний) - так что я могу сделать, если проверка не удалась, удалите их?
Я мог бы, конечно, сделать мой POCO реализовать интерфейс (скажем, "IValidatable" ) и вызвать метод на этом интерфейсе во время этого события.
Но это кажется "слишком поздно" для проверки бизнеса - это консенсус?
Я в основном ищу руководство здесь, я пытаюсь разработать повторно используемую интеллектуальную схему проверки сложной бизнес-логики, учитывая мою вышерасположенную архитектуру.
Другой кривый шар для вас - как вы знаете, POCO с EF означает, что POCO имеет все свойства в БД - поэтому у меня может быть свойство "PostID", с помощью get/set accessors (поскольку EF необходимо получить/установить эти свойства).
Но проблема в том, что "PostID" - столбец identity, так как я могу защитить поле от того, чтобы он был установлен в явном виде? Например, если я (по какой-либо причине) делает следующее:
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? Тогда как я могу справиться с сохранением? (так как это находится в Единице работы, а не в сервисном слое).
Итак, чтобы это не было вопросом "повсюду", вот мои вопросы:
- Простая проверка POCO - следует ли это делать с аннотациями данных? Плюсы/минусы/подводные камни?
- При каких обстоятельствах (если есть) мы должны подключаться к событию SavingChanges контекста данных EF, чтобы обеспечить проверку?
- Где я должен выполнять комплексную проверку бизнеса? В сервисе explicity или в методе POCO (который я могу позвонить из службы). Как создать интеллектуальную/многоразовую схему?
- Как мы можем "скрыть" автоматически сгенерированные свойства POCO от подделки?
Любые мысли будут оценены наиболее высоко.
Извините, если этот пост "слишком длинный", но это важная проблема, и она может быть решена разными способами, поэтому я хотел предоставить всю информацию для наилучшего возможного ответа.
Спасибо.
ИЗМЕНИТЬ
Ниже приведен полезный ответ, но я все еще (идеально) искал больше мыслей. Кто-нибудь еще?