Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch lazy properties in Spring Projections

I'm currently trying to evaluate the possibilies of using Spring Data JPA.

Trying to use Projections, I'm currently stuck in trying to fetch specific properties Eager.

I have a simple entity which lazy references another entity with a foreign key. I now would like to define different projections for the prior entity. "Primitive" properties are projected well into the projection interface, but trying to project another entity/projection results in it still being lazy loaded.

I would now like to tell Spring/JPA to eagerly load entities/projections inside projections. One possible way would be to use EntityGraphs (They were working well), but I would have to create repositories for each method using different graphs. Question being which other ways are there?

Example:

Entity Buyer:

@Entity
public class Buyer {
    private Integer id;
    private String someProperty;
    private User user;

    ...

    @OneToOne(
        fetch = FetchType.LAZY)
    @JoinColumn(
        name = "CAB_USR_ID",
        referencedColumnName = "ID",
        updatable = false,
        nullable = true,
        foreignKey = @ForeignKey(name = "FK_CAB_USR"))
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

Entity User:

@Entity
public class User {

    private Integer id;
    private String name;

    ...

}

Projection Buyer

public interface BuyerCProjection {
    Integer getId();
    UserProjection getUser();
}

Projection User

public interface UserProjection {

    Integer getId();
    String getName();
}

Repository I would like to use

public interface BuyerRepository extends Repository<Buyer, Integer> {

    <T> List<T> findBy(Class<T> t);
}
like image 422
Schartey Avatar asked Feb 16 '17 08:02

Schartey


People also ask

What is lazy loading in Spring JPA?

With a LAZY type dependency, only data of the wanted object is loaded: author's data is not retrieved. With Spring Data JPA, every relationship between 2 domain objects owns one of these data loading types. By default, the method will be determined by the relationship type.

How lazy loading works in JPA?

By default, JPA uses the lazy fetch strategy in associations of type @ElementCollection. Thus, any access to the collection in a closed Persistence Context will result in an exception. This test throws an exception when we try to access the phone list because the Persistence Context is closed.

What is the default fetch type in Hibernate?

By default, Hibernate uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.

What do spring data rest projections do?

Spring data REST Projection supports projecting only a selected fields from an entity representation. To do that, we can define those specific fields into our @Projection interface. Let's create a custom view of our Student entity with first name and last name fields.


1 Answers

I don't think there is a way to instruct JPA/Hibernate to fetch eagerly using projections. The projection is applied after the fetch query is executed, so it's too late to modify the query.

There's a compromise solution using the jackson-datatype-hibernate module with the FORCE_LAZY_LOADING feature enabled. This forces all lazy-loaded objects in your projections to be initialized and returned.

Note that this isn't as efficient as writing custom queries using entity graphs or JOIN FETCH. It will behave the same as calling Hibernate.initialize on each lazy-loaded object, executing another select query. So it results in N+1 selects. But it can be a good way to get started. When something starts to be slow, you can still optimize by writing join-fetch or entity graph queries.

like image 126
Dario Seidl Avatar answered Oct 26 '22 16:10

Dario Seidl