简体   繁体   中英

Spring Data, JPA @OneToMany Lazy fetch not working in Spring Boot

I have @OneToMany relationship between FabricRoll and FabricDefect .

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "fabric_roll_id", referencedColumnName = "fabric_roll_id")
private Set<FabricDefect> fabricDefects = new HashSet<>();

The problem is when I get FabricRoll by JpaRepository function

findAll()

the associate FabricDefect is also loaded.

I want to load only FabricRoll and FabricDefect should load when calling the function getFabricDefect()

FabricRollServiceImpl class

@Component
public class FabricRollServiceImpl implements IFabricRollService{
    @Autowired
    FabricRollRepository fabricRollRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public List<FabricRoll> getAllFabricRoll() {
        FabricRoll fabricRoll1 = new FabricRoll();
        fabricRoll1.setBatchNo("34344");
        fabricRoll1.setLotNo("425");
        fabricRoll1.setPoNo("42");
        fabricRoll1.setRollLength(2343);
        fabricRoll1.setRollNo("356");
        fabricRoll1.setRollWidth(60);
        fabricRoll1.setStyleNo("354");

        FabricDefect fabricDefect = new FabricDefect();
        fabricDefect.setDefectNote("note");
        fabricDefect.setDefectPoint(3);
        fabricDefect.setSegment(3);
        fabricDefect.setYard(42);


        Set<FabricDefect> fabricDefects = new HashSet<>();
        fabricDefects.add(fabricDefect);


        fabricRoll1.setFabricDefects(fabricDefects);

        addFabricRoll(fabricRoll1);

        FabricRoll fabricRoll = null;


        return fabricRollRepository.findAll();
    }

@Override
public void addFabricRoll(FabricRoll fabricRoll) {
    fabricRollRepository.save(fabricRoll);
}

}

Break point: 在此处输入图片说明

Console: 在此处输入图片说明

You don't need to use @JoinColumn , and you don't need to instantiate fabricDefects

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<FabricDefect> fabricDefects ; 

See more in this question.

FabricDefect class:

@ManyToOne
@JoinColumn(name = "fabric_roll_id")
private FabricRoll roll;

FabricRoll class:

@OneToMany(mappedBy = "roll")
private Set<FabricDefect> fabricDefects;

Collections are by default loaded lazily, JPA will query the db only when the method getFabricDefects will be called. You can see it by yourself enabling logging.

I found solution in this tutorial .

You have to modify FabricRoll OneToMany map as below:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "fabricRoll")
private Set<FabricDefect> fabricDefects;

FabricDefect ManyToOne as below (remember to remove fabric_roll_id field if you included it in your entity):

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fabric_roll_id")
private FabricRoll fabricRoll;

And you don't need to add @Transactional(propagation = Propagation.REQUIRED) before getAllFabricRoll() function.

It seems to be a debugging artifact.

At debugging time, because the transaction is still open, the watched lazy loaded entity properties will be loaded at the breakpoint evaluation time.

To check the "production" behavior you should insert a em.detach statement just before the breakpoint or use logging (as suggested by Manza) and check em.getEntityManagerFactory().getPersistenceUnitUtil().isLoaded(fabricRoll1.fabricDefects()) returns false on the detached entity.

(remember to inject EntityManager for example by declaring @PersistenceContext private EntityManager em; )

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