Составной ключ Hibernate и перекрывающиеся поля - как избежать дублирования столбцов - PullRequest
0 голосов
/ 20 февраля 2019

У меня проблема с управлением отображением для конкретной модели.

Это мультитенантное приложение, и мы решили включить «tenant_id» в каждую сущность, поэтому мы не будеммы должны объединяться каждый раз, когда нам нужно получить сущность (на самом деле, это корень моей проблемы ...).

Модель выглядит следующим образом:

+--------------------+   +---------------+
|        Book        |   |    Author     |
+--------------------+   +---------------+
| id (pk)            |   | id (pk)       |
| tenant_id (pk)(fk) |   | tenant_id (pk |
| author_id (fk)     |   | name          |
| title              |   +---------------+
+--------------------+

Как видите, идентификатор клиента находится в каждой сущности и является частью первичного ключа.Мы используем @IdClass для управления составным ключом.Вот код:


    @Data
    public class TenantAwareKey implements Serializable {

        private UUID id;
        private Integer tenantId;
    }


    @IdClass(TenantAwareKey.class)
    @Entity
    @Table(name = "BOOK")
    @Data
    public class Book {

        @Id
        @GeneratedValue
        @Column(name = "ID")
        private UUID id;
        @Id
        @Column(name = "TENANT_ID")
        private Integer tenantId;

        private String title;

        @ManyToOne
        @JoinColumns(
            value = {
                @JoinColumn(referencedColumnName = "id", name = "author_id"),
                @JoinColumn(referencedColumnName = "tenant_id", name = "tenant_id", insertable = false, updatable = false)
            })
        private Author author;   
    }


    @IdClass(TenantAwareKey.class)
    @Entity
    @Data
    public class Author {
        @Id
        @GeneratedValue
        @Column(name = TenantAwareConstant.ENTITY_ID_COLUMN_NAME)
        private UUID id;
        @Id
        @Column(name = TenantAwareConstant.TENANT_ID_COLUMN_NAME)
        private Integer tenantId;

        private String name;
    }

И затем, когда я запускал свое приложение, у меня получалось:


    Caused by: org.hibernate.AnnotationException: Mixing insertable and non insertable columns in a property is not allowed: 
    com.pharmagest.durnal.tenant.entity.BookNoDuplicateColumn.author
        at org.hibernate.cfg.Ejb3Column.checkPropertyConsistency(Ejb3Column.java:725)
        at org.hibernate.cfg.AnnotationBinder.bindManyToOne(AnnotationBinder.java:3084)
    (...)

Мне удается заставить его работать, если я нене пытайтесь «взаимно объединить» столбец tenant_id, это может быть приемлемо, когда у меня есть только один внешний ключ с этим tenant_id, но все меньше и меньше с увеличением числа внешних ключей, что приводит к добавлению столбца tenant_id каждый раз, дублированию информации и т. д.портит память ...

Немного покопавшись, я обнаружил в Hibernate открытую проблему: https://hibernate.atlassian.net/browse/HHH-6221

Она не исправлялась годами ... Итак, мой вопросявляется: Вы сталкивались с таким отображением, и есть ли решение, чтобы избежать дублирования столбца, когда у меня есть внешний ключ, который разделяет поле с первичным ключом?

1 Ответ

0 голосов
/ 21 февраля 2019

Как описано здесь , вы можете обойти проверку, используя @JoinColumnOrFormula для столбца id_tenant.

Вы должны сопоставить ассоциацию автора следующим образом:

    @JoinColumnsOrFormulas(
        value = {
                @JoinColumnOrFormula(column = @JoinColumn(referencedColumnName = "id", name = "author_id")),
                @JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "tenant_id", value = "tenant_id"))
        })
...