对象引用未保存的瞬态实例问题

时间:2011-03-15 03:04:40

标签: .net nhibernate hibernate

我有一个新员工的员工输入屏幕,提交后会被员工模型绑定器拦截。员工拥有“业务部门”和“覆盖业务部门”。覆盖业务部门是最近添加的,是我的问题的原因。

以下是部分员工映射:

 <class name="Employee" table="Employee">
    <id name="Id" column="id">
      <generator class="native" />
    </id>
    ...
    <many-to-one name="BusinessUnit" class="BusinessUnit" column="businessUnitId" />
    <many-to-one name="OverrideBusinessUnit" class="BusinessUnit" column="overrideBusinessUnitId" not-null="false" />
    ...
   </class>

以下是业务部门映射:

<class name="BusinessUnit" table="BusinessUnit" lazy="true">
    <id name="Id" column="id">
        <generator class="native" />
    </id>
    <property name="Description" column="description"/>
    <many-to-one name="guidelineApprover" class="Employee" column="guidelineApproverId" cascade="none" fetch="join" access="field" />
    <many-to-one name="increaseApprover" class="Employee" column="increaseApproverId" cascade="none" fetch="join" access="field" />
 </class>

在提交表单后的员工模型绑定器中,我使用NHibernate从数据库中获取业务单位和覆盖业务单位。这是代码:

从模型绑定器中的数据库中获取业务单位:

   string attemptedBusinessUnitId = valueProvider.GetValue(key).AttemptedValue;
   Int32.TryParse(attemptedBusinessUnitId, out businessUnitId);
   employee.BusinessUnit = businessUnitRepository.Get(businessUnitId);
   modelState.SetModelValue(key, valueProvider.GetValue(key));

从模型绑定器中的数据库中获取覆盖业务单位:

    string attemptedOverrideBusinessUnitId = valueProvider.GetValue(key).AttemptedValue;
    Int32.TryParse(attemptedOverrideBusinessUnitId, out overrideBusinessUnitId);
    employee.OverrideBusinessUnit = businessUnitRepository.Get(overrideBusinessUnitId);
    modelState.SetModelValue(key, valueProvider.GetValue(key));

我当前的提取模式设置为“提交”。我的问题是,在我多次添加“覆盖业务单元”并尝试执行employeeRepository.Save(employee)后,我开始收到以下错误:

    object references an unsaved transient instance - save the transient instance before flushing. 
Type: BusinessUnit, Entity: BusinessUnit

如果我在这个字段上设置cascade =“all”,我只是得到另一个类似的异常,但是需要保存Employee类型的瞬态实例,实体EmployeeEmpty。任何人都可以通过查看代码片段告诉我如何避免这种异常(最好不涉及级联)?

编辑:

employeeRepository.Save(employee)只调用session.SaveOrUpdate(employee)。所以我要做的就是在分配给员工之后保存我从数据库中检索到的两个业务单位字段。

2 个答案:

答案 0 :(得分:1)

对不起。我想到了。实际上,Employee类中的BusinessUnit属性存在问题。我正在使用空对象模式,因此我收到此错误,因为NHibernate试图保存类型为“BusinessUnit.Empty”的临时对象。这是由于我的代码中的错误导致无法在BusinessUnit.Empty和null之间正确转换。无论如何,谢谢你的帮助。

这是我在实现null对象模式时使用的方法。首先在映射文件中的NHibernate属性上设置access =“field”。这将允许NHibernate从私有变量而不是公共属性中读取值。 e.g。

<many-to-one name="businessUnit" class="BusinessUnit" column="businessUnitId" cascade="none" access="field" />

然后在你的课堂上做这样的事情:

private BusinessUnit businessUnit;
public virtual BusinessUnit BusinessUnit 
{
    get
    {
        if(businessUnit == null)
            return BusinessUnit.Empty;

        return businessUnit;
    }
    set { 
        if (value == BusinessUnit.Empty)
            value = null;

        businessUnit = value;
    }
}

如您所见,私有变量永远不会被赋值为BusinessUnit.Empty。 NHibernate总是会看到值“null”。这种模式解决了我的问题。希望它最终会对其他人有所帮助。

答案 1 :(得分:0)

如果您要在表单中创建新员工,然后更新BusinessUnit和OverrideBusinessUnit,则以下内容成立:

  1. 您不需要使用cascadeType = All,因为您不需要保存商务单位的实例。
  2. employeeRepository.SaveOrUpdate(员工)做什么?如果它尝试更新员工实例,那么您将收到所提到的错误。您应该尝试保存此员工对象。
  3. 如果我的推测错误,请发布更多代码段。