0

I have a User class containing a collection of lazy loaded objects.

class User {
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @Getter
    @Column(nullable = false)
    private List<Wallet> wallets= new ArrayList<>();
}

Now I also have a Transaction class which contains a reference to the User's wallet.

class Transaction {
        @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
        @JoinColumn(name = "senderWallet", referencedColumnName = "id")
        private Wallet senderWallet;
}

Now I created a service which is supposed to fetch the transactions for a given user:

@Transactional
public List<Transaction> getTransactionsForUser(User user) {
    List<Wallet> wallets = user.getWallets();
    List<Transaction> transactions = new ArrayList<>();

    for (Wallet wallet : wallets) {
        transactions.addAll(transactionRepository.findBySenderWallet(wallet));
    }

    return transactions;
}

In the controller, I'm fetching the current logged in user like this:

User user = ((UserPrincipal) authentication.getPrincipal()).getUser();

Afterwards, I make a call to the service:

List<Transaction> transactions = transactionService.getTransactionsForUser(user);

And this throws a LazyInitializationException. What's the workaround here?

1 Answer 1

1

1) I think that your @OneToMany should have the mappedBy defined:

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
@Getter
@Column(nullable = false)
private List<Wallet> wallets= new ArrayList<>();

2) You are passing an entity User which has been fetched in a different transactional context which seems to be closed now.

In the service method you should perform a merge of that entity before proceding. Srping Data Jpa save method has merging implemented so calling that is sufficient:

@Transactional
public List<Transaction> getTransactionsForUser(User user) {
    userRepository.save(user);  // Add this <---

    List<Wallet> wallets = user.getWallets();
    List<Transaction> transactions = new ArrayList<>();

    for (Wallet wallet : wallets) {
        transactions.addAll(transactionRepository.findBySenderWallet(wallet));
    }

    return transactions;
} 
Sign up to request clarification or add additional context in comments.

3 Comments

What's the reason behind 1? The user is the owner of the relationship. 2) That's what I've guessed, but it seems counterintuitive to do this every single time. Is there a different way to do what I'm trying to achieve? (in terms of design/architecture - maybe add a new method in the service that will fetch the logged in user in the service instead of fetching it in the controller)
The reason for 1 is that you have defined a bidirectional mapping but have not declared an owning entity. As a result your schema will have both a join table and a foreign key which is improper.
On top of that you use JoinColumn or JoinTable on OneToMany. Not Column as such does not exist on the owned entity.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.