entity-framework - 在 Entity Framework 和存储库模式中处理数据库异常的位置

标签 entity-framework exception error-handling repository

您将如何设计此方案(使用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项目中,驻留存储库方法(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方法如下所示:
public string Commit()
{
    string errorMessage = string.Empty;

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

    return errorMessage;
}

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

假设插入带有以下数据的用户记录:
(UserId,....,Email,...)
1, ... , person1@mail.com , ...
2, ... , person1@mail.com , ...

很明显,这将导致DbUpdateException发生。当然,可以将其捕获并传播到应显示的位置。我觉得这种设计是完全错误的:
  • 验证应分别针对每个属性进行:对于字段值的唯一性,这也不应该成立吗?这是否意味着我必须将DAL和MODEL合并到一个项目中?
  • 我将如何处理由于违反表A中的fieldA,表B中的fieldB和表C中的fieldC的唯一性而引起的错误?使用通用错误消息“该值已存在”或“违反唯一性”不是很说明性!
  • 我是否应该插入另一个负责处理此类错误的项目-业务层?
  • 我应该处理更新哪个(ASP.NET MVC) Action / Controller 中的错误吗?
  • 如何在多语言应用程序中处理正确的错误消息?
  • 最佳答案

    我正面临相同的情况,目前正在 Controller 中处理异常。

    考虑以下实体:

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

    所有这些操作都返回到同一 View ,并向用户显示验证错误,如下所示:

    我不确定这有多“合适”,但是我目前无法想到一种更好的方法来处理(例如,即使我在DbContext派生类中捕获了此问题并抛出了更具体的异常,我仍然需要处理它在 Controller 中以便在运行时对其执行任何操作)。

    我也不确定是否需要检查内部异常。我修改了this帖子中的代码,该帖子主要在内部异常中检查SqlException并检查错误号(在这种情况下为2627,这是唯一的键约束),然后再将错误号报告给用户。如果SQL错误号是其他内容,则会显示一般错误消息。

    更新:

    现在,我在域服务类中处理异常,该类是example shown here的派生类,它允许我在 Controller 外部处理异常。

    关于entity-framework - 在 Entity Framework 和存储库模式中处理数据库异常的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9817786/

    相关文章:

    c# - 将 List<X> 转换为 DBDataReader

    java - 未处理的异常类型 Java InstantiationException

    exception - EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)与 dataTaskWithUrl

    parsing - 使用 yacc 时,如何告诉 yyparse() 要停止解析?

    c# - C#如何检查是否已引发异常

    sql - 关于 Entity Framework 的思考

    c# - Linq 包括集合中的子项

    database - heroku运行rails db :migrate Running rails

    entity-framework - 按分页分组(跳过)

    Java-DOM-Parser : Exception on Transformer. 转换