【问题标题】:Retrieve JPQL Query as DTO in Spring boot application在 Spring Boot 应用程序中检索 JPQL 查询作为 DTO
【发布时间】:2021-01-21 07:32:21
【问题描述】:

我基本上想要做的是运行一个查询并将结果放入类Account 的对象中。需要强调的非常重要的是,该查询在未映射为@Entity 的两个表之间执行联接。那我该怎么做呢?

这是我的 FooRepository.java

@Repository
public interface FooRepository extends JpaRepository<Foo, Long> {

  Foo findById(Long id);

@Query(value = "SELECT Q1.ACCOUNT_NAME," +
          "Q2.GROUP_NAME  " +
          "FROM USERS_DEV Q1\n" +
          "JOIN USERS_GROUPS Q2 ON Q1.ACCOUNT_NAME = Q2.ACCOUNT_NAME\n" +
          "WHERE LOWER(Q1.ACCOUNT_NAME) = 'john.pit'", nativeQuery = true)
  List<Account> getAllAccounts();

那么如何更改我的查询以获得所需的结果?

这是我的 Account.java

public class Account {

    String samAccountName;
    String groupName;

    public Account(String accountName, String groupName) {
        this.accountName = accountName;
        this.groupName = groupName;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }
}

【问题讨论】:

  • 尽可能避免使用nativeQuery。也就是说,如果您适当地映射属性名称,这 应该 工作(常量大小写不再是默认值)。

标签: java sql spring hibernate jpql


【解决方案1】:

您可以使用EntityManagerResultTransformer

entityManager.createNativeQuery(
    "SELECT Q1.ACCOUNT_NAME," +
    "Q2.GROUP_NAME  " +
    "FROM USERS_DEV Q1 " +
    "JOIN USERS_GROUPS Q2 ON Q1.ACCOUNT_NAME = Q2.ACCOUNT_NAME " +
    "WHERE LOWER(Q1.ACCOUNT_NAME) = 'john.pit'"
)
            .unwrap(NativeQuery.class)
            .setResultTransformer(new ResultTransformer() {
                @Override
                public Object transformTuple(Object[] tuple, String[] aliases) {
                    return new Account(
                        (String) tuple[0],
                        (String) tuple[1]
                    );
                }

                @Override
                public List transformList(List collection) {
                    return collection;
                }

            })
            .getResultList();

可能需要演员表。

【讨论】:

  • 我按照你说的做了,现在我得到了这个:InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [不适用];嵌套异常是 org.hibernate.exception.SQLGrammarException: could not extract ResultSet Caused by: java.sql.SQLSyntaxErrorException: ORA-00923: FROM keyword not found where expected
  • @MariusPop 是的,那是我的错误,我以为是 jpql。对于原生应该有其他解决方案,让我编辑我的答案
  • @MariusPop 立即尝试。不要担心ResultTransformer 的弃用,直到有合适的替代品才会被删除
  • 我对 entityManager 不太熟悉。我应该更准确地将这段代码粘贴到哪里?还在存储库类中?我应该创建一个 EntityManager 的实例吗?
  • @MariusPop 你可以创建一个单独的类,我建议CustomFooRepository,在那里你可以创建一个返回List&lt;Account&gt;的方法并粘贴代码。 EntityManager可以注入@Autowired
【解决方案2】:

作为替代方案,您可以通过以下方式将@NamedNativeQuery@SqlResultSetMapping 一起使用:

@Entity
@NamedNativeQuery(
  name = "findAllAccounts",
  query = 
     "SELECT " +
     "  Q1.ACCOUNT_NAME AS accountName, " +
     "  Q2.GROUP_NAME AS groupName " +
     "FROM USERS_DEV Q1 " +
     "JOIN USERS_GROUPS Q2 ON Q1.ACCOUNT_NAME = Q2.ACCOUNT_NAME " + 
     "WHERE LOWER(Q1.ACCOUNT_NAME) = 'john.pit'",
  resultSetMapping = "findAllAccountsMapping"
)
@SqlResultSetMapping(
   name = "findAllAccountsMapping",
   classes = @ConstructorResult(
      targetClass = Account.class,
      columns = {
         @ColumnResult(name="accountName"),
         @ColumnResult(name="groupName"),
      }
   )
)
public class Foo {
   // ...
}

FooRepository:

@Repository
public interface FooRepository extends JpaRepository<Foo, Long> {

  @Query(name = "findAllAccounts", nativeQuery = true)
  List<Account> getAllAccounts();
}

请参阅休眠documentation 了解更多详情。

【讨论】:

  • 无法提取结果集原因:java.sql.SQLSyntaxErrorException: ORA-00923: FROM keyword not found where expected
  • 仍然得到FROM keyword not found where expected,但是当我在sql developer中复制粘贴查询时,它工作得很好。我真的不明白:(
  • @MariusPop 尝试使用我更新的答案中的映射。如果没有帮助,请启用hibernate.show_sqlhibernate.format_sqlhibernate.use_sql_comments 并查看究竟执行了什么查询。
  • 问题是间距。我不知道 sql 会粘合所有内容,所以有些单词也被粘合了
  • 好的,是的,我已经看到你关于这个的问题了。
【解决方案3】:

也许我错了,但我记得您可以执行以下操作(使用 HQL):

@Query("select new Account(u.name, g.groupName) " +
          "from User as u" +
          "join u.group as g" +
          "where LOWER(u.name) = 'john.pit'")

语法可能有误,但如果你使用 HQL,我相信你可以在 select 语句中使用 DTO 构造函数。

希望对你有帮助:D

【讨论】:

  • 这仅在表被映射为实体时才有效
猜你喜欢
  • 2021-02-10
  • 2020-11-18
  • 2018-09-18
  • 2018-02-14
  • 2018-10-18
  • 2017-08-15
  • 2021-08-21
  • 1970-01-01
  • 2021-03-25
相关资源
最近更新 更多