Simple example:
mappings:
@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;
...
usage:
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);
}
here's output:
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
Now that's a strange behavior. I can get Country object (probably some proxy) and Hibernate didn't issue any additional SQL queries yet. But when I call country.getId() – hibernate issues SQL query to load full country object. It's obvious that Hibernate knows country.id value so I expected that hibernate will just return that id without any additional SQL queries. But it does not.
The problem is - I don't need that entire entity. I only need id and I don't want that separate SQL query (or JOIN query if I set FetchType.EAGER).
I think you will have have to change your Country
entity like below.Add AccessType
annotation on the Id field.
@Entity
public class Country {
@Id@GeneratedValue@AccessType("property")
private Integer id;
private String name;
Faced similar problem,and followed this article:- Accessor Type Annotation
So correct JPA-only standard solution will be:
@Entity
public class Country {
@Id @GeneratedValue @Access(PROPERTY)
private Integer id;
Just wanted to add to @RE350's answer.
In Hibernate 5.2.15, if you are using CriteriaQuery
. Then this can be done easily without the need of the @AccessType
annotation.(which has been deprecated in favor of @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!!
Note: You can also fetch country like this in which case, it will actually join the table.
final Path<Integer> uid = q.join("country").get("id");
Update:
In the case of a ManyToMany join however, this does not seem to be easy, unless you have an entity to model the ManyToMany table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With