【问题标题】:HQL: How to query certain fields when one of those fields is a one-to-many List?HQL:当这些字段之一是一对多列表时如何查询某些字段?
【发布时间】:2017-12-16 01:55:59
【问题描述】:

我在编写 HQL 查询以从我的 Cases 实体中仅选择 caseidtitlecaseStatus 字段时遇到困难。返回的案例必须根据 caseid 区分。我不希望包含 nameuserid 字段。我也不想对caseidtitlecaseStatus 字段使用延迟提取。请注意,caseStatus 字段是一对多列表。以下是实体。省略了 getter/setter 以节省空间。

@Entity
@Table(name = "Cases")
public class Cases {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "caseid", nullable = false)
    private Integer caseid;
    private Integer userid;
    private String name;
    private String title;
    @OrderBy("caseStatusId DESC")
    @OneToMany(mappedBy = "cases", fetch = FetchType.EAGER)
    private List<CaseStatus> caseStatus;
}

@Entity
@Table(name = "CaseStatus")
public class CaseStatus {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "caseStatusId", nullable = false)
    private Integer caseStatusId;
    private String info;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "caseid")
    private Cases cases;
}

我的目标是检索仅包含 caseidtitleList&lt;CaseStatus&gt; 的 Cases 实体的不同 List&lt;Cases&gt;List&lt;Object[]&gt;List&lt;CaseStatus&gt; 将包含 CaseStatus 对象,并填充其所有字段。

public List<Object[]> getCases(String title) {
    TypedQuery<Object[]> q = em.createQuery("select distinct c.caseid, c.title, cs "
        + "FROM Cases c join c.caseStatus cs "
        + "where c.title like :title", Object[].class);
    q.setParameter("title", "%" + title + "%");
    List<Object[]> results = q.getResultList();
    return results;
}

上述方法很接近,但不正确,因为它不是在其中一个索引中返回List&lt;CaseStatus&gt;,而是仅返回一个CaseStatus 实体。

例如,如果我的数据库包含一个 Case 和一个大小为 n 的 List&lt;CaseStatus&gt;,则结果将类似于以下示例:

我现在得到的结果示例。不正确:

        List<Object[]> index 0:
            Contains an Object[] where:
                Object[0] = {some caseid}
                Object[1] = {some title}
                Object[2] = {1st CaseStatus}
        List<Object[]> index 1:
            Contains an Object[] where:
                Object[0] = {same caseid as the one found in index 0 above}
                Object[1] = {same title as the one found in index 0 above}
                Object[2] = {2nd CaseStatus}
        ...
        List<Object[]> index n-1:
            Contains an Object[] where:
                Object[0] = {same caseid as all the previous}
                Object[1] = {same title as all the previous}
                Object[2] = {nth CaseStatus}

我希望达到的结果示例:

        List<Object[]> index 0:
            Contains an Object[] where:
                Object[0] = {unique caseid}
                Object[1] = {some title}
                Object[2] = List<CaseStatus> with size of n

更新了问题。我要检索的字段不是nametitleList&lt;CaseStatus&gt;,而是caseidtitleList&lt;CaseStatus&gt;caseid 是 Cases 的主键。

我发现了各种线程 Select Collections with HQL - hibernate forumSelect collections with HQL - stackoverflow。这几乎是我遇到的问题。似乎没有人在这些线程中找到解决方案。

【问题讨论】:

  • 你能发布生成的 SQL 查询吗?
  • 查看错误消息,它说“由:com.microsoft.sqlserver.jdbc.SQLServerException:关键字'as'附近的语法不正确。” ,我在您的查询中没有看到任何“as”关键字,您是否发布了正确的查询?
  • 它是 HQL,hibernate 生成的查询是你会发现有问题的“as”的地方。如果您在休眠配置中将 org.hibernate.cfg.AvailableSettings.SHOW_SQL(或“hibernate.show_sql”)设置为 true 并将日志记录设置为调试,则可以看到这一点。
  • 将生成的 SQL 查询从日志记录添加到原始帖子。我注意到 .因为 col_2_0 可能会导致错误。我想知道为什么我写的 HQL 会导致这种情况。
  • 如果你问的是HQL,为什么要使用JPAHQLJPA 无关,因此请从您的标签列表中删除JPA。如果你的意思是JPA 查询,那么在select 列表中使用集合值属性是非法的。

标签: java hibernate hql


【解决方案1】:

你为什么不直接使用

Query q = em.createQuery("select distinct c from Cases c where "
            + "c.name like :name and "
            + "c.title like :title");

试试这个。这可能是一种幼稚的方法,但应该能够解决问题。您可能会获得比您需要的更多的字段,但返回类型将是案例列表。

【讨论】:

    【解决方案2】:

    正确的语法应该是

    TypedQuery<Object[]> q = em.createQuery("select c.name, c.title, cs FROM Cases c "
                    + "join c.caseStatus cs where "
                    + "c.name = :name and "
                    + "c.title = :title", Object[].class);
    

    返回类型将是List&lt;Object[]&gt;,其中Object[] 的第一个索引是c.name,第二个是c.title,第三个是关联的caseStatus 实体。可以查询多个实例(行)。

    我们需要 JOIN,因为 CaseStatus 和 Case 之间的关系是通过集合映射的。

    SELECT cs
    FROM Case c JOIN c.cases cs;
    

    【讨论】:

    • 我注意到在结果 List 中,每个索引都包含一个 CaseStatus 而不是 CaseStatus 列表。有什么方法可以检索每个案例及其关联的 CaseStatus 列表?
    • 此外,如果 Case 具有大小大于 2 的 List,则返回 List 不包含基于 caseid 的不同实体。其中会有重复的实体。您知道检索不同实体的方法吗?我尝试将关键字 distinct 添加到您的示例查询中,但似乎没有任何影响。
    • 示例:返回类型将是 List,其中 Object[] 的第一个索引是 c.name,第二个是 c.title,第三个是关联的 List。跨度>
    • 一切都取决于你首先如何持久化对象。请记住,您始终必须保持关系双方的联系。您问:“我注意到在结果 List 中,每个索引都包含一个 CaseStatus 而不是 CaseStatus 列表。”答案是:一切都取决于对象如何相互关联(通过外键链接)。
    • 问:你知道检索不同实体的方法吗? A:请描述场景,具体要检索什么。
    【解决方案3】:

    事实上,HQL 完全面向对象并在查询中使用您的类结构,因此通过编写c.caseStatus,HQL 期望您的Cases 类具有caseStatus 属性,这是错误的,因为它是一个集合。

    如果您查看Hibernate HQL documentation,您会看到:

    然而,与 SQL 相比,HQL完全面向对象并且理解继承、多态和关联等概念。

    我认为您需要在这里做的是更改您的查询,使其与您的类结构相匹配:

        Query q = em.createQuery("select distinct c.name, c.title, cs.caseStatus FROM Cases c left join c.caseStatus where "
            + "c.name like :name and "
            + "c.title like :title");
    

    【讨论】:

      【解决方案4】:

      Hibernates 对查询有点困惑;在 HQL 中你的加入是这样的(抱歉,由于计算机不稳定,我无法在发布前进行测试,但你应该明白)

      select distinct c from Cases c left join fetch c.caseStatus cs where....
      

      “获取”让它变得急切。请注意,这将返回一个类型为 Cases 的数组。你的 where 子句看起来是对的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-09
        • 2023-01-18
        • 1970-01-01
        • 1970-01-01
        • 2017-07-04
        • 2013-10-15
        • 2020-03-03
        • 1970-01-01
        相关资源
        最近更新 更多