Timothy
Timothy

Reputation: 117

lazy loading for one to many does not work for hibernate and lombok

Lazy loading for one to many does not work

I have the following Order entity

@Data
@Entity
@EqualsAndHashCode
@Table(name = Order.TABLE_NAME)
public class Order implements Serializable {

private static final long serialVersionUID = -7036337819884484941L;

@Column(name = OrderNames.ORDER_ID)
private String orderId;

@Column
private String name;

@JsonManagedReference
@ToString.Exclude
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<OrderItem> orderItem = new HashSet<>();

and I have another entity OrderItem

@Data
@Entity
@EqualsAndHashCode(callSuper = true, exclude = "order")
@Table(name = OrderItemNames.TABLE_NAME)
public class OrderItem implements Serializable {

private static final long serialVersionUID = -7036337819884484941L;

@Column(name = OrderItemNames.ORDER_ID)
private String orderId;

@Column(name = OrderItemNames.ORDER_ITEM_ID)
private String orderItemId;

@JsonBackReference
@ToString.Exclude
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = OrderItemNames.ORDER_FK, nullable = false)
private Order order;

Here is my repository

@Repository
public interface OrderRepository extends JpaRepository<Order, String> {
    Order findByOrderId(String orderId);
}

And here is my ServiceImpl

@Override
public Order findByOrderId(String orderId) {
    Order order = orderRepository.findByOrderId(orderId);

    return order;
}

From my understanding, if I debug on the orderRepository.findByOrderId, I expect it will only show Order entity (without OrderItem) because the fetch type is lazy

But the actual result is eager and the order has the orderItem entity as well regardless if I do it eagerly / lazily.

I have followed this as well https://stackoverflow.com/a/37727206/6460497 but to no avail. Do I miss something regarding the ToString or @EqualsAndHashCode ?

EDIT:

I turned on the SQL logging and it does 2 queries (select the order table and then select the orderItem table). This happens on both eager and lazy loading.

I also tried to remove lombok @Data and use @Getter @Setter create my own equal hashCode and toString, but it still load the data even if i set it to lazy.

Here is my properties to postgreSql

spring.jpa.database=postgresql
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.properties.hibernate.default_schema=public
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.open-in-view = false

hibernate.show_sql=true
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.format_sql=true
hibernate.hbm2ddl.auto=

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=username
spring.datasource.password=password

Upvotes: 2

Views: 3293

Answers (3)

segito10
segito10

Reputation: 388

You can put on "order" the annotation

@Getter(AccessLevel.NONE)

Upvotes: 1

Rakib
Rakib

Reputation: 145

There is a high chance Order is getting initialized when getOrderItems() is called while debugging if OpenEntityManagerInView interceptor is configured.

To turn this off in spring boot project you can use the following option in your application.properties file.

spring.jpa.open-in-view=false

You can check whether Order is getting fetched with a SQL JOIN query or with a different SELECT query by enabling <property name="show_sql">true</property> in your persistent.xml or by using the following if using spring boot.

spring.jpa.properties.hibernate.show_sql=true

You can see a sample for testing the scenario in this repository.

Upvotes: 2

Timothy
Timothy

Reputation: 117

I have found the answer by adding the following properties

spring.jpa.open-in-view = false

Also I found out that because I am debuging the entity, it seems that it does eager loading where actually it works as expected (lazy).

@Override
public Order findByOrderId(String orderId) {
    Order order = orderRepository.findByOrderId(orderId);
    return order;
}

say i put a debug point at

return order;

at this point, the db only do one query (for order) and then I lookup the entity like this then only hibernate do the query for the child entity.

Upvotes: -1

Related Questions