Sav*_*dis 7 error-handling entity-framework exception repository
您将如何设计此场景(使用Entity Framework 4.1,Code First和存储库模式):Visual Studio解决方案包含以下项目
Solution
|-Web Application Project
|-DAL Project
|-Model Project
Run Code Online (Sandbox Code Playgroud)
所以在模型项目中有各种类.假设我们在那里有一个名为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; }
....
}
Run Code Online (Sandbox Code Playgroud)
在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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的工作单元类的Commit方法如下所示:
public string Commit()
{
string errorMessage = string.Empty;
try
{
Database.Commit();
}
catch (DbUpdateException updExc)
{
errorMessage = updExc.InnerException.Message;
}
return errorMessage;
}
Run Code Online (Sandbox Code Playgroud)
正如你看到的,我处理DbUpdateException的Commit()工作类股的方法; 这意味着对于可能导致更新错误的每个类,这将在此处理.
假设使用以下数据插入用户记录:
(UserId,....,Email,...)
1, ... , person1@mail.com , ...
2, ... , person1@mail.com , ...
Run Code Online (Sandbox Code Playgroud)
很明显,这会导致发生DbUpdateException.当然,这可以被捕获并传播到它应该出现的地方.我觉得这个设计是完全错误的:
每个属性应单独进行验证:对于字段值的唯一性,这不应该也是如此吗?这是否意味着我必须将DAL和MODEL合并到一个项目中?
如何处理由于表A中的fieldA,表B中的fieldB,表C中的fieldC违反fieldA的唯一性而导致的错误?使用一般错误消息"值已存在"或"唯一性违规"不是很具描述性!
我应该插入另一个负责此类错误处理的项目 - 业务层吗?
我应该处理执行更新的(ASP.NET MVC)操作/控制器中的错误吗?
如何在多语言应用程序中处理正确的错误消息?
我面临同样的情况,目前我正在处理控制器中的异常。
考虑以下实体:
public class Part
{
public int Id { get; set; }
public string Number { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我在数据库中的“数字”字段上设置了唯一约束,因此如果输入重复值,将引发异常。这就是我处理异常的方式:
[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);
}
Run Code Online (Sandbox Code Playgroud)
所有这一切都是返回到相同的视图并向用户显示验证错误,如下所示:

我不确定这有多“正确”,但我目前想不出更好的方法来处理这个问题(例如,即使我在DbContext派生类中发现了这个问题并抛出了一个更具体的异常,我仍然需要在控制器以便在运行时对其执行任何操作)。
我也不确定是否需要检查内部异常。我修改了这篇文章中的代码,它基本上检查SqlException内部异常中的 a 并在向用户报告之前检查错误号(在本例中为 2627 是唯一键约束)。如果 SQL 错误号是其他内容,则会显示一般错误消息。
更新:
我现在处理域服务类中的异常,该类是此处显示的示例的派生类,它允许我处理控制器外部的异常。