Подтвердить что ты не робот

Multi-Column Присоединиться к Hibernate/JPA Аннотации

У меня есть два объекта, которые я хотел бы объединить через несколько столбцов. Эти столбцы разделяются объектом @Embeddable, который совместно используется обеими объектами. В приведенном ниже примере Foo может иметь только один Bar, но Bar может иметь несколько Foo (где AnEmbeddableObject - уникальный ключ для Bar). Вот пример:

@Entity
@Table(name = "foo")
public class Foo {
    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "seqGen")
    @SequenceGenerator(name = "seqGen", sequenceName = "FOO_ID_SEQ", allocationSize = 1)
    private Long id;
    @Embedded
    private AnEmbeddableObject anEmbeddableObject;
    @ManyToOne(targetEntity = Bar.class, fetch = FetchType.LAZY)
    @JoinColumns( {
        @JoinColumn(name = "column_1", referencedColumnName = "column_1"),
        @JoinColumn(name = "column_2", referencedColumnName = "column_2"),
        @JoinColumn(name = "column_3", referencedColumnName = "column_3"),
        @JoinColumn(name = "column_4", referencedColumnName = "column_4")
    })
    private Bar bar;

    // ... rest of class
}

И класс Bar:

@Entity
@Table(name = "bar")
public class Bar {
    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "seqGen")
    @SequenceGenerator(name = "seqGen", sequenceName = "BAR_ID_SEQ", allocationSize = 1)
    private Long id;
    @Embedded
    private AnEmbeddableObject anEmbeddableObject;

    // ... rest of class
}

Наконец, класс AnEmbeddedObject:

@Embeddable
public class AnEmbeddedObject {
    @Column(name = "column_1")
    private Long column1;
    @Column(name = "column_2")
    private Long column2;
    @Column(name = "column_3")
    private Long column3;
    @Column(name = "column_4")
    private Long column4;

    // ... rest of class
}

Очевидно, что схема плохо нормализована, это ограничение, что в каждой таблице повторяются поля AnEmbeddedObject.

Проблема заключается в том, что я получаю эту ошибку, когда я пытаюсь запустить Hibernate:

org.hibernate.AnnotationException: referencedColumnNames(column_1, column_2, column_3, column_4) of Foo.bar referencing Bar not mapped to a single property

Я пробовал отмечать, что JoinColumns не могут быть вставлены и обновлены, но без везения. Есть ли способ выразить это с помощью аннотаций Hibernate/JPA?

4b9b3361

Ответ 1

Это сработало для меня. В моем случае 2 таблицы foo и boo должны быть объединены на основе трех разных столбцов. Обратите внимание, что в моем случае три общих столбца не являются первичным ключом

i.e., одно к одному отображение на основе трех разных столбцов

@Entity
@Table(name = "foo")
public class foo implements Serializable
{
    @Column(name="foocol1")
    private String foocol1;
    //add getter setter
    @Column(name="foocol2")
    private String foocol2;
    //add getter setter
    @Column(name="foocol3")
    private String foocol3;
    //add getter setter
    private Boo boo;
    private int id;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "brsitem_id", updatable = false)
    public int getId()
    {
        return this.id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
    @OneToOne
    @JoinColumns(
    {
        @JoinColumn(updatable=false,insertable=false, name="foocol1", referencedColumnName="boocol1"),
        @JoinColumn(updatable=false,insertable=false, name="foocol2", referencedColumnName="boocol2"),
        @JoinColumn(updatable=false,insertable=false, name="foocol3", referencedColumnName="boocol3")
    }
    )
    public Boo getBoo()
    {
        return boo;
    }
    public void setBoo(Boo boo)
    {
        this.boo = boo;
    }
}





@Entity
@Table(name = "boo")
public class Boo implements Serializable
{
    private int id;
    @Column(name="boocol1")
    private String boocol1;
    //add getter setter
    @Column(name="boocol2")
    private String boocol2;
    //add getter setter
    @Column(name="boocol3")
    private String boocol3;
    //add getter setter
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "item_id", updatable = false)
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
}

Ответ 2

Если это не работает, у меня нет идей. Таким образом вы получаете 4 столбца в обеих таблицах (как Bar принадлежит им, а Foo использует их для ссылки Bar) и сгенерированные идентификаторы в обоих объектах. Набор из 4 столбцов должен быть уникальным в Bar, поэтому отношение "много-к-одному" не становится много-ко-многим.

@Embeddable
public class AnEmbeddedObject
{
    @Column(name = "column_1")
    private Long column1;
    @Column(name = "column_2")
    private Long column2;
    @Column(name = "column_3")
    private Long column3;
    @Column(name = "column_4")
    private Long column4;
}

@Entity
public class Foo
{
    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "seqGen")
    @SequenceGenerator(name = "seqGen", sequenceName = "FOO_ID_SEQ", allocationSize = 1)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
        @JoinColumn(name = "column_1", referencedColumnName = "column_1"),
        @JoinColumn(name = "column_2", referencedColumnName = "column_2"),
        @JoinColumn(name = "column_3", referencedColumnName = "column_3"),
        @JoinColumn(name = "column_4", referencedColumnName = "column_4")
    })
    private Bar bar;
}

@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {
    "column_1",
    "column_2",
    "column_3",
    "column_4"
}))
public class Bar
{
    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "seqGen")
    @SequenceGenerator(name = "seqGen", sequenceName = "BAR_ID_SEQ", allocationSize = 1)
    private Long id;
    @Embedded
    private AnEmbeddedObject anEmbeddedObject;
}

Ответ 3

Hibernate не поможет вам сделать то, что вы пытаетесь сделать. Из Hibernate documentation:

Обратите внимание, что при использовании ссылочного столбца ColumnName в столбце не первичного ключа связанный класс должен быть Serializable. Также обратите внимание, что ссылочное имяColumnName в столбец не первичного ключа должно быть сопоставлено с свойством, имеющим один столбец (другие случаи могут не работать). (выделено курсивом)

Итак, если вы не желаете сделать AnEmbeddableObject идентификатор для бара, то Hibernate не будет лениво, автоматически получить Bar для вас. Вы, конечно, можете использовать HQL для записи запросов, которые присоединяются к AnEmbeddableObject, но вы теряете автоматическое извлечение и поддержание жизненного цикла, если настаиваете на использовании многоколоночного непервичного ключа для Bar.