【问题标题】:JPQL distinct with string functionJPQL 与字符串函数不同
【发布时间】:2011-11-21 19:44:12
【问题描述】:

我有一个这样的 JPQL:

select distinct d 
from Department d
left join fetch d.employees

当我想获取我的 Department 实体的惰性属性之一时,distinct 不再起作用

select distinct d, substring(d.htmlDescription, 1,400)
from Department d
left join fetch d.employees

查询返回的部门数量与其中的员工数量一样多。

substring(d.htmlDescription) 很重要,因为该属性被定义为 CLOB(在 postgresql 下键入 TEXT):

@Column(columnDefinition = "TEXT")
@Basic(fetch = FetchType.LAZY)
String htmlBody;

子字符串函数在 sql 中翻译,因此限制了数据库和 Web 服务器之间传输的数据量。

作为一种解决方法,我尝试将查询分为两部分:

select d, substring(d.htmlDescription, 1,400)
from Department d where d in (
    select distinct d1
    from Department d1  left join fetch d1.employees
)

这不起作用,因为JOIN FETCH 不得在子查询的FROM 子句中使用。

【问题讨论】:

    标签: java hibernate jpa jpa-2.0 jpql


    【解决方案1】:

    由于我无法制作 cmets,因此我想指出一些令我怀疑的事情。

    1. distinct d, substring(d.htmlDescription, 1,400) 返回的对象是什么?您可以使用单独的查询获取该字符串,还是使用 Java 获取该字符串?
    2. 我相信该查询可以重写为一个没有左连接语句的查询。
    3. 也许您可以重写查询,以便您可以先放置 substring 语句,然后再放置 distinct d?

    【讨论】:

    • 1.我添加了使用子字符串 jpql 函数而不是 java 的原因。
    • 2.左连接用于获取。这是我要在该查询上加载的唯一惰性关系。如果没有 fetch,结果是 N+1 选择。
    • 3.我不明白你的提议。
    【解决方案2】:

    最后我找到了解决问题的方法:

    1. 修改我的映射
    2. 在 2 次调用中减少请求。

    htmlBody 字段现在位于另一个实体中。因此部门实体更轻。

    class Department{
    ...
    @OneToOne (fetch = FetchType.LAZY, 
        cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
    Content content = new Content();
    ...
    }
    
    
    class Content{
    ...
    @Column(columnDefinition = "TEXT")
    @Basic(fetch = FetchType.LAZY)
    String htmlBody;
    ...
    }
    

    然后我可以使用以下请求:

        List<Department> deps = em.get().createQuery(
                "select distinct d " +
                        "from Department d " +
                        "order by d.id desc ", Department.class)
                .setFirstResult(first)
                .setMaxResults(count)
                .getResultList();
    
        List<Object[]> tuple = em.get().createQuery(
                "select d, substring(d.content.htmlBody, 1,400)" +
                        "from Department d " +
                        "left join fetch d.employees" +
                        "where d in (:deps) order by d.id desc")
                .setParameter("deps", deps)
                .getResultList();
    
        ... //Filter the duplicates due to the fetching
    

    这样,我有 2 个 sql 查询。员工的获取是在第二个查询中完成的,该查询发生在少量数据上。子字符串在 SQL 中实现。完美!

    【讨论】:

      猜你喜欢
      • 2019-08-17
      • 1970-01-01
      • 2014-01-30
      • 2013-11-15
      • 2021-07-19
      • 1970-01-01
      • 2019-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多