【问题标题】:Multiple custom constructors - Hibernate JPA TypedQuery多个自定义构造函数 - Hibernate JPA TypedQuery
【发布时间】:2021-11-08 01:37:21
【问题描述】:

是否可以编写一个包含多个自定义构造函数的TypedQuery?例如,如果您要创建包含 id 和另一个对象的对象,例如:

TypedQuery<ChapterWithBookId> query = em.createQuery(
  "SELECT new " + ChapterWithBookId.class.getName() + "(book.id, new example.Chapter(chapter.id, "
  + "chapter.size"
  + ")) "
  + "FROM " + Book.class.getName() + " AS book JOIN " + Chapter.class.getName() + " AS chapter WHERE "
  + "book.id IN :ids", ChapterWithBookIds.class)
  .setParameter("ids", ids);

不管这个例子是否有实际意义,这个查询应该返回一个ChapterWithBookId类型的对象列表,在该列表中,对于所有具有id的书籍的每一章都有一个对象,包含在id列表中设置为参数。

【问题讨论】:

  • 您需要使用完全限定名称,例如 com.foo.bar.MyClass。除此之外,我不明白你的问题是什么。该代码示例是否不起作用或者您到底在问什么?
  • @BenjaminMaurer 我只是试图使示例尽可能短(example.Chapter 是完全限定名称)。该代码示例不起作用,因为它在 new 关键字处给出了语法错误异常。似乎只有在 SELECT 语句之后才支持新的,但是如果我添加第二个 SELECT 语句,它也不起作用。

标签: mysql hibernate jpa


【解决方案1】:

正如 JPA 规范中定义的那样(参见 4.8 SELECT 子句部分):

SELECT 子句的语法如下:

select_clause ::= SELECT [DISTINCT] select_item {, select_item}*

select_item ::= select_expression [ [AS] result_variable]

select_expression ::=
single_valued_path_expression |
scalar_expression |
aggregate_expression |
identification_variable |
OBJECT(identification_variable) |
constructor_expression

constructor_expression ::=
NEW constructor_name ( constructor_item {, constructor_item}* )

constructor_item ::=
single_valued_path_expression |
scalar_expression |
aggregate_expression |
identification_variable

aggregate_expression ::=
{ AVG | MAX | MIN | SUM } ([DISTINCT] state_valued_path_expression) |
COUNT ([DISTINCT] identification_variable | state_valued_path_expression |
single_valued_object_path_expression) |
function_invocation

所以,如您所见,constructor_item 不能是constructor_expression。但是您可以轻松地重构您的类ChapterWithBookId 构造函数以通过idsize 构造example.Chapter,并且恕我直言,这将使JPQL 更具可读性。

【讨论】:

    【解决方案2】:

    没错,JPQL 中不能有两个构造函数调用——它不是 Java,而是一种自定义语言,并且只支持“SELECT NEW”。

    有几种方法可以解决这个问题:

    .1。让您的构造函数也构建第二个对象 - 不可否认,这是一个丑陋的 hack:

    public ChapterWithBookId(Long bookId, Long chapterId, Long size) {
        this.bookId = bookId;
        this.chapter = new Chapter(chapterId, size);
    }
    

    .2。只需将结果作为元组返回,遍历元组列表并构建对象(也很丑陋)。

    .3。如果你使用 Hibernate,请使用 Hibernate 的 ResultTransformer:

    List<ChapterWithBookId> chapterWithBookDtos = entityManager
    .createQuery(
        "SELECT book.id, chapter.id, chapter.size "
        + "FROM " + Book.class.getName() + " AS book JOIN " + Chapter.class.getName() + " AS chapter WHERE "
      + "book.id IN :ids", ChapterWithBookIds.class)
      .setParameter("ids", ids);)
    .unwrap( org.hibernate.query.Query.class )
    .setResultTransformer(
        new ResultTransformer() {
            @Override
            public Object transformTuple(
                Object[] tuple,
                String[] aliases) {
                return new ChapterWithBookId(
                    (Long) tuple[0],
                    new Chapter((Long) tuple[1], (Long) tuple[2])
                );
            }
     
            @Override
            public List transformList(List collection) {
                return collection;
            }
        }
    )
    .getResultList();
    

    这里是关于您的选项的一般文章:Hibernate’s ResultTransformer in Hibernate 4, 5 & 6

    关于为什么 ResultTransformer also improves query efficiency 由 Vlad Mihalcea 撰写的博客文章。

    Vlad 还提供了hibernate-types library,它有一个非常棒的 ListResultTransformer。

    我绝对推荐最后两篇文章以及 Vlad 写的所有内容 - 博客和书籍。

    【讨论】:

    • 谢谢。选项 3 看起来非常好,但不幸的是,无论我使用什么 SQL 语法,我都会收到 org.hibernate.exception.SQLGrammarException: could not extract ResultSet 错误,原因是 java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 。当我使用多个构造函数时,即使是非常简单的语法也不起作用。如果我只以这种方式构造一个Chapter 对象。
    • @lasbr ResultTransformer 在查询之后处理结果行,因此它不能生成SQLSytnaxErrorException。我刚刚对其进行了测试,我可以将嵌套的构造函数调用放在transformTuple 方法中。你返回什么结果才重要。无论如何,SQLSytnaxErrorException 听起来像是 Hibernate 产生了错误的 SQL。检查您的配置以确保您配置了正确的 SQL 方言,启用调试打印以便您可以看到生成的 SQL 查询并检查它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-27
    相关资源
    最近更新 更多