我想使用休眠条件API执行联接查询,并显式映射一些联接字段。 这非常简单,因此我的代码生成了:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Country> criteria = builder.createQuery(Country.class);
Root<Country> root = criteria.from(Country.class);
Join<Country, Translation> join = root.join("translatedName");
criteria.multiselect(root, join.get("fr"));
TypedQuery<Country> tq = session.createQuery(criteria);
List<Country> countries = tq.getResultList();
国家实体
@Entity
@Table(name = "countries")
public class Country {
@Id
@Column
private UUID id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "name_id")
private Translation translatedName;
@Transient
private String name;
public Country(Country c, String name) {
this.id = c.id;
this.name = name;
}
//getters...
}
翻译实体
package database.models;
import service.model.Country;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "translations")
public class Translation {
@Id
private String id;
private String fr;
private String en;
// getters/setters
}
这正是我想要的。 Multiselect语句将联接字段传递给我的构造函数,然后将其存储在正确的变量中。
但是,我遇到了臭名昭著的N + 1选择问题:
Hibernate: select country0_.id as col_0_0_, translatio1_.id as col_1_0_, translatio1_.fr as col_2_0_ from countries country0_ inner join translations translatio1_ on country0_.name_id=translatio1_.id
Hibernate: select country0_.id as id1_0_0_, country0_.name_id as name_id2_0_0_ from countries country0_ where country0_.id=?
...
经过一些研究,我发现使用fetch语句而不是join可以解决此问题。更新的代码:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Country> criteria = builder.createQuery(Country.class);
Root<Country> root = criteria.from(Country.class);
Join<Country, Translation> join = (Join)root.fetch("translatedName");
criteria.multiselect(root, join.get("fr"));
TypedQuery<Country> tq = session.createQuery(criteria);
List<Country> countries = tq.getResultList();
查询失败,并带有以下(众所周知的)QueryException:
Caused by: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias1,role=service.model.Country.translatedName,tableName=translations,tableAlias=translatio1_,origin=countries country0_,columns={country0_.name_id ,className=database.models.Translation}}]
我开始了解到我用于映射自定义字段的DTO投影与联接获取不兼容。
出于记录,我什至不需要获取我的translatedName
关系。我只想提取正确的语言并将其映射到我的实体中。
先谢谢了。有什么建议吗?
这里的主要目的是在我国填写一个name
字段,并将其直接返回给用户,而不是使用一个包含所有可用翻译内容的嵌套字段。
例如,如果我收到lang = fr的查询,我想返回:
{
"name": "fr_name"
}
不是
{
"name": {
"fr": "fr_name",
"en": "en_name"
}
}
出于性能原因,我不想遍历结果集以手动对其进行映射