ПЕРЕХОД в СПЯЩИЙ режим с перекрывающимися составными ОСНОВНЫМ и ВНЕШНИМ ключами

#hibernate #spring-data-jpa #composite-primary-key

Вопрос:

У меня есть несколько сущностей:

 @Entity
@Table(name = "cbonus")
public class BonusEntity {
    @EmbeddedId
    @AttributeOverride(name = "id", column = @Column(name = "id"))
    @AttributeOverride(name = "clusterId", column = @Column(name = "cluster_id"))
    private BonusId bonusId;
    private boolean released;
    
    @ManyToOne(targetEntity = AccountEntity.class, optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", insertable = false, updatable = false)
    @JoinColumn(name = "bank_id", referencedColumnName = "bank_id", insertable = false, updatable = false)
    @JoinColumn(name = "user_id", referencedColumnName = "user_id", insertable = false, updatable = false)
    private AccountEntity account;
}

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

    @EmbeddedId
    @AttributeOverride(name = "clusterId", column = @Column(name = "cluster_id"))
    @AttributeOverride(name = "bankId", column = @Column(name = "bank_id"))
    @AttributeOverride(name = "userId", column = @Column(name = "user_id"))
    @NotNull
    private AccountId accountId;

    // other fields
}
 

Когда я пытаюсь сохранить новую запись cbonus, у меня есть исключение:

org.postgresql.util.Исключение PSQLException: ОШИБКА: значение null в столбце «bank_id» отношения «cbonus» нарушает ограничение not-null Подробно: Неудачная строка содержит (773, gp3, null, null, f).

и запрос

ОТЛАДКА 24817 — [nio-8080-exec-4] org.hibernate.SQL
: вставка в значения cbonus (выпущено, идентификатор кластера, идентификатор) (?, ?, ?)

Непосредственно перед сохранением в объекте заполнены все поля. Я попытался удалить ограничения на нулевое значение, но тогда значения просто останутся НУЛЕВЫМИ. Я думаю, что причина в наложении составного первичного ключа и составного внешнего ключа.

Как я могу справиться с этим с помощью Hibernate?

схемы бд:

 CREATE TABLE cbonus
(
    id         BIGINT                NOT NULL,
    cluster_id TEXT                  NOT NULL,
    bank_id    BIGINT                NOT NULL,
    user_id    TEXT                  NOT NULL,
    released   BOOLEAN DEFAULT FALSE NOT NULL,
    FOREIGN KEY (cluster_id, bank_id, user_id) REFERENCES account,
    PRIMARY KEY (id, cluster_id)
);

CREATE TABLE account
(
    cluster_id TEXT       NOT NULL,
    bank_id    BIGINT     NOT NULL,
    user_id    TEXT       NOT NULL,
    -- [other fields]
    PRIMARY KEY (cluster_id, bank_id, user_id)
);
 

Ответ №1:

Ваше отображение неверно. Столбец bank_id никогда не будет «доступен для записи» в соответствии с вашими настройками. Тебе это нужно:

     @AttributeOverride(name = "id", column = @Column(name = "id"))
    @AttributeOverride(name = "clusterId", column = @Column(name = "pk_cluster_id"))
    private BonusId bonusId;

    @ManyToOne(targetEntity = AccountEntity.class, optional = false, fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas({
       @JoinColumnOrFormula(column = @JoinColumn(name = "bank_id", referencedColumnName = "bank_id")),
       @JoinColumnOrFormula(column = @JoinColumn(name = "user_id", referencedColumnName = "user_id")),
       @JoinColumnOrFormula(formula = @JoinFormula(value = "cluster_id", referencedColumnName = "cluster_id"))
    private AccountEntity account;

    })
 

и некоторое исправление схемы:

 CREATE TABLE command_response
(
    id                   BIGSERIAL PRIMARY KEY,
    pk_cluster_id        TEXT                    NOT NULL,
    cluster_id           TEXT                    NOT NULL,
    bank_id              BIGINT                  NOT NULL,
    ...
    FOREIGN KEY (cluster_id, bank_id, user_id) REFERENCES account,
    PRIMARY KEY (id, pk_cluster_id)
 

Комментарии:

1. Спасибо, ты был отчасти прав. Кроме того, мы должны разделить перекрывающиеся компоненты primary_keys по разным столбцам.