如何告诉NHibernate触发器会更新另一个表

本文关键字:更新 另一个 触发器 何告诉 NHibernate | 更新日期: 2023-09-27 18:01:27

在使用NHibernate时,我刚刚得到了一个TooManyRowsAffectedException,我已经看到了通过注入一个不同的批处理程序来解决这个问题的方法,比如这里的TooMany RowsAffetedException带有加密的触发器,或者通过修改数据库中的触发器以使用SET NOCOUNT ON(我不能使用这个,因为我不想修改数据库——它非常复杂,有100多个表都关联在一起,我不想因为其他应用程序使用它而搞砸它(。我不明白的是为什么会发生这种异常。我所做的就是,我有一个Sample对象,它有几个我要检查的值,如果这些值符合给定的标准,我将Sample.IsDone行设置为"Y"(在我们的数据库中,所有布尔值都用字符Y或N表示(。代码很简单:

IQueryable<Sample> samples = session.Query<Sample>().Where(s =­­> s.Value == desiredValue);
foreach (Sample sample in samples)
{
  sample.IsDone = 'Y';
  session.Flush(); // Throws TooManyRowsAffectedException
}
session.Flush(); // Throws TooManyRowsAffectedException

Flush调用抛出的是我把它放在循环内部还是外部。是我做错了什么,还是只与数据库的制作方式有关?在Flush((之前,我曾尝试对样本调用SaveOrUpdate((,但它没有改变任何内容。我知道我可以解决这个例外,但我更希望了解问题的根源。

注意:在异常中,它告诉我实际行数为2,预期为1。为什么我只更改了一行,却更新了两行?

谢谢大家的帮助!

编辑:

我发现这是因为数据库中有一个触发器在更新样本时更新Container表中的一行(Containers Containers Samples(。有没有一种方法可以配置NHibernate,以便它知道这个触发器并期望更新正确数量的行?

如何告诉NHibernate触发器会更新另一个表

我发现的唯一解决方案显示在下面使用Fluent NHibernate的代码片段中。它很难看,因为很难将SQL编码到映射中,但它确实有效。Check属性设置为None,以便忽略计数。我不知道你是否可以使用直接的HBM文件来实现这一点,但可能有一种方法。如果NHibernate(或Fluent NH(中有一个配置选项,可以设置预期的更新行数,也可以在需要时忽略它,那就太好了。

public class OrderMap : ClassMap<Order>
{
    public OrderMap()
    {
        Id(c => c.Id, "order_id").GeneratedBy.Native();
        Table("order");
        Map(c => c.GroupId, "group_id");
        Map(c => c.Status, "status");
        Map(c => c.LocationNumber, "location");
        SqlInsert("insert into order (group_id, status, location) values (?, ?, ?)").Check.None();
        SqlUpdate("update order set group_id = ?, status = ?, location = ? where order_id = ?")).Check.None();
        SqlDelete("delete order where order_id = ?").Check.None();
    }
}

编辑:对于那些不知道Fluent NHibernate或喜欢手工生成HBM文件的不幸的人来说,以下是这个示例映射的HBM文件:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Your.DomainModel.Entities.Order, Your.DomainModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="order">
    <id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="order_id" />
      <generator class="identity" />
    </id>
    <property name="GroupId" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="group_id" />
    </property>
    <property name="Status" type="System.Int16, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="status" />
    </property>
    <property name="LocationNumber" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="loc_num" />
    </property>
    <sql-insert check="none">insert into order (group_id, status, location) values (?, ?, ?)</sql-insert>
    <sql-update check="none">update order set group_id = ?, status = ?, location = ? where order_id = ?</sql-update>
    <sql-delete check="none">delete order where order_id = ?</sql-delete>
  </class>
</hibernate-mapping>

使用探查器检查执行的sql。anjlab sql探查器总是帮我搞定。

在那之后,检查一下你的桌子上是否有触发器——也许它们造成了一些麻烦。

编辑

你应该像这里一样改变你的触发器:http://www.codewrecks.com/blog/index.php/2009/03/25/nhibernate-and-toomanyrowsaffectedexception/

您无法告诉NHibernate触发器更新了数据库中的其他实体,只能像Sixto Saez在回答中显示的那样忽略它。但是,您可以使用EventListeners在代码中执行触发器操作。或者,如果更新对事务的其余部分无关紧要,则在触发器开始时将set NOCOUNT设置为ON,在触发器结束时将set NO COUNT设为OFF。