hibernate上的JPA复合外键问题

时间:2013-04-23 10:36:41

标签: hibernate jpa-2.0 hibernate-mapping

我正在使用Hibernate JPA,EnterpriseDB(PostgresPlus Advanced Server 9.2.1.3)和Jboss 7.1.1 Final并在读取具有复合主键和(一对一)外键链接到另一个实体的实体时收到异常

我准备了一个展示案例的项目。单击here以下载示例项目文件。 注意:该文件将在接下来的7天内在服务器上提供。如果需要,我可以上传文件并更改链接。

我尝试读取实体列表,将复合主键的一列与参数匹配。

public List<TableA> getComposites(String key) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<TableA> query = cb.createQuery(TableA.class);

    Root<TableA> aEntity = query.from(TableA.class);
    aEntity.fetch(TableA_.tableB, JoinType.LEFT);

    query.where(cb.equal(aEntity.get(TableA_.id).get(TableAPK_.colA), key));

    query.select(aEntity).distinct(true);

    try {
        return em.createQuery(query).getResultList();
    } catch (NoResultException ignore) {
        return null;
    }
}

例外是:

Caused by: org.hibernate.TypeMismatchException: Provided id of the wrong type for class org.test.hibernate.persistence.entity.TableB. Expected: class org.test.hibernate.persistence.entity.TableBPK, got class org.test.hibernate.persistence.entity.TableAPK

表A和表B具有与复合主键(col_a,col_b,col_c)的一对一链接,共享相同的列名。表B的主键也是表A主键的外键。

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

@Column(name="col_a")
private String colA;

@Column(name="col_b")
private String colB;

@Column(name="col_c")
private String colC;


@Entity
@Table(name="table_a")
public class TableA implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private TableAPK id;

@Column(name="col_ex_d")
private String colExD;

//bi-directional one-to-one association to TableB
@OneToOne(mappedBy="tableA", fetch=FetchType.LAZY)
private TableB tableB;


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

@Column(name="col_a")
private String colA;

@Column(name="col_b")
private String colB;

@Column(name="col_c")
private String colC;


@Entity
@Table(name="table_b")
public class TableB implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private TableBPK id;

@Column(name="col_ex_d")
private Integer colExD;

@Column(name="col_ex_e")
private String colExE;

@Column(name="col_ex_f")
private Boolean colExF;

//bi-directional one-to-one association to TableA
@OneToOne(fetch=FetchType.LAZY)
@PrimaryKeyJoinColumns({
    @PrimaryKeyJoinColumn(name="col_a", referencedColumnName="col_a"),
    @PrimaryKeyJoinColumn(name="col_b", referencedColumnName="col_b"),
    @PrimaryKeyJoinColumn(name="col_c", referencedColumnName="col_c")
    })
private TableA tableA;

如果您想在本地测试:Project有一个liquibase配置来创建表,甚至自己插入示例数据(composite-persistence/src/main/liquibase)。您可以检查changelog.xml文件以创建表以及主键和外键。但是我没有在包中包含连接属性文件。如果你想在你的本地运行项目,我可以尝试帮助设置环境。测试只是在部署后在浏览器上调用servlet

/composite-web/Composite?myKey=a1

如果您想使用eclipselink进行测试,只需激活composite-persistence/src/resources/META-INF/persistence.xml上的提供程序和属性(它们被注释掉以使用Jboss的默认JPA提供程序:Hibernate;您需要在Jboss服务器上配置eclipselink模块)。顺便说一下,实体的设置与eclipselink一起使用。

1 个答案:

答案 0 :(得分:0)

由于TableAPKTableBPK相等(具有完全相同的结构),您可以删除一个并在任何地方使用另一个。

我的意思是:删除TableBPK,重命名TableAPK执行TablePK并在任何地方使用它。

TableA那样:

@Entity
@Table(name="table_a")
public class TableA implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private TablePK id; //<- this line changed from TableAPK to TablePK
...

TableB

@Entity
@Table(name="table_b")
public class TableB implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private TablePK id; //<- this line changed from TableBPK to TablePK
相关问题