Issue
I have two models, Account
and Transaction
. The Account
looks as follows:
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private BigDecimal balance;
@OneToMany(fetch = FetchType.LAZY)
private List<Transaction> transactions;
public Account(final BigDecimal balance) {
this.balance = balance;
this.transactions = new ArrayList<>();
}
public void addTransaction(Transaction transaction) {
this.transactions.add(transaction);
}
}
The Transaction
entity is as follows:
public class Transaction {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
@OneToOne(fetch=FetchType.LAZY)
private Account sender;
@OneToOne(fetch=FetchType.LAZY)
private Account recipient;
private BigDecimal amount;
public Transaction(Account sender, Account recipient, BigDecimal amount) {
this.sender = sender;
this.recipient = recipient;
this.amount = amount;
}
}
As you can see, a Transaction
is between a Sender
and Recipient
, both of these are represented by the Account
entity. In this case, a Transaction
will have a One-To-One mapping for a Sender and the same for a Recipient. However, on the flip side, the Account
entity should be able to represent all transactions from an account regardless of whether it is a sender or receiver. Using the above mapping allows me to insert transactions, however I am unable to get it back on the mapping. In essence, I am not sure what the best annotations to use are in this case.
I should add, that using the above code, I get the following hibernate error:
Caused by: org.hibernate.AnnotationException: A Foreign key refering com.xxx..Account from com.xxx.Transaction has the wrong number of column. should be 1
Solution
I'm assuming that an Account
can be the sender/receiver in multiple transactions:
Sender and Receiver are actually a
@ManyToOne
:public class Transaction { @Id @GeneratedValue(strategy= GenerationType.AUTO) private Integer id; @ManyToOne(fetch=FetchType.LAZY, optional = false) private Account sender; @ManyToOne(fetch=FetchType.LAZY, optional = false) private Account recipient; private BigDecimal amount; public Transaction(Account sender, Account recipient, BigDecimal amount { this.sender = sender; this.recipient = recipient; this.amount = amount; } }
That's because a single
Account
can be the sender for many transactions, but a singleTransaction
can only have a sender. The same for the receiver. I'm also assuming that all the transactions must have a sender and receiver.@OneToMany
to two different colums.You are creating a one-to-many in
Account
, but which column do you expect to map the association on theTransaction
? Because there are two possible columns containing an account, Hibernate ORM doesn't know which one to use and throws an exception.
Removing the association from Account
should solve your issue:
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private BigDecimal balance;
public Account(final BigDecimal balance) {
this.balance = balance;
}
}
When you need all the transactions for a specific account you can run the following JPQL query. For example, using the EntityManager:
entityManager
.createQuery("FROM Transaction t WHERE t.sender=:account OR t.recipient=:account")
.setParameter("account", account )
.getResultList();
Answered By - Davide