Spring Data, JPA @ManyToOne lazy initialization not working

I know that there are many similar questions about this problem, but nothing works for me.

I have a @ManyToOne connection between Aim and User.

@ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "user_id", nullable = false, updatable = false) private User user; 

and

 @OneToMany(fetch = FetchType.LAZY, mappedBy = "user") private Collection<Aim> userAims; 

respectively.

 @Override @Transactional(propagation = Propagation.REQUIRED) @PreAuthorize("isAuthenticated() and principal.user.isEnabled() == true") public Aim findById(String aimId) throws NumberFormatException, EntityNotFoundException { Aim aim = null; try { aim = aimRepository.findOne(Long.parseLong(aimId)); } catch (NumberFormatException e) { throw new InvalidDataAccessApiUsageException(e.getMessage(), e); } if (aim == null) throw new EntityNotFoundException("Aim with id: " + aimId + " not found!"); return aim; } 

The @OneToMany associations work great with lazy typing . The method is not nested in another @Transactional method, so @Transactional works fine.

enter image description here

enter image description here

So the record exists.

  • The User and Target classes are not final and implement Serializable
  • Some sources suggest adding annotations to getters. He is also not a job.
  • @Fetch (FetchMode.SELECT) the same situation = \
  • A query through Hibernate gives the same thing, but a HQL query with a left fetch join works fine
  • My FK is ON. UPDATING CASCADE TO THE CASCADE INSERT
  • optional = false also tried ...

Please note that I do not have a LazyInitException



Thanks in advance!

+6
source share
1 answer

I assume from the code in your findById method, and by the link to β€œlazy initialization does not work” in the header, that you want to find the Aim object by its numerical identifier, as well as the associated User object.

To do this with lazy loading, you need to β€œget” the associated object, and (most importantly) you need to β€œget” one of the associated fields of the object.

So, the code inside the try block should be:

 aim = aimRepository.findOne(Long.parseLong(aimId)); if (aim != null && aim.getUser() != null) { aim.getUser().getUserId(); // doesn't need to be assigned to anything } 

Alternatively, if you have access to the log, you can use userId in a debug or trace log message:

 if (aim != null && aim.getUser() != null) { logger.debug("Lazy-loaded User " + aim.getUser().getUserId()); } 

This is an added benefit that you can debug when things are lazy.

By the way, we found out what a difficult way to make the search procedure throw an Exception when it does not find something bad. This is because you can use the find routine to find out if an entity does NOT exist. If this happens in a transaction, your exception may cause an unwanted rollback (unless you ignore it). It is better to return null and check this instead of using try ... catch .

+1
source

Source: https://habr.com/ru/post/987966/


All Articles