2

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?

James Meade
  • 1,147
  • 5
  • 22
  • 46

1 Answers1

2

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.

Sebastiaan van den Broek
  • 5,818
  • 7
  • 40
  • 73
  • I know of these auto-generated functions, but in my case I already have the `Account` with `Set` that is associated with it. So I just want to simply delete one of the `AccountBalance` records from the database. From my understanding, are you suggesting that `AccountBalance` should have an association to Account, but `Account` shouldn't have `Set`? That way I can simply remove an `AccountBalance` by calling `accountBalanceRepository.delete(accountBalance)`? – James Meade Jul 05 '18 at 10:33
  • 2
    Yes that's what I'm suggesting. That also makes it much easier on the database side of things, since otherwise for every new or deleted AccountBalance you need to update your Account record, including problems with locking etc. Unless you really need a bidirectional association like this for some reason, you really shouldn't be creating them. And either way it's better to have the ownership of the association on the side that only has to save 1 foreign key (like an AccountBalance referring to a single Account, instead of an Account referring to maybe a million AccountBalances) – Sebastiaan van den Broek Jul 05 '18 at 10:34
  • That makes a lot of sense, thank you for your suggestion! I will look into whether the bidirectional association is even needed, otherwise I will change my code to look like what you have suggested. – James Meade Jul 05 '18 at 10:47
  • Just to confirm, this suggestion worked perfectly! I am now able to remove an `AccountBalance` record from the database. – James Meade Jul 05 '18 at 15:30
  • 1
    Glad it works! I added some extra information in case you do need to query starting from the Account side. – Sebastiaan van den Broek Jul 05 '18 at 15:55