【问题标题】:Criteria builder joinSet fetches Object instead of Set of ObjectsCriteria builder joinSet 获取对象而不是对象集
【发布时间】:2016-03-26 20:53:51
【问题描述】:

我有 2 个具有 OneToMany 关系的实体。

@Entity
public class Table1 implements Serializable {

@Id
private Long id;

private String field1;
private String field2;
private String field3;

@OneToMany
@JoinColumn(name = "table1_id")
private Set<Table2> tables2;
}

@Entity
public class Table2 {

    @Id
    private Long id;

    private String field1;
}

我想使用标准生成器从 Table1 获取数据到附加对象 Table1Trimmed

public class Table1Trimmed {

    private Long id;
    private Set<Table2> tables2;

    public Table1Trimmed(Long id, Set<Table2> tables2) {
        this.id = id;
        this.tables2 = tables2;
    }

}

我就是这样做的

CriteriaQuery<Table1Trimmed> cq = criteriaBuilder.createQuery(Table1Trimmed.class);
Root<Table1> table1Root = cq.from(Table1.class);
SetJoin<Table1, Table2> tables2Join = table1Root.joinSet("tables2");
cq.select(criteriaBuilder.construct(Table1Trimmed.class, table1Root.get("id"), tables2Join));
List<Table1Trimmed> tables1Trimmed = em.createQuery(cq).getResultList();

但是当我运行我的应用程序时,我收到了这个错误

java.lang.NoSuchMethodException: Table1Trimmed.<init>(java.lang.Long, Table2)
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getConstructor(Class.java:1825)
    at org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getConstructorFor(PrivilegedAccessHelper.java:172)
    at org.eclipse.persistence.internal.jpa.querydef.CriteriaQueryImpl.populateAndSetConstructorSelection(CriteriaQueryImpl.java:400)
    at org.eclipse.persistence.internal.jpa.querydef.CriteriaQueryImpl.select(CriteriaQueryImpl.java:93)

这意味着框架想要将 Table2 类的对象注入到我的 Table1Trimmed 构造函数中,而不是 Table2 对象的 Set。有没有办法使用标准构建器来实现这一点?

【问题讨论】:

  • 您不能在 JPQL 或 Criteria 查询中选择多值字段(这实际上就是您使用构造所做的事情)。请参阅 JPA 规范 JPQL“BNF”表示法

标签: java jpa eclipselink criteria criteria-api


【解决方案1】:

最佳解决方案是创建仅包含特定字段的附加只读实体。

@ReadOnly
@Entity("table1trimmed")
@Table("table1")
public class Table1Trimmed {

    @Id
    private Long id;
    @OneToOne
    @JoinFetch(JoinFetchType.OUTER)
    @JoinColumn(name = "table1_id")
    private Set<Table2> tables2;

}

好的,我在这里找到了间接答案 [​​1]

[1] 2 JPA entities on the same table

【讨论】:

    【解决方案2】:

    嗯,你正在尝试做的事情有两个问题。首先是您的查询获得了多行。 tables2 集合中的每个条目都有一行:

    -----------------------------------------
    |  TABLE1.ID  |  TABLE2.ID |  TABLE1_ID |
    -------------+-------------+-------------
    |     1      |     1       |     1      |
    |     1      |     2       |     1      |
    -----------------------------------------
    

    如果您提取到Table1 是可以的,但如果您在 JPQL 或 CriteriaQuery 中构建则不行。一个Construct 语句只能做一行,一个类。如果您创建一个具有Table2 构造函数的Table1Trimmed,您将看到您获得每个Table2 条目的结果,而不是每个Table1 条目的结果。

    其次,对于 Set,没有 JPA 提供者可以使用的构造函数。 SetHashSet 可以从另一个 Collection 构造,但同样,Construct 构造中没有任何内容可以构造 CollectionTable2s。 (不得不这么说!:)。

    【讨论】:

    • 明白,但你知道如何使用 Criteria Builder 来实现,我想要做什么吗?
    • 我的意思很漂亮,因为我想省略一些手动对象分组等。
    • 是的,创建一个更小的只读实体是有意义的
    猜你喜欢
    • 1970-01-01
    • 2015-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多