【问题标题】:Where to handle DB exceptions in Entity Framework and repository pattern在实体框架和存储库模式中处理数据库异常的位置
【发布时间】:2012-03-22 07:03:55
【问题描述】:

您将如何设计此场景(使用 Entity Framework 4.1、代码优先和存储库模式): 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 项目中驻留存储库方法(插入、更新等)以及 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 方法如下所示:

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

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

    return errorMessage;
}

如您所见,我正在处理 Unit of Work 类的 Commit() 方法中的 DbUpdateException;这意味着对于每个可能导致更新错误的类,都将在此处处理。

假设使用以下数据插入用户记录:

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

很明显,这将导致 DbUpdateException 发生。当然,这可以被捕获并传播到它应该出现的地方。我感觉这个设计是完全错误的:

  1. 应分别对每个属性进行验证:字段值的唯一性难道不应该如此吗?这是否意味着我必须将 DAL 和 MODEL 合并到一个项目中?

  2. 如何处理因违反表 A 中的字段 A、表 B 中的字段 B、表 C 中的字段C 的唯一性而导致的错误?使用通用错误消息“值已存在”或“违反唯一性”不是很具有描述性!

  3. 我是否应该插入另一个负责此类错误处理的项目业务层?

  4. 我应该处理更新的 (ASP.NET MVC) Action/Controller 中的错误吗?

  5. 如何在多语言应用程序中处理正确的错误消息?

【问题讨论】:

    标签: entity-framework exception error-handling repository


    【解决方案1】:

    我面临同样的情况,目前我正在处理我的控制器中的异常。

    考虑以下实体:

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

    所有这一切都是返回到同一个视图并向用户显示验证错误,如下所示:

    我不确定这有多“正确”,但我目前想不出更好的方法来处理这个问题(例如,即使我在我的 DbContext 派生类中发现了这个并抛出了一个更具体的异常,我也会仍然需要在控制器中处理它,以便在运行时对其执行任何操作)。

    我也不确定是否需要检查内部异常。我修改了this 帖子中的代码,该帖子基本上检查内部异常中的SqlException,并在将错误号报告给用户之前检查错误号(在本例中为 2627,这是一个唯一键约束)。如果 SQL 错误编号是其他内容,则会显示一般错误消息。

    更新:

    我现在在域服务类中处理异常,它是 example shown here 的派生类,它允许我在控制器之外处理异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多