NHibernate使用自定义sql-insert vs catch程序引发异常并引出params

时间:2012-01-30 21:31:03

标签: sql-server nhibernate

我通过过程调用映射了带有自定义sql(插入,删除,更新)的类。但是,我注意到当我的插入过程无法引发异常时,来自NHibernate的GenericAdoException没有从过程中引发我的消息。

但是,删除和更新过程中所有引发的异常都很好,只有插入过程没有捕获它的异常消息。

当我们使用“本机”生成器将id与自定义sql结合使用时,这是NHibernate 3.2.4的限制还是错误?

我正在寻找从这些过程中获取一些参数的方法,比如每个事件的时间戳(插入,删除和更新),时间戳在过程中生成。

EDIT:OUT PARAMs - 我在属性映射选项中找到了“generated”选项,我们可以要求NHibernate从程序中获取参数。这意味着这些属性具有genarated值。所以我尝试使用generated =“always”并适用于插入,更新和删除操作。示例:<property name="MyProp" generated="always"/>

1 个答案:

答案 0 :(得分:0)

我发现当您使用ExecuteReader()运行这些存储过程时,sql server驱动程序不会将存储过程引发的消息放入SqlException中。另一方面,NHibernate使用ExecuteReader()执行自定义sql-insert(我对其源代码进行了重新编写),我认为在使用本机映射时获取密钥是正确和必要的(或者身份),我的情况。

好吧,现在该怎么办?我发现(很难找到)SqlConnection有一个名为&#34; InfoMessage&#34;的事件。您可以在其中接收(捕获)从存储过程发送的所有消息(raiserror)。现在,这有可能“赶上”#34;这些消息,但是当我们插入session.save()时,如何让它们穿过NHibernate核心并被我们的应用程序接收?

尽管我们有权访问会话,因此对于连接(SqlConnection),消息已经丢失,因为它们仅在事件发生之前被分配给事件SqlConnection.InfoMessage的代理接收。

为了解决这个问题,我尝试了两种方法:

  • 在第一个中,我投射了一种在DriverConnectionProvider.GetConnection()内注册委托的方法,这个委托会将消息存储在线程上下文中,并将其与连接相关联,因此这些消息可以在以后获取。
  • 在第二个和所选择的一个中,我实现了IDbConnectionIDbCommand包裹SqlConnectionSqlCommand(但我认为NHibernate有一个错误,因为在有些地方它引用了DbConnection而不是IDbConnection - 就像在ManagedProviderConnectionHelper中一样,所以我不得不从DbConnection和DbCommand扩展而来。

在我的CustomSqlConnection中,我注册了委托并存储了这些消息供以后使用。 这很有效!作为独立驱动程序(ADO)作为NHibernate驱动程序工作。

这个想法是:

    public class CustomSqlConnection : DbConnection, IDbConnection {
        private SqlConnection con;
        private StringBuilder str = new StringBuilder(0);

        public CustomSqlConnection() {
            con = new SqlConnection();
            con.InfoMessage += OnInfoMessage;
        }

        private void OnInfoMessage(object sender, SqlInfoMessageEventArgs e) {
            if (str.Length > 0) {
                str.Append("\n");
            }
            str.Append(e.Message);
        }

        public string FetchMessage() {
            string msg = Message;
            str.Clear();

            return msg;
        }

        ...
        ...
    }

编辑:艰难的一步是从DdConnection和Dbcommand实现所有操作,修复对sql实例的调用(查看上面的字段con),所以:

        ...
        public override void Open() {
            con.Open();
        }
        ...