我正在尝试捕获EF可能在一个地方抛出的所有SQLExceptions(连接错误,超时等)。我在DI中使用了一个工作模式单元,所以没有var using = context
例如。在业务逻辑周围使用.Single
或.ToList
等调用。
我是否可以覆盖或注入任何类别的钩子或事件来执行此操作?
答案 0 :(得分:0)
假设您的工作单元最终调用DbContext.SaveChanges()
,您可以使用try-catch包装此调用。
另一个需要开发团队遵守规则的选项是在基础BL类中添加两个方法:IList<T> MaterializeList<T>(IQueriable<T> query)
和T MaterializeSingle<T>(IQueriable<t> query)
,它们看起来像这样:
protected IList<T> MaterializeList<T>(IQueriable<T> query) {
try {
return query.ToList();
}
catch {
//your error handling code here
}
}
和
protected T MaterializeSingle<T>(IQueriable<t> query) {
try {
return query.FirstOrDefault();
}
catch {
//your error handling code here
}
}
然后始终使用这些方法实现。
作为旁注,我尝试在我的数据访问层中保留LINQ to Entities查询,使业务逻辑层不知道数据访问技术。
答案 1 :(得分:0)
有一点工作要做,但这会对你有所帮助:
使用假上下文封装您DbContext
并隐藏您的DbSets
。您构建了一个新的上下文,它将成为业务逻辑的上下文。这个不能访问DbSets
,它向用户显示自定义dbSet。主要工作是构建伪上下文,它需要在真正的dbSet上使用所有方法。
/// <summary>
/// This sould no be used anywhere except in MyDbContext2
/// </summary>
public class MyDbContext : DbContext
{
public DbSet<SomeTableClass> SomeTable { get; set; }
}
/// <summary>
/// This will be your context in the business-logic
/// </summary>
public class MyDbContext2
{
private MyDbContext realDb;
public MyDbContext2(string conStr)
{
realDb = new MyDbContext();
}
public MyDbSet<SomeTableClass> SomeFakeTable { get; set; }
}
/// <summary>
/// Fake-set with logging
/// </summary>
/// <typeparam name="T"></typeparam>
public class MyDbSet<T> where T : class
{
private DbSet<T> dbSet;
public MyDbSet(DbSet<T> realDbSet)
{
this.dbSet = realDbSet;
}
public List<T> ToList()
{
try
{
return dbSet.ToList();
}
catch (Exception e)
{
// Do some logging..
throw;
}
}
public T SingleOrDefault()
{
try
{
return dbSet.SingleOrDefault();
}
catch (Exception e)
{
// Do some logging..
throw;
}
}
}
一个好主意是重命名你DbContext
并引入一个旧名称的假名。这样,Visual Studio将向您显示必须实现的方法。