简体   繁体   中英

Spring Boot - Load parent entity record in 1 To Many relationship using Generic DAO Implementation

In my spring-boot application (using hibernate), for simple CRUD on entities I have a generic DAO implementation with create, update, read, delete methods. My question is specifically around the read functionality - where I cannot use the generic read method on entities which have relationship. As doing so in the generic DAO implementation the child objects(configured with lazy-loading) too get populated.

GenericHibernateDaoImpl.java

    public class GenericHibernateDaoImpl<T, PK extends Serializable> implements IGenericDao<T,PK>{
       // including only my read method
       @Override
       public T read(Class<T> t, int id) {
           String _query = String.format("SELECT r FROM %s r WHERE Id= %s",t.getName(),""+id);
           return (T) getSession().createQuery(_query, t).getSingleResult();
       }
    }

The above helps me when I want to query simple tables with no relationship.

In scenarios where I want to select a database record without loading its children (in cases of 1..M relationship but only returning the parent), I use a non-generic type as below (because if I use the above class in such case, it pulls all data from associated tables):

SalePlanDao.java - here I can get just the parent record

public class SalePlanDao implements IGenericDao<FFMSalePlan, Serializable> {
   @Override
   public FFMSalePlan read(Class<FFMSalePlan> t, int id) {
       String _query = String.format("SELECT r FROM %s r WHERE Id= %s",t.getName(),""+id);
       FFMSalePlan _mmSalePlan = (FFMSalePlan) getSession().createQuery(_query, t).getSingleResult();
       return _mmSalePlan;
   }
}

When I call the SalePlanDao.read, it now returns only the parent record and not its children (lazy-loading).

I want to be able to load only the parent entity like in snippet 2 from a generic read method like in GenericHibernateDaoImpl.java. That way, I can keep 1 such method in the whole project and only when children are needed, invoke a separate DAO which has a call to Hibernate.Initialize(etc).

I am assuming that the field on which lazy-load is enabled is "touched" in the generic implementation and hence it invokes selects on the child tables also.

My question is more of "how to design it" rather than any technical issue/error I am facing. How do I achieve generic read on entities with relationship to only return the parent record?

Entities

  • FFMSalePlan - parent table
  • FFTSalePlan - child table

FFMSalePlan.java

public class FFMSalePlan implements Serializable {
   //other fields
    @JsonProperty("detail")
    @OneToMany(mappedBy = "mSalePlan", orphanRemoval = true)
    @Cascade({CascadeType.ALL})
    private Set<FFTSalePlan> tSalesPlan;
}

FFTSalePlan.java

public class FFTSalePlan implements Serializable {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "i_saleplan_id", referencedColumnName = "i_id" )
    private FFMSalePlan mSalePlan;
}

If I were you, I wouldn't write generic logic or use Hibernate.initialize to initialize relationships. Usually, the way to go is using entity graphs in a Spring Data repository: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.entity-graph

Another way to handle the fetching is to make use of DTOs or projections. You can look into Spring Data Projections, but I think this is a perfect use case forBlaze-Persistence Entity Views , which is similar to Spring Data Projections, but goes way beyond the basic stuff and performs a lot better.

The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM