I am trying to implement a JPA-based solution using Domain Driven Development and I have encoutered a use case that I did not find any solution to. I am using JPA with Hibernate and Spring Boot.
Here is a simplified example. Lets say you have a value object:
@Embeddable
public class AmountWithCurrency {
private BigDecimal amount;
@Embedded
@AttributeOverride(name="id", column=@Column(name = "CURRENCY_ID"))
private CurrencyId currencyId;
protected AmountWithCurrency() {
//for JPA
}
public AmountWithCurrency(BigDecimal amount, CurrencyId currencyId) {
this.amount = amount;
this.currencyId = currencyId;
}
Where CurrencyId is another @Embeddable with just an Long id field.
Then I have an entity with two fields:
@Embedded
@AttributeOverrides({
@AttributeOverride(name="amount", column=@Column(name = "AMOUNT1")),
})
private AmountWithCurrency amount1;
@Embedded
@AttributeOverrides({
@AttributeOverride(name="amount", column=@Column(name = "AMOUNT2")),
})
private AmountWithCurrency amount2;
Note that I would like the two fields to share the same DB Column CURRENCY_ID in the table. Obviously, if try to use this code, I would get this exception:
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Repeated column in mapping for entity: com.MyEntity column: currency_id (should be mapped with insert="false" update="false")
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:402)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
I have tried searching online and did not find any solution.
Possible solutions: Just create two distinct currency1Id and currency2Id columns in the table and map each value object to it - works, but defeats the purpose of a shared currency on both fields. I can handle the shared currency validation on entity-level, but I think this is just an unnecessary design to add extra db column if I don't want it there. Also, if I have something like PRIMARY KEY or UNIQUE constraints on the table with the column involved, things get out of control.
Perhaps some magic with entity lifecycle hooks I did not think about?
Thank you for your comments, I appreciate your time.