【问题标题】:Object references an unsaved transient instance issue对象引用了未保存的瞬态实例问题
【发布时间】:2011-03-15 03:04:40
【问题描述】:

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

这是部分员工映射:

 <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。谁能通过查看代码 sn-ps 告诉我如何避免此异常(最好不涉及级联)?

编辑:

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

【问题讨论】:

    标签: .net nhibernate hibernate


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

    【讨论】:

      【解决方案2】:

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

      1. 您不需要使用 cascadeType=All,因为您不需要保存业务单元的实例。
      2. employeeRepository.SaveOrUpdate(employee) 做什么?如果它尝试更新员工实例,那么您将收到您提到的错误。您应该尝试保存此员工对象。

      如果我的假设是错误的,请发布更多代码 sn-ps。

      【讨论】:

      • 我添加了更多信息。这是否与同一班级有 2 个多对一有关,两者都从数据库中补水并分配给员工。当我只是处理“businessUnit”多对一时,我没有这个问题。仅在我添加“businessUnitOverride”多对一时才引入此问题。
      • 我不认为这可能是一个问题,在映射的意义上看起来还可以。但是从设计的角度来看,同一个类的多个多对一映射并不是一个好主意。既然它们已经很多了,为什么还要放在两个单独的列表中?
      • 映射也很混乱。从映射文件中我可以看到员工和业务部门之间存在多对多关系(guidelineApprover 和 increaseApprover)。我会建议您再次修改映射,即使您设法在不这样做的情况下摆脱此错误,它最终也可能会导致问题。在这种情况下,您可能希望 GuidelineApprover 和 increaseApprover 扩展 Employee,然后从 BussinessUnit 对每个进行多对多映射。对于业务单元和覆盖业务单元,员工端也应该这样做。
      • 编辑评论:GuidelineApprover 和IncreaseApprover 应该与业务部门是一对多的。员工方面也类似。至于错误,您显然保存了一些不存在的内容,因此您应该查看与此更新相关的完整事件序列。不要使用休眠的 saveOrUpdate 而是去合并。
      猜你喜欢
      • 1970-01-01
      • 2010-12-20
      • 1970-01-01
      • 2011-04-12
      • 1970-01-01
      • 1970-01-01
      • 2012-02-27
      • 2019-01-14
      • 2012-03-21
      相关资源
      最近更新 更多