JPA - два составных поля Embeddable с общим столбцом БД? - PullRequest
0 голосов
/ 17 января 2019

Я пытаюсь реализовать решение на основе JPA с использованием доменной разработки, и я предложил вариант использования, для которого я не нашел никакого решения. Я использую JPA с Hibernate и Spring Boot.

Вот упрощенный пример. Допустим, у вас есть объект значения:

@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;
    }

Где CurrencyId - это еще один @Embeddable, содержащий только поле с длинным идентификатором.

Тогда у меня есть сущность с двумя полями:

@Embedded
@AttributeOverrides({
        @AttributeOverride(name="amount", column=@Column(name = "AMOUNT1")),
})
private AmountWithCurrency amount1;

@Embedded
@AttributeOverrides({
        @AttributeOverride(name="amount", column=@Column(name = "AMOUNT2")),
})
private AmountWithCurrency amount2;

Обратите внимание, что я хотел бы, чтобы два поля совместно использовали один и тот же столбец БД CURRENCY_ID в таблице. Очевидно, что если попытаться использовать этот код, я получу следующее исключение:

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)

Я попытался выполнить поиск в Интернете и не нашел решения.

Возможные решения: Просто создайте два отдельных столбца currency1Id и currency2Id в таблице и сопоставьте каждый объект значения с ним - работает, но не использует назначение общей валюты в обоих полях. Я могу справиться с проверкой общей валюты на уровне объекта, но я думаю, что это просто ненужный дизайн для добавления дополнительного столбца БД, если я не хочу его там. Кроме того, если у меня есть что-то вроде ограничений PRIMARY KEY или UNIQUE для таблицы с включенным столбцом, все выходит из-под контроля.

Возможно, какое-то волшебство с крючками жизненного цикла сущности, о которых я не думал?

Спасибо за ваши комментарии, я ценю ваше время.

1 Ответ

0 голосов
/ 18 января 2019

К вашему сведению, я нашел один способ реализовать это, изменив второе поле на пустую сумму - так что внутри есть только одно поле для currencyId. Затем я сделал метод получения для суммы2, который будет восстанавливать полный экземпляр с использованием currencyId из первой суммы. Примерно так:

@Embedded
@AttributeOverrides({
        @AttributeOverride(name="amount", column=@Column(name = "AMOUNT1")),
})
private AmountWithCurrency amount1;

@Column
private BigDecimal amount2;

public AmountWithCurrency getAmount2(){
    return new AmountWithCurrency(amount1.getCurrencyId(), amount2);
}

Это все еще не идеальное решение, поскольку оно все еще может вызывать проблемы в запросах и т. Д. Но, похоже, сейчас работает для меня. Надеюсь, это кому-нибудь поможет.

...