2011-03-15 65 views
1

我有一个新员工的员工输入屏幕,在提交时被员工模型绑定器拦截。员工拥有“业务部门”和“业务部门”。越控业务部门是最近添加的,并且是我的问题的原因。对象引用一个未保存的瞬态实例问题

这里是部分员工的映射:

<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(员工):

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

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

编辑:

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

回答

1

对不起。我想到了。这实际上是Employee类中BusinessUnit属性的一个问题。我使用空对象模式,所以我得到这个错误,因为NHibernate试图保存类型为“BusinessUnit.Empty”的瞬态对象。这是由于未能在BusinessUnit.Empty和null之间正确转换导致我的代码中存在错误。无论如何感谢所有的帮助。

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

<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”。这种模式解决了我的问题。希望它最终对别人有帮助。

0

如果要创建形式新员工,然后更新BusinessUnit和OverrideBusinessUnit,然后满足以下条件:

  1. 您DONOT需要使用的CascadeType =所有,因为你是DONOT需要保存商业单位的实例。
  2. employeeRepository.SaveOrUpdate(employee)是做什么的?如果它试图更新员工实例,那么您将会看到您提到的错误。您应该尝试保存此员工对象。

如果我的假设错了,请发布更多的代码片段。

+0

我加了一点信息。这对于同一个班级有两对多的关系,这两个都是从数据库中重新水化并分配给该员工的。当我刚刚处理“businessUnit”多对一时,我没有这个问题。此问题仅在我多次添加“businessUnitOverride”时引入。 – SideFX

+0

我不认为这可能是一个问题,在映射意义上看起来不错。但从设计意义上来说,对同一班级的多对多映射并不是一个好主意。既然他们已经很多,为什么你想要然后在两个单独的名单? –

+0

此外,映射相当混乱。从映射文件中,我可以看到员工和业务单位之间存在多对多关系(准则申请者和增加申请者)。我会建议您再次修改映射,即使您设法在不这样做的情况下摆脱此错误,最终可能会导致问题。在这种情况下,您可能需要GuidelineApprover和IncreaseApprover来扩展Employee,然后使用BussinessUnit进行多对多映射。对于bussinessUnit和overrideBussinessUnit,Employee端应该做同样的事情。 –

相关问题