4

我有一个 JPA 实体,我想在这个表上添加自加入。表看起来像例如

@Entity
@Table(name = "TABLE_A")
@IdClass(TableAPk.class)
public class TableA implements Serializable {

    private static final long serialVersionUID = 1L;


    @Id
    @Column(name = "COLUMN_1", nullable = false, length = 64)
    private String            column_1;

    @Id
    @Column(name = "COLUMN_2", nullable = false, precision = 10, scale = 2)
    private BigDecimal        column_2;


    @ManyToOne
    @JoinColumn(name = "COLUMN_1", insertable = false, updatable = false)
    //@ManyToOne(optional = true, fetch = FetchType.LAZY)
    //@JoinTable(name = "KEY_MAPPING", 
    //        joinColumns = { @JoinColumn(name = "J_COLUMN_1", referencedColumnName = "COLUMN_1", insertable = false, updatable = false) } )
    private TableA tableA;

    @OneToMany(mappedBy="tableA", fetch = FetchType.LAZY)
    private Set<TableA> tableASet;

IdClass 看起来像:

public class TableAPk implements Serializable {
    // default serial version id, required for serializable classes.
    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 1L;

    private String            column_1;

    private BigDecimal        column_2;

根据我的业务逻辑,我只需要在单列上添加自加入

final Join<TableA, TableA> joinASelf = joinX.join("tableA", JoinType.INNER);

但是表有复合主键,所以不止一个字段用@Id注解。我得到如下异常:

引起:org.hibernate.AnnotationException:从 com.data.TableA 引用 com.data.TableA 的外键列数错误。应该是2。

我如何在此处仅在单列上添加自加入?我是 JPA 的新手,所以如果我遗漏了什么,请告诉我。

2015 年 2 月 21 日更新:我添加了注释 @AssociationOverride 来覆盖关联:

@ManyToOne
@AssociationOverride(name="tableA", 
        joinColumns=@JoinColumn(name="COLUMN_1"))
private TableA tableA;

生成的列名显示为“TABLE_A_COLUMN_2”。我无法找出原因。有什么线索吗?

4

1 回答 1

6
  1. 正确的方法是(不是OP想要的)

您可以使用@JoinColumns注释(注意复数而不是单数),从而加入:

@Entity
@Table(name = "TABLE_A")
@IdClass(TableAPk.class)
public class TableA implements Serializable {

    private static final long serialVersionUID = 1L;


    @Id
    @Column(name = "COLUMN_1", nullable = false, length = 64)
    private String            column1;

    @Id
    @Column(name = "COLUMN_2", nullable = false, precision = 10, scale = 2)
    private BigDecimal        column2;


    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "FK_COL1", referencedColumnName="COLUMN_1"),
        @JoinColumn(name = "FK_COL2", referencedColumnName="COLUMN_2")
    })
    private TableA tableA;

    @OneToMany(mappedBy="tableA", fetch = FetchType.LAZY)
    private Set<TableA> tableASet;
  1. 问题的解决方案:

删除那些@ManyToOne/@OneToMany关系并添加一个private String refCol1;. 这样,为 JPQL 编写相应的条件查询:SELECT t1 FROM TableA t1, TableA t2 WHERE t2.refCol1 = t1.column1

解决CriteriyQuqeries方案如下:

final CriteriaBuilder criteriaBuilder = entityManagerMds.getCriteriaBuilder();
// This Pojo is used to fetch only selected fields
final CriteriaQuery<DummyPojo> createQuery = criteriaBuilder.createQuery(DummyPojo.class);

final Root<TableX> tableX = createQuery.from(TableX.class);
final Join<TableX, TableA> joinTableA = tableX.join("tableAs", JoinType.INNER);


// Every time you want to add a self join, create new root
final Root<TableA> tableA = createQuery.from(TableA.class);
final Predicate predicateSelfJoin = criteriaBuilder.equal(joinTableA.<String>get("column_1"), tableA.<String>get("column_1"));
于 2015-02-23T08:40:02.923 回答