休眠搞乱了我的查询
hibernate messes up my query
您好,我编写了以下 Criteria-API 查询,它创建了一个损坏的 sql-select 语句,因为 multiselect。如果我取消对 multiselect 的注释,查询将按预期工作,但问题是我不想拥有所有数据。我的 portal-object 中有几个关系,在我当前的情况下完全没有必要加载它们。
该方法如下所示:
@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
如果我使用 multiselect,为什么 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;
...
}
和代码 class
@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;
...
}
您不能 select 整个合集 (codes
)。
假设您希望结果的每一行都由一个代码和一个证书组成,那么 JPQL 查询应该是
select code, portal.certificate from Portal portal
left join portal.codes as code
where portal.id = :id
这当然会 return 与给定门户中的代码一样多的行,而不仅仅是一个。
避免加载门户实体的其他列可能是过早的、不必要的优化。直接做应该容易得多
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
这将 return 包含门户的唯一行,带有预取的一组代码。
如果您真的希望您的应用程序更快,您应该改为默认设置惰性关联(尤其是 toMany 关联),并在需要时使用提取连接。
您好,我编写了以下 Criteria-API 查询,它创建了一个损坏的 sql-select 语句,因为 multiselect。如果我取消对 multiselect 的注释,查询将按预期工作,但问题是我不想拥有所有数据。我的 portal-object 中有几个关系,在我当前的情况下完全没有必要加载它们。
该方法如下所示:
@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
如果我使用 multiselect,为什么 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;
...
}
和代码 class
@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;
...
}
您不能 select 整个合集 (codes
)。
假设您希望结果的每一行都由一个代码和一个证书组成,那么 JPQL 查询应该是
select code, portal.certificate from Portal portal
left join portal.codes as code
where portal.id = :id
这当然会 return 与给定门户中的代码一样多的行,而不仅仅是一个。
避免加载门户实体的其他列可能是过早的、不必要的优化。直接做应该容易得多
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
这将 return 包含门户的唯一行,带有预取的一组代码。
如果您真的希望您的应用程序更快,您应该改为默认设置惰性关联(尤其是 toMany 关联),并在需要时使用提取连接。