【问题标题】:Object references an unsaved transient instance save the transient instance before flushing:对象引用了一个未保存的瞬态实例,在刷新之前保存瞬态实例:
【发布时间】:2013-01-04 12:19:06
【问题描述】:

上图显示了表之间的关系。

AddressType 表包含静态值,例如 mailinghomework 等。

AddressTypeRel 模型类中,我有一个带有多对一注释的 AddressType 对象

AddressTypeRel.java

public class AddressTypeRel implements java.io.Serializable{
.......

private AddressType addressType=new AddressType();
.......

@ManyToOne()
@LazyCollection(LazyCollectionOption.FALSE)
@JoinColumn(name="typeId", insertable=false, updatable=false, nullable=false)
@NotFound(action = NotFoundAction.IGNORE)
public AddressType getAddressType() {
   return addressType;
}

public void setAddressType(AddressType addressType) {
   this.addressType = addressType;
}
......
}

保存到 Address 表后,我还应该保存 type(mailing/billing) 地址和 addressId 进入 AddressTypeRel 但我无法保存。当我尝试保存时

AddressTypeRel addressTypeRel=new AddressTypeRel();
addressTypeRel.setAddressId(i) //i=5 for example
addressTypeRel.setTypeId(j)    //j=4 for example
hibernatetemplate.save(addressTypeRel);

发生的错误是:

对象引用了一个未保存的瞬态实例 - 保存瞬态 刷新前的实例:com.sample.AddressType

【问题讨论】:

  • AddressType 是否也在hibernatetemplate.save(addressTypeRel); 之前保存。在我看来,您试图指向未保存在数据库中的地址类型(此处为:addressTyperel.setTypeId(j);)ID。
  • @mardavi 实际上 AddressType 表已经包含值。它是一个静态表,有各种地址类型 1.mailing2.home 等。我们只是将 AddressType 表的 Ids 保存到 AddressTypeRel
  • 从您的问题来看,您将一个表列映射到两个属性并不明显(即int getTypeId()AddressType getAddressType 都指向typeId 列),请解决这个问题。

标签: hibernate


【解决方案1】:

您需要将@ManyToOne() 更改为@ManyToOne(cascade = CascadeType.ALL),以便保存将尝试级联到AddressType,然后忽略它,因为您在@JoinColumn 上设置了insertable=false, updatable=false

【讨论】:

  • 我试过了,还是不行。事实上,insertable=false, updatable=false 并没有被忽略,hibernate 也意识到了它们。如果没有发生另一个异常(与insertableupdatable 属性无关),它们将被应用并且不会插入/更新列:object references an unsaved transient instance - save the transient instance before flushing
【解决方案2】:

问题

Entity AddressTypeRel 正在将一个表列映射到两个 bean 属性:

  1. int typeId(问题中没有明确说明,但你可以从addressTypeRel.setTypeId(j) //j=4 for example推断出来)
  2. AddressType addressType(如问题中明确描述的那样)

Hibernate 不允许将同一个表列映射两次,除非您采取如下所述的必要步骤。

解决办法

这是两步过程,您只完成了第一步。目标是使 AddressType addressType(通过其 getter getAddressType() 映射)只读,因为 Hibernate 仅在所有其他映射都是只读的情况下才允许多次映射一列

  1. 使AddressTypeRelAddressType之间的关系只读:

    • 您已经将其映射为 insertable=false, updatable=false,但这仅适用于关系,而不适用于目标实体
  2. 使目标实体只读,在我们的例子中是AddressType

    • 只需将其标记为@Transient,此注释将使休眠状态忽略关系的其他实体,并且不会打扰您保存它

讨论

  • 我以前用过insertable=false, updatable=false,为什么现在会出现这个问题? 因为实体字段上的读写映射更为常见,而某些原始类型上的只读映射或非实体对象。在这种情况下,您在int 上有读写映射,在实体AddressType 上有只读映射。当然,您不必在原始类型或非实体对象上使用 @Transient 注释。
  • 为什么insertable=false, updatable=false 不更聪明,并检测这些情况? 因为 Hibernate 将两个实体之间的关系视为三部分构造:a) 此实体 b) 目标实体 c) 它们之间的关系,所以使这个结构只读需要 b)c) 只读,并且对于这两个都有不同的工具来做到这一点(如解决方案中所述)。这很有用,因为您可以更好地控制,例如您可能希望将目标实体设为@Transient,而不是关系insertable=true, updatable=true

【讨论】:

    猜你喜欢
    • 2016-02-24
    • 2014-10-26
    • 2014-05-16
    • 1970-01-01
    • 1970-01-01
    • 2012-02-27
    • 2019-01-14
    • 2012-03-21
    • 1970-01-01
    相关资源
    最近更新 更多