Search code examples
javaspringhibernatejpahibernate-jpa

Deleting Hibernate entity that has a foreign key in database


I have already looked into this issue that I am having and tried to remove the AccountBalance from the Set in the corresponding Account Hibernate class, and then saving the Account object, but the database isn't updated.

I want to delete an AccountBalance record from the database using Hibernate. An Account can have many AccountBalances, but an AccountBalance can only have one Account.

I am using a repository class which extends CrudRepository to save Hibernate instances to their corresponding tables in the database. I have tried using the delete() function specifically on the AccountBalance I want to delet, but that doesn't work.

Here is the Hibernate code I already have in AccountBalance:

@Entity
@Table(name = "account_balance")
public class AccountBalance {

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "acc_id", nullable = false)
private Account account;

And Account:

@Entity
@Table(name = "account")
public final class Account {

@OneToMany(fetch = FetchType.EAGER, mappedBy = "account", cascade = CascadeType.ALL)
private Set<AccountBalance> balances = new HashSet<>();

I have already tried this functionality to no avail.

public void deleteAccountBalance(Account account, String balanceCode) {
    for (Iterator<AccountBalance> iterator = account.getBalances().iterator(); iterator.hasNext();) {
        AccountBalance accBal =  iterator.next();
        if (accBal.getBalanceCode().equals(balanceCode)) {
            iterator.remove();
        }
    }
    accountRepository.save(account);
}

Any ideas on what I am doing wrong?


Solution

  • There are a lot of recommendations to NOT use associations from 2 sides like this, with good reason as they're hard to keep in sync.

    For most use cases you should just have the association stored in AccountBalance, so you only save 1 foreign key (to Account) in there. It's very simple to add some method to your AccountBalance repository to find an AccountBalance by Account and whatever other field. These are even auto-generated, i.e. you just write public AccountBalance findByAccountAndBalanceCode(Account account, String balanceCode); and the method is already implemented. Though you can also write your own query with a @Query annotation on the method.

    In the same way you can just find all AccountBalances belonging to an Account, if you need to display this to the user. public List<AccountBalance> findByAccount(Account account); and you're done.

    In that case, there is simply nothing to update on the Account side of things, if you remove an AccountBalance you only remove a single record from your database.

    If you need to do a query which starts from the Account side of things but you are querying on some condition in AccountBalances, you can still do a select a from Account a where exists (select AccountBalance ab from AccountBalance where ab.account = a and <insert some AccountBalance constraint>)

    Although for better performance I'd recommend using joins, something like select a from AccountBalance ab inner join ab.account a and then you can still constrain on both tables.