【问题标题】:JPA CriteriaBuilder left outer join for table with no relations?JPA CriteriaBuilder为没有关系的表留下了外连接?
【发布时间】:2016-12-27 19:07:45
【问题描述】:

最初我需要使用 JPA CriteraiBuilder 编写代码以执行以下 SQL:

SELECT ve.col_1,
  (SELECT vm.col_4
  FROM table2 vm
  WHERE vm.col_2  = ve.col_2
  AND vm.col_3 = ve.col_3
  ) as col_a
FROM table1 ve;

但我了解到,不能在 select 子句中添加子查询。所以我将查询更改为像这样使用左外连接。

SELECT ve.col_1,
  vm.col_4 as col_a
FROM table1 ve,
  table2 vm
WHERE 
vm.col_2 (+)    = ve.col_2 
AND vm.col_3 (+) = ve.col_3;

现在 table1 和 table2 没有使用外键的直接关系。对应的 JPA 实体如下所示:

Table1.java ->

@Column(name = "COL_1")
private String col_1;

@Column(name = "COL_2")
private String col_2;

@Column(name = "COL_3")
private String col_3;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumns({
    @JoinColumn(name="COL_2"),
    @JoinColumn(name="COL_3")
})
private Table2 table2;


Table2.java ->

@Column(name = "COL_4")
private String col_4;

@Column(name = "COL_2")
private String col_2;

@Column(name = "COL_3")
private String col_3;

我的代码如下:

final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

final CriteriaQuery<SearchTO> query = criteriaBuilder.createQuery(
        SearchTO.class);
Root<Table1> root = query.from(Table1.class);

final Join<Table1, Table2> joinTable2 = root.join(Table1_.table2,
        JoinType.LEFT);

然后我尝试使用以下方法获取值:

joinTable2.get(Table2_.col_4)

那么现在我得到的错误是:

A Foreign key refering com.Table2 from com.Table1 has the wrong number of column

Table2 大约有 6 列带有注释 @Id,我无法将其更改为只有两列带有 @Id 注释。

请告诉我:

  • 如果可以为我的方法 1(选择子句中的子查询)使用 CriteriaBuilder 编写代码。

  • 如果不可能,我该如何实现方法 2 中提到的左外连接。请注意,Table2 没有 Table1 的任何引用。

请注意,我使用的是普通的 JPA API。数据库是Oracle11g。 JDK版本是1.7。

【问题讨论】:

  • 有哪位专家可以在这里提供帮助吗?

标签: java jpa left-join criteria-api


【解决方案1】:

一种解决方案是使用标准构建器创建视图和查询。 你可以在Joining tables without relation using JPA criteria看到我的回答 您需要做的唯一更改是在视图定义中使用左连接。 希望它能解决您的用例。

【讨论】:

    【解决方案2】:

    对于方法 1:您可以为条件查询编写子查询

    Subquery<Entity1> subquery = cq.subquery( Entity1.class );
        Root fromSubQuery = subquery.from( Entity1.class );
        subquery.select( cb.max( fromSubQuery.get( "startDate" ) ) );
        subquery.where( cb.equal( fromSubQuery.get( "xyzId" ), fromRootOfParentQuery.get( "xyzId" ) ) );
    

    将其用作:

    Root<Entity2> entity2 = cq.from( Entity2.class );
    Predicate maxDatePredicate = cb.and( cb.equal( entyty2.get( "startDate" ), subquery ) );
    

    对于方法 2: 除了在两个实体之间建立关系以进行左连接之外,别无他法。您可以为没有 getter 和 setter 的关系定义私有变量,并使用该变量来设置左连接。 然后将谓词添加到criteriaBuilder

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-13
      相关资源
      最近更新 更多