简单示例:
映射:
@Entity
public class City {
@Id@GeneratedValue
private Integer id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Country country;
...
@Entity
public class Country {
@Id@GeneratedValue
private Integer id;
private String name;
...
用法:
Query query = session.createQuery("from City");
List<?> cities = query.list();
for (Object cityObj : cities) {
City city = (City) cityObj;
System.out.printf("City: %s %s%n", city.getId(), city.getName());
Country country = city.getCountry();
System.out.println("Country retrieved");
Integer countryId = country.getId();
System.out.printf("Country id: %s%n", countryId);
}
这里的输出:
Hibernate: select city0_.id as id0_, city0_.country_id as country3_0_, city0_.name as name0_ from City city0_
City: 1 Astana
Country retrieved
Hibernate: select country0_.id as id1_0_, country0_.name as name1_0_ from Country country0_ where country0_.id=?
Country id: 1
City: 2 Almaty
Country retrieved
Country id: 1
City: 3 Omsk
Country retrieved
Hibernate: select country0_.id as id1_0_, country0_.name as name1_0_ from Country country0_ where country0_.id=?
Country id: 2
现在这是一种奇怪的行为。我可以获得Country对象(可能是一些代理),而Hibernate还没有发出任何其他SQL查询。但是当我调用country.getId()时 - hibernate会发出SQL查询来加载完整的国家/地区对象。很明显,Hibernate知道country.id值,所以我希望hibernate只返回那个id而不需要任何额外的SQL查询。但事实并非如此。
问题是 - 我不需要整个实体。我只需要id,我不想要那个单独的SQL查询(如果我设置FetchType.EAGER,则需要JOIN查询)。
答案 0 :(得分:6)
我认为您必须更改Country
实体,如下所示。在Id字段中添加AccessType
注释。
@Entity
public class Country {
@Id@GeneratedValue@AccessType("property")
private Integer id;
private String name;
面对类似的问题,并遵循这篇文章: - Accessor Type Annotation
答案 1 :(得分:1)
因此,正确的JPA标准解决方案将是:
@Entity
public class Country {
@Id @GeneratedValue @Access(PROPERTY)
private Integer id;
答案 2 :(得分:1)
只想添加到@ RE350的答案中。
在Hibernate 5.2.15中,如果您使用的是CriteriaQuery
。然后,无需@AccessType
注释即可轻松完成此操作。(已弃用@AttributeAccessor
注释)。
final CriteriaBuilder cb = criteriaBuilder();
final CriteriaQuery<City> query = criteriaQuery();
final Root<City> q = query.from(City.class);
final Path<Integer> uid = q.get("country").get("id"); // Note this!!
注意: 您也可以在这种情况下获取国家/地区,它将实际上加入表格。
final Path<Integer> uid = q.join("country").get("id");
更新:
但是,对于ManyToMany联接来说,这似乎并不容易,除非您有一个实体来对ManyToMany表进行建模。