There are a few similar answered questions from around 2013/2014 but the solutions do not seem to work for me, so I am hoping that something has perhaps changed since then and that I am not missing something glaringly obvious. (new project: spring-boot 2.0.2.RELEASE and hibernate 5.2.17.Final)
The issue: I have an entity that contains a OneToOne (FetchType.LAZY) mapping to another entity, both of which are tables in a MySQL database. I would like the mapping between the two entities to be lazy such that hibernate does not perform a second query to retrieve the mapped entity. The association will never be null, i.e. not optional.
Expected: Given the two entities, e.g. Person and Address (as described below), when making the HQL or JPA request to retrieve one Person from the database I would expect (and want) to see only the following hibernate sql query:
Hibernate: select person0_.id as id1_1_ from person person0_
Actual: Instead, I also see an eager fetch to get the Address entity:
Hibernate: select person0_.id as id1_1_ from person person0_
Hibernate: select address0_.id as id1_0_0_ from address address0_ where address0_.id=?
Attempted solutions: I have tried variations of the following:
- setting
optional = false
(Hibernate: one-to-one lazy loading, optional = false) - adding the
LazyToOneOption.NO_PROXY
annotation (Hibernate Lazy Loading with @LazyToOne(LazyToOneOption.NO_PROXY)) - ignoring mapping during serialisation/deserialisation with
@JsonIgnore
Any help would be greatly appreciated!
Simplified example to reproduce issue: For a simplified example I used as reference this post in which the OP states that they have a working solution: Hibernate: one-to-one lazy loading, optional = false
I created a new Spring Boot project following this tutorial: https://www.callicoder.com/spring-boot-rest-api-tutorial-with-mysql-jpa-hibernate/ with the initial project generated through http://start.spring.io/ (Maven + Java + Spring Boot 2.0.2 and dependencies Web + JPA + MySQL + DevTools)
The entity (Person) I want to query is defined as follows:
@Entity
public class Person {
@Id
@SequenceGenerator(name = "person_sequence", sequenceName = "sq_person")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "person_sequence")
@Column(name = "id")
private long personID;
@LazyToOne(value = LazyToOneOption.NO_PROXY)
@OneToOne(mappedBy = "person", cascade = CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
@JsonIgnore
private Address address;
// .. getters, setters
}
The mapped entity (Address) is defined as:
@Entity
public class Address {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(generator = "gen")
@GenericGenerator(name = "gen", strategy = "foreign", parameters = @Parameter(name = "property", value = "person"))
private long personID;
@PrimaryKeyJoinColumn
@OneToOne(fetch = FetchType.LAZY)
private Person person;
}
Application entry:
@SpringBootApplication
public class OneToOneMappingApplication {
public static void main(String[] args) {
SpringApplication.run(OneToOneMappingApplication.class, args);
}
}
JpaRepository:
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}
RestController:
@RestController
@RequestMapping("/api")
public class PersonController {
@Autowired
PersonRepository personRepository;
// Get All Persons
public List<Person> getAllPersons() {
return personRepository.findAll();
}
}
In the application.properties I have requested spring jpa to show the SQL:
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/onetone_app?useSSL=false
spring.datasource.username = username
spring.datasource.password = password
# Show SQL
spring.jpa.show-sql = true
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
# Bytecode enhancement for NO_PROXY usage (?)
hibernate.ejb.use_class_enhancer = true
One Person with id = 0 and one Address with id = 0 were inserted in the database in order to make the above test.