1
votes

I'm trying to make Spring JPA Data work for me, but have been struggling. Here is the problem.

I have two domain classes with a simple OneToMany relation between them:

class Card {
    @ManyToOne(mappedBy="user")
    private User user;
}

class User {
     @OneToMany
     private List<Card> cards;
}

I have set up Repository interface for each of the class: CardRepository, UserRepository extending the JpaRepository, both repository is injected into a service

@Service
@Transactional(readOnly = true)
class Service {
  @Autowired
  CardRepository repo1;
  @Autowired
  UserRepository repo2;

  public void someMethod() {
      // make use of the repos
      User u=repo2.findByIdentifier("ID1");
      List<Card> cards = u.getCards();
      //do something with the cards will throw lazyinitialization exception.
  }
}

pretty basic setting up. problem comes with the someMethod(), in which I queried an User with its identifier, then try to get the mapped @OneToMany's list, then the LazyInitialization exception happened.

I'm not quite sure if I missed something there? seems as long as the repository's method is returned, the entitymanager is closed; If that's the case, i'm wondering how can I get the relationship without define another repository method?

If I however set the @OneToMany's fetch to be eager, no problem, but it is something I really don't want to do.

The delete() of the repository seems also problematic. If I delete a card first, then trying to delete() its owning user (which still have the card in its list), the delete will fail complaining cannot find the card. but I didn't set any removal propagation from the User to the Card!

I hope someone can explain how the entitymanager is used in the JpaRepository, it seems making Jpa programming more harder. I know all the repository is automatically generated but if someone can point to how they are implemented that wil be very helpful.

Thanks. Wudong

1
It looks to me like you have your OneToMany and ManyToOne the wrong way around. I would expect the OneToMany(mappedBy="") to be on the collection. Also, ManyToOne doesn't have a mapped by property, for that exact reason. - Alex Barnes
yeah, my fault, the annotation was put wrong way around, not corrected in the question. - Wudong
where is the transaction boundary? What you faced is typically caused by not declaring the transaction boundary correctly, so that once the query is done, the transaction (and hence the underlying Session) is closed right away, leaving no session for lazy fetching - Adrian Shum

1 Answers

0
votes

First of all, the mapping tag needs to be interchanged, i.e.

class User(){
 @OneToMany(mappedBy="user")
 private List<Card> cards;
}

class Card{
@ManyToOne
private User user;
}

and how are you calling your someMethod ? if it is called in init-method, you'll not be able to use @Transactional