Где обрабатывать исключения БД в Entity Framework и шаблоне хранилища - PullRequest
7 голосов
/ 22 марта 2012

как бы вы спроектировали этот сценарий (используя Entity Framework 4.1, Code First и шаблон репозитория): решение Visual Studio содержит следующие проекты

Solution
|-Web Application Project
|-DAL Project
|-Model Project

Таким образом, в модельном проекте есть различные классы.Предположим, у нас есть класс с именем User со следующим определением (урезанным):

public class User{

    [Key]
    public int UserId { get; set; }

    ....

    //this property has a unique constraint created in a custom DB Initializer class
    public string email { get; set; }

    ....
}

В проекте DAL находятся методы репозитория (Insert, Update и т. Д.), А также класс Initializer:

public class MyDatabaseInitializer : IDatabaseInitializer<MyDatabase>
{
    public void InitializeDatabase(MyDatabase context)
    {
        try
        {
            if (!context.Database.Exists())
            {
                context.Database.Create();
                context.Database.ExecuteSqlCommand(
                    "ALTER TABLE Users ADD CONSTRAINT uc_Email UNIQUE(Email)");
            }
        }
        catch (Exception ex)
        {
            throw ex.InnerException;
        }
    }
}

Метод Commit моего класса Unit of Work выглядит следующим образом:

public string Commit()
{
    string errorMessage = string.Empty;

    try
    {
        Database.Commit();
    }
    catch (DbUpdateException updExc)
    {                                 
        errorMessage = updExc.InnerException.Message;            
    }                       

    return errorMessage;
}

Как вы видите, я обрабатываю DbUpdateException в методе Commit() в Unit of Workучебный класс;это означает, что для каждого класса, который может вызвать ошибку обновления, это будет обработано здесь.

Предположим, кто-то вставляет записи пользователя со следующими данными:

(UserId,....,Email,...)
1, ... , person1@mail.com , ...
2, ... , person1@mail.com , ...

Очевидно, что этовызовет исключение DbUpdateException.Конечно, это можно поймать и распространить в том месте, где оно должно появиться.У меня такое ощущение, что этот дизайн совершенно неправильный:

  1. Проверка должна выполняться для каждого свойства в отдельности: не должно ли это быть верно и для уникальности значений поля?Означает ли это, что мне нужно объединить DAL и MODEL в один проект?

  2. Как бы я обрабатывал ошибки, вызванные нарушением уникальности для поля A в таблице A, поля B в таблице B,поле C в таблице C?Использование общего сообщения об ошибке «Значение уже существует» или «Нарушение уникальности» не очень наглядно!

  3. Должен ли я вставить еще один уровень Project-Business, который заботится о такой обработке ошибок?

  4. Должен ли я обрабатывать ошибки в (ASP.NET MVC) Action / Controller, который выполняет обновление?

  5. Как обработать правильную ошибкусообщение в многоязычном приложении?

1 Ответ

4 голосов
/ 12 августа 2012

Я сталкиваюсь с той же ситуацией, и в данный момент я обрабатываю исключение в моем контроллере.

Рассмотрим следующую сущность:

public class Part
{
    public int Id { get; set; }
    public string Number { get; set; }
}

У меня установлено уникальное ограничение наполе «Число» в базе данных, поэтому при вводе дублирующего значения будет выдано исключение.Вот как я обрабатываю исключение:

[HttpPost]
public ActionResult Create(Part part)
{
    if (ModelState.IsValid)
    {
        try
        {
            db.Parts.Add(part);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch (DbUpdateException e)
        {
            SqlException s = e.InnerException.InnerException as SqlException;
            if (s != null && s.Number == 2627)
            {
                ModelState.AddModelError(string.Empty,
                    string.Format("Part number '{0}' already exists.", part.Number));
            }
            else
            {
                ModelState.AddModelError(string.Empty,
                    "An error occured - please contact your system administrator.");
            }
        }
    }
    return View(part);
}

Все, что он делает, это возвращает к тому же представлению и отображает для пользователя ошибку проверки следующим образом:

enter image description here

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

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

Обновление:

Теперь я обрабатываю исключения в классе обслуживания домена, который является производным от пример, показанный здесь , который позволяет мне обрабатывать исключение за пределами контроллера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...