Hibernate,在不加载关联实体的情况下获取外部id

时间:2014-12-26 10:11:21

标签: java hibernate

简单示例:

映射:

@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查询)。

3 个答案:

答案 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表进行建模。