复合外键JPA TypeMismatchException

时间:2016-10-24 02:24:39

标签: jpa foreign-keys key composite-key

我通过简单的Parent Child表解释了我的场景。

我的复合主键也是引用Parent表的复合外键。

create table parent(
code varchar(10) not null,
id int not null,
parentcol varchar(10),
primary key(code,id)
);

create table child(
code varchar(10) not null,
id int not null,
childcol varchar(10) not null,
primary key(code, id),
foreign key(code, id) references parent(code,id)
);

创建的实体(这是通过Eclipse JPA插件)

@Entity
@Table(name="parent")
@NamedQuery(name="Parent.findAll", query="SELECT p FROM Parent p")
public class Parent implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private ParentPK id;

@Column(length=10)
private String parentcol;

//bi-directional one-to-one association to Child
@OneToOne(mappedBy="parent")
private Child child;

public Parent() {
}

/* getters and setters */

}

@Embeddable
public class ParentPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;

@Column(unique=true, nullable=false, length=10)
private String code;

@Column(unique=true, nullable=false)
private int id;

    /* getters and setters */

/** Overridden equals and hashcode **/
}



@Entity
@Table(name="child")
@NamedQuery(name="Child.findAll", query="SELECT c FROM Child c")
public class Child implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private ChildPK id;

@Column(nullable=false, length=10)
private String childcol;

//bi-directional one-to-one association to Parent
@OneToOne
@JoinColumns({
    @JoinColumn(name="code", referencedColumnName="code", nullable=false, insertable=false, updatable=false),
    @JoinColumn(name="id", referencedColumnName="id", nullable=false, insertable=false, updatable=false)
    })
private Parent parent;

    /* getters and setters */

}

@Embeddable
public class ChildPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;

@Column(insertable=false, updatable=false, unique=true, nullable=false, length=10)
private String code;

@Column(insertable=false, updatable=false, unique=true, nullable=false)
private int id;

/* overridden equals and hashcode */

我正在使用Spring数据保存我的实体,如下所示。父表包含一个代码为“code”且Id为1的记录。

Child child = new Child();
ChildPK childPK = new ChildPK();
childPK.setCode("code");
childPK.setId(1);
child.setId(childPK);
child.setChildcol("child1");
childRepository.save(child);

当必须插入新记录时,第1次运行成功。但问题是在第二次运行时,必须更新让我们说,

child.setChildcol("child2");

我遇到错误

HHH000327: Error performing load command : org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.xebia.eTechLog.entities.Parent. Expected: class com.xebia.eTechLog.entities.ParentPK, got class com.xebia.eTechLog.entities.ChildPK

如果我尝试在子表中提供ParentPk的引用为

@Entity
@Table(name="child")
@NamedQuery(name="Child.findAll", query="SELECT c FROM Child c")
public class Child implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private ParentPK id;

@Column(nullable=false, length=10)
private String childcol;

//bi-directional one-to-one association to Parent
@OneToOne
@JoinColumns({
    @JoinColumn(name="code", referencedColumnName="code", nullable=false, insertable=false, updatable=false),
    @JoinColumn(name="id", referencedColumnName="id", nullable=false, insertable=false, updatable=false)
    })
private Parent parent;

它确实有效,但如果在Parent类中有更多字段,那就不会这样了。这是我的真实场景。

1 个答案:

答案 0 :(得分:0)

您应该使用派生身份。这意味着您应该指出孩子对其父母的引用会映射孩子的ID(带有@MapsId注释):

@Entity
public class Child implements Serializable {
    @EmbeddedId
    private ChildPK id;

    @Column(nullable=false, length=10)
    private String childcol;

    @OneToOne
    @MapsId  // <<< NB
    @JoinColumns({
        @JoinColumn(name="code", referencedColumnName="code"),
        @JoinColumn(name="id", referencedColumnName="id")
    })
    private Parent parent;

    ...
}

派生身份在JPA 2.1规范2.4.1节中讨论。