Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate 对象引用未保存的临时实例-保存新的子/孙引用时出现问题_Hibernate_Jpa_Save_Cascade_Transient - Fatal编程技术网

Hibernate 对象引用未保存的临时实例-保存新的子/孙引用时出现问题

Hibernate 对象引用未保存的临时实例-保存新的子/孙引用时出现问题,hibernate,jpa,save,cascade,transient,Hibernate,Jpa,Save,Cascade,Transient,我在hibernate中遇到了级联保存问题,并且在跟踪源代码时运气不太好 简言之,我映射了一个三级父/子/孙关系,当我保存一个对一个有两个子的父/子/孙关系的引用,并且每个子/子都有几个孙子时,第一次持久化成功,每个人都会获得相应的ID: Parent (id:p1) child1 (id:parent,c1) grandchild (id:child1,g1) grandchild (id:child1,g2) child2 (id:parent

我在hibernate中遇到了级联保存问题,并且在跟踪源代码时运气不太好

简言之,我映射了一个三级父/子/孙关系,当我保存一个对一个有两个子的父/子/孙关系的引用,并且每个子/子都有几个孙子时,第一次持久化成功,每个人都会获得相应的ID:

Parent (id:p1)
    child1 (id:parent,c1)
        grandchild (id:child1,g1)
        grandchild (id:child1,g2)
    child2 (id:parent,c2)
        grandchild (id:child2,g1)
        grandchild (id:child2,g2)
然后,如果我加载父对象(急切地)并添加一个新的子对象以及它自己的几个新的子对象,那么当我试图通过父对象持久化更改时,会出现未保存的暂时错误:

Parent (id:p1)
    child1 (id:parent,c1)
        grandchild1 (id:child1,g1)
        grandchild2 (id:child1,g2)
    child2 (id:parent,c2)
        grandchild3 (id:child2,g1)
        grandchild4 (id:child2,g2)
    child3 (id:<new>)
        grandchild5 (id:child3,<new>)
        grandchild6 (id:child3,<new>)
我省略了重载的equals和hashcode方法,但实际上它们都匹配键字段

我所能找到的最好的根本原因是这个方法:AbstractEntityPersister:4480

公共布尔值CanExtractDoutofEntity(){
返回hasIdentifierProperty()| | hasEmbeddedCompositeIdentifier()| | hasIdentifierMapper();
}

这就是hibernate(1.5.2.RELEASE)确定要保存的孙子是暂时的,需要从其父(child3)中提取它的id的地方。在搜索id时,它执行上面的函数,所有引用方法返回null,导致调用返回false。此时将抛出异常

如果能洞察到我可能做错了什么,我们将不胜感激,而且我们非常欢迎找到解决方案

谢谢,
Jason

为了其他人的利益,我将用我如何解决这个问题来回答我自己的问题

基本问题是,我依赖@ManyToOne映射关系将父ID提供给子对象。这样做并不是直接将父id字段映射到子id字段

虽然这可能适用于两级层次结构,但它的意思似乎是,低于此层次结构的任何后续级别都会在第二级子级中看到对父id的依赖,但看不到要映射到的显式列。我觉得这是一个bug,但我对自己的理解不够自信,无法做出这样的假设

无论如何,为了解决这个问题,我执行了以下三个更改:

1) 我将所有parent@Id列直接映射到每个子级(每个级别随后添加了越来越多的键)。仅复制了字段和@Column方面

2) 每个子项中的@ManyToOne父项映射未标记为ID

3) 我为每个子对象添加了@PrePersist映射,以从@ManyToOne映射的父对象中提取父id,并将值复制到映射的字段中

一直以来,我觉得我需要显式地映射列,但不知道如何从父母那里获取ID。只有当我把二和二放在一起时,我才意识到一个非id@ManyToOne映射和一个@PrePersist组合可以实现这一点

我怀疑@MapsId可能与@PrePersist代码块中的逻辑具有相同的影响,因此必须进行实验,但目前。。。它起作用了

希望有一天这能帮助别人

@Entity
@Transactional
@EntityListeners(AuditingEntityListener.class)
@Table(name="DS_EXTENDED_DATA_SOURCE")
public final class Rule {

    @Id
    @GeneratedValue(generator="IdentityProvider")
    @GenericGenerator(name="IdentityProvider", strategy="com.teradata.tac.domain.common.IdentityProvider")
    @Column(name="Extended_Data_Source_Id", nullable=false, length=MAX_ID_LENGTH, updatable=false, insertable=true)
    private String  extendedDataSourceId;

    @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true, fetch=FetchType.EAGER, mappedBy="rule")
    @Fetch(FetchMode.SELECT)
    @OrderBy("Display_X_Position_Num,Display_Y_Position_Num,Extended_Data_Source_Id")
    private List<Node<?>> nodes = new ArrayList<>();
}
@Entity
@IdClass(NodeId.class)
@Table(name="DS_XDS_NODE")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="Xds_Node_Type_Cd")
public class Node<T extends Node<T>> extends BaseDomain<Node<T>> {

    @Id
    @GeneratedValue(generator="IdentityProvider")
    @GenericGenerator(name="IdentityProvider", strategy="com.teradata.tac.domain.common.IdentityProvider")
    @Column(name="Xds_Node_Id", nullable=false, length=MAX_ID_LENGTH, updatable=false, insertable=false)
    protected String xdsNodeId;

    @Column(name="Xds_Node_Type_Cd", nullable=false, insertable=false, updatable=false)
    protected short xdsNodeTypeCd;

    @Id
    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="Extended_Data_Source_Id", insertable=false, updatable=false, nullable=false)
    @ApiModelProperty(hidden=true)
    @JsonBackReference(value="rule")
    protected Rule rule;

    // Selected Columns
    @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true, fetch=FetchType.EAGER, mappedBy="node")
    @Fetch(FetchMode.SELECT)
    @OrderBy("Display_Ord")
    protected List<SelectedColumn> selectedColumns = new ArrayList<>();
}   
@Entity
@Table(name="DS_XDS_JOIN_NODE")
@DiscriminatorValue("60")
public class JoinNode extends Node<JoinNode> {

}
@Entity
@IdClass(SelectedColumnId.class)
@Table(name = "DS_XDS_SELECTED_COLUMN")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class SelectedColumn {

    @Id
    @GeneratedValue(generator = "IdentityProvider")
    @GenericGenerator(name = "IdentityProvider", strategy = "com.teradata.tac.domain.common.IdentityProvider")
    @Column(name = "Xds_Selected_Column_Id", nullable = false, length = MAX_ID_LENGTH, updatable = false, insertable = false)
    protected String xdsSelectedColumnId;

    @Id
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumns({
        @JoinColumn(name = "Extended_Data_Source_Id", insertable = false, updatable = false, nullable = false),
        @JoinColumn(name = "Xds_Node_Id", insertable = false, updatable = false, nullable = false) })
    protected Node<?> node;
}
public class NodeId {

    private Rule   rule;           // Parent object reference
    private String xdsNodeId;      // local instance id (not guaranteed to be unique)

    public NodeId() {}

    public NodeId(Rule rule, String xdsNodeId) {
        this.rule = rule;
        this.xdsNodeId = xdsNodeId;
    }

    public String getId() {
        return this.xdsNodeId;
    }

    public Rule getRule() {
        return this.rule;
    }
}