0

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

我准备了一个项目来展示这个案例。单击此处下载示例项目文件。注意:该文件将在接下来的 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一起工作。

4

1 回答 1

0

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

我的意思是: delete TableBPK, rename TableAPKdoTablePK并在任何地方使用它。

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
于 2013-04-24T13:24:11.903 回答