hibernate 搞砸了我的查询

Posted

技术标签:

【中文标题】hibernate 搞砸了我的查询【英文标题】:hibernate messes up my query 【发布时间】:2017-05-30 05:23:45 【问题描述】:

您好,由于多选,我编写了以下 Criteria-API 查询,该查询创建了一个损坏的 sql-select 语句。如果我取消注释多选,则查询按预期工作,但问题是我不希望拥有所有数据。我的门户对象中有几个关系,在我目前的情况下绝对不需要全部加载它们。

方法如下:

  @Override
  public Optional<Portal> loadPortalData(long clientId)
  
    log.trace("loading data for client with id ''", clientId);
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Portal> criteriaQuery = criteriaBuilder.createQuery(Portal.class);
    Root<Portal> root = criteriaQuery.from(Portal.class);
    criteriaQuery.multiselect(root.get(Portal_.codes),
                              root.get(Portal_.certificate))
                 .where(criteriaBuilder.equal(root.get(Portal_.id), clientId));
    try
    
      return Optional.of(entityManager.createQuery(criteriaQuery).getSingleResult());
    
    catch (NoResultException noResult)
    
      return Optional.empty();
    
  

而损坏的查询如下所示:

30 Mai 2017 07:12:56,305 [main] TRACE mypackage.repository.PortalDaoImpl (PortalDaoImpl.java:39) - loading data for client with id '1'
Hibernate: 
select
    . as col_0_0_,
    portal0_.certificate as col_1_0_ 
from
    portal portal0_ 
inner join
    Code authorisat1_ 
        on portal0_.id=authorisat1_.client_id 
inner join
    certificate certificat2_ 
        on portal0_.certificate=certificat2_.id 
where
    portal0_.id=1

如果我使用多选,为什么 hibernate 会这样搞乱我的查询?

编辑:

@Entity
@Table(name = "portal")
public class Portal

   ...
   @Valid
   @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "client")
   private Set<Code> codes = new HashSet<>();

   @Valid
   @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
   @JoinColumn(name = "certificate", referencedColumnName = "id")
   private Certificate certificate;
   ...

和代码类

@Entity
public class Code


  @Id
  @GeneratedValue
  private long id;

  @NotNull
  @Column(nullable = false, unique = true)
  private String code;

  @NotNull
  @ManyToOne(fetch = FetchType.EAGER, targetEntity = Portal.class)
  @JoinColumn(name = "client_id", referencedColumnName = "id", nullable = false)
  private Portal client;

  @NotNull
  @Temporal(TemporalType.TIMESTAMP)
  @Column(nullable = false)
  private Date creation_time;

  @Column(nullable = false)
  private int expires_in;
  ...

【问题讨论】:

Portal实体的代码是什么?为什么不使用 JPQL 进行这样的静态查询? 为什么门户实体的代码很重要? JPQL 产生同样的错误 嘿,你是需要帮助的人。投票结束,因为您不想免费提供允许我帮助您的所需信息。 【参考方案1】:

您不能选择整个集合 (codes)。

假设您希望结果的每一行都由一个代码和一个证书组成,那么 JPQL 查询应该是

select code, portal.certificate from Portal portal 
left join portal.codes as code
where portal.id = :id

这当然会返回与给定门户中的代码一样多的行,而不仅仅是一个。

避免加载门户实体的其他列可能是过早的、不必要的优化。这样做应该会容易得多

em.find(Portal.class, id)

或者,如果您想在同一查询中加载代码和证书

select distinct portal from Portal portal 
left join fetch portal.certificate
left join fetch portal.codes
where portal.id = :id

这将返回一个包含门户的唯一行,以及预取的代码集。

如果您真的希望您的应用程序快速运行,则应改为默认设置惰性关联(尤其是 toMany 关联),并在需要时使用 fetch 连接。

【讨论】:

以上是关于hibernate 搞砸了我的查询的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat:我搞砸了我的 jndi 连接设置还是啥?

Outlook 自动清理我的换行符并搞砸了我的电子邮件格式

Gradle 在 Android Studio 中搞砸了我的应用程序,如何修复?

无法实例化抽象类我认为我搞砸了我的构造函数 C++

<br> 标签使用 scrapy 和 python 搞砸了我的数据

HTML5 可拖动图像“选择”并在 Firefox 中搞砸了我的拖动 javascript