如何捕获由Entity Framework 4触发的触发器中调用RAISERROR引发的SqlException?

8

我已经设置了Entity Framework来更新一个表格。更新会被一个instead-of触发器拦截,该触发器会调用RAISERROR:

CREATE TRIGGER mySchema.UpdateBusinessObjects
ON mySchema.BusinessObjects
INSTEAD OF UPDATE
AS
    RAISERROR(''test error from SQL'',16,1)
    RETURN

在我的存储库类中,我试图捕获由SQL中的RAISERROR生成的SqlException异常:
public void SaveBusinessObject(BusinessObject b) {
    try {
         repo.Entry(b).State = EntityState.Modified;
         repo.SaveChanges();
    } catch (SqlException ex) {
         // handle exception here
    }
}

问题在于C#没有捕获SqlException,它作为未处理的异常传递给调用者("SqlException was unhandled by user: test error from SQL")。看起来EF的SaveChanges()方法不知怎么把异常传递到我的try catch块之上。为了避免EF异常可能更通用的情况,我尝试将catch语句切换为catch (Exception ex),但仍然出现未处理的SqlException。我是否忽略了一些简单的东西?SaveChanges()方法存在什么问题?

尝试使用空的catch语句,只是为了看看会发生什么。 - Ignacio Soler Garcia
在Visual Studio的调试模式下,似乎会出现两个异常:第一个是“System.Data.SqlClient.SqlException”,没有被任何“catch()”类型语句捕获。第二个是“System.Data.Entity.Infrastructure.DbUpdateException”,被.NET捕获,并将前者作为InnerException。然而,只有后者会导致.NET崩溃 - 第一个被忽略了。难道前者来自外部进程,比如SQL服务器? - rocketmonkeys
4个回答

1

有两件事情:

  1. 如果您想让RAISERROR抛出SqlException,您需要将其严重性设置在10以上。严重程度为10及以下的错误是信息性错误,因此不会引发异常。

  2. 捕获EntityException或在常规异常的catch块中设置断点。在立即窗口中检查异常类型:ex.GetType();


1
我尝试在一个表上使用几乎与您相同的触发器,并尝试通过实体框架保存相应的(新)对象。从我所看到的,抛出的异常是System.Data.UpdateException类型而不是SqlException。内部异常是SqlException并包含您在触发器中引发的自定义消息,即“来自SQL的测试错误”。希望这可以帮助到您。

谢谢.. 问题是即使使用最基本的异常类型,我也无法捕获异常,因此无法深入挖掘并找出它是什么类型。你所说的“从你看到的”是什么意思? - user941238

0

我也曾经遇到过这个问题。

我在使用 MVC mini profiler 来测量查询时间,但发现一旦将其从项目中移除后,异常就能够被按照我的预期捕获。


0
我所知道的避免使用try catch来处理异常的唯一方法是在不同的线程中抛出异常。EF代码能否在不同的线程上执行?也许您可以在“异常”对话框中启用第一次机会的异常抛出。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接