16

当前方法

在 ASP.NET Web 表单应用程序(使用 Spring.NET 和 NHibernate)中,我们有一个聚合根(Person),其详细信息通过多个屏幕/页面捕获。Person实体在进入此工作流之前就存在,对 Person 对象图所做的所有更改都是原子的,因此只能在提交最终屏幕时刷新到数据库。

为了实现这一点,我们第一次使用 NHibernate 3.2 从数据库中(延迟地)将Person加载到第一页,然后在页面浏览过程中加载序列化的Person对象图并将其保存到 HTTP Session 变量。

从 HTTP 会话中检索出Person后,它与当前 NHibernate 会话处于分离状态,因此我们通过在当前会话上调用Update()方法重新连接,如下所示:

var sessionPerson = Session[PersonSessionName] as Person;
var currentSession = SessionFactory.GetCurrentSession();
currentSession.Update(sessionPerson);

注意:使用Lock()会抛出异常,提示“重新关联的对象有脏集合”。

重新连接后,我们可以按预期遍历对象图,从数据库中提取尚未加载到内存中的子实体的数据。

映射文件的子集

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="false" assembly="Domain" namespace=" TestApp.Domain">
  <class name="Person" table="Person">
    <id name="Id">
      <generator class="TestApp.CustomNHibernateHiLoGenerator, TestApp.Core" />
    </id>
    <property name="Name" not-null="false" />

    <bag name="PersonCountries" access="field.camelcase-underscore" cascade="all-delete-orphan">
      <key column="PersonId" foreign-key="FK_ PersonCountry_Person" not-null="true" />
      <one-to-many class="PersonCountry" />
    </bag>
  </class>

  <class name="Country" table="Country">
    <id name="Id">
      <generator class="TestApp.CustomNHibernateHiLoGenerator, TestApp.Core" />
    </id>
    ... No back reference to Person
  </class>
</hibernate-mapping>

领域

public class PersonCountry : Entity, ICloneable
{
    // No properties of note
}

public class Person : Entity, ICloneable
{
    public virtual string Name { get; set; }
    public virtual IEnumerable<PersonCountry> PersonCountries { get; set; }
    ... 
    // More Properties
}

刷新对数据库的更改

.. // Code-behind
PricingService.Save(ProductContext.Pricing, forceMerge: true);            


public class PricingService : IPricingService
{
   [Transaction]  // Spring.NET transaction
   public Pricing Save(Pricing pricing, bool forceMerge = false)
   {            
      if(forceMerge)
      {
         CurrentSession.Merge(entity);
      }
      else
      {
         CurrentSession.SaveOrUpdate(entity);
      }
   }
}

当需要刷新对数据库的所有更改时,只要我们只更改Name,更改就会按预期工作。但是,将新的Country项添加到Person会导致Merge()在一对多关系上的级联失败,并出现以下异常(奇怪的是,删除Country可以正常工作)。

NHibernate.StaleStateException: Batch update returned unexpected row count from update; actual row count: 0; Expected: 1

任何帮助将不胜感激。

4

1 回答 1

6

每个具有有效 ID 的实体都被视为持久实体,这就是它尝试在合并中更新它的原因,但因为它尚未保存但它失败了。session.Flush()之后调用session.Update()

于 2012-12-13T20:03:38.803 回答