Проблемы с отображением JPA / Hibernate @OneToMany List (с @OrderColumn) с помощью @JoinTable - PullRequest
0 голосов
/ 03 мая 2018

Я новичок в JPA и изучаю книгу «Сохранение Java с Hibernate 2nd Edition». У меня возникают некоторые трудности в отображении двунаправленного списка @OneToMany (с @OrderColumn) с помощью @JoinTable. У меня не было проблем с @JoinColumn, но, похоже, я что-то не так делаю в случае @JoinTable. Я привел мой пример ниже.

КЛАСС АДРЕСА:

@Entity
@Table(name = "ADDRESS")
public class Address {
    @Id
    @GeneratedValue(generator = "MY_ID_GENERATOR")
    @Column(name="_ADDRESS_ID")
    private Long addressId;

    @NotNull
    @Column(name="_CITY", nullable = false)
    protected String city;

    //-------------------------------------
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinTable(
        name = "ADDRESS_LIST",
        joinColumns = {@JoinColumn(name = "_A_ID", unique = true, updatable = false, insertable = false, referencedColumnName = "_ADDRESS_ID")},
        inverseJoinColumns = {@JoinColumn(name = "_P_ID", updatable = false, insertable = false, referencedColumnName = "_PERSON_ID")}
    )
    private Person person;
    //-------------------------------------

    protected Address() {}
    public Address(@NotNull String city) {
        super();
        this.city = city;
    }
    public Address(@NotNull String city, Person person) {
        super();
        this.city = city;
        this.person = person;
    }
    public Long getId() { return addressId; }
    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }
    public Person getPerson() { return person; }
    public void setPerson(Person person) { this.person = person; }
}

КЛАСС ЧЕЛОВЕКА:

@Entity
@Table(name = "PERSON")
public class Person {
    @Id
    @GeneratedValue(generator = "MY_ID_GENERATOR")
    @Column(name="_PERSON_ID")
    private Long personId;

    @NotNull
    @Column(name="_NAME", nullable = false, length = 50)
    private String name;

    //-------------------------------------
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, orphanRemoval = true)
    @JoinTable(
        name = "ADDRESS_LIST",
        joinColumns = {@JoinColumn(name = "_P_ID", referencedColumnName = "_PERSON_ID")},
        inverseJoinColumns = {@JoinColumn(name = "_A_ID", unique = true, referencedColumnName = "_ADDRESS_ID")}
    )
    @OrderColumn(name = "_ORDER", nullable = false)
    private List<Address> addressList = new ArrayList<>();
    //-------------------------------------

    public Person() {
        super();
    }
    public Person(@NotNull String name) {
        super();
        this.name = name;
    }
    public Long getPersonId() { return personId; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public List<Address> getAddressList() { return addressList; }
    public void setAddressList(List<Address> addressList) { this.addressList = addressList; }
}

Теперь в основном классе, если я забочусь о обеих сторонах ассоциации, это не работает !!

Person person = new Person("Sourangshu Biswas");
person.getAddressList().add(new Address("Siliguri", person));
person.getAddressList().add(new Address("Kolkata", person));
person.getAddressList().add(new Address("Chennai", person));

Ошибка выдачи !!

Caused by: java.sql.SQLException: Field '_P_ID' doesn't have a default value.

Но если я не передам объект "персона" в констриктор "Address ()", он работает.

Person person = new Person("Sourangshu Biswas");
person.getAddressList().add(new Address("Siliguri"));
person.getAddressList().add(new Address("Kolkata"));
person.getAddressList().add(new Address("Chennai"));

Я проверил базу данных, я также получаю значения в столбце "_ORDER" !! Но вопрос в том, как это работает !! Насколько мне известно, мы должны заботиться о обеих сторонах в двунаправленной ассоциации. Почему он не работает, когда я передаю объект "person" в константу "Address ()" !!!! ?? Объект «человек» еще не сохранился, вот почему? Но то же самое я делал в других типах (SET / BAG) картографирования, тогда это работало.

1 Ответ

0 голосов
/ 31 мая 2018

ПРИМЕЧАНИЕ. Это двунаправленное отображение LIST, и я также хочу использовать OrderColumn. Согласно книге «Java Persistence With Hibernate 2nd Edition» (стр. 185), этот случай является исключением.

В книге упоминается обходной путь для создания упорядоченной двунаправленной ассоциации «один ко многим» с использованием столбца соединения , который сильно отличается. Здесь вы фактически создали две отдельные ассоциации, которые используют одну и ту же таблицу соединений. Сейчас:

если я не передам объект "персона" в констриктор "Address ()", он работает.

Если для Address.person установлено значение null, Hibernate не пытается сохранить связь «многие к одному». Следовательно, генерируется один оператор INSERT (хранится только связь один-ко-многим):

INSERT INTO ADDRESS_LIST(_P_ID, _A_ID) VALUES (?, ?);

в основном классе, если я забочусь о обеих сторонах ассоциации, она не работает !!

Если вы добавите Address в Person.addressList и назначите ненулевое Person для Address.person, Hibernate попытается сохранить обе ассоциации. Будут сгенерированы два оператора INSERT: один для связи один-ко-многим (аналогично приведенному выше), а другой для ассоциации много-к-одному - что-то вроде:

INSERT INTO ADDRESS_LIST() VALUES ();

Почему пустой список столбцов и пустой список значений? Поскольку вы пометили оба столбца соединения в таблице соединений insertable=false. База данных жалуется, что значение для столбца _P_ID отсутствует - и это понятно, поскольку _P_ID не может быть NULL, и нет значения по умолчанию для использования.

Конечно, если вы отбросите insertable=false, оба оператора INSERT будут идентичны, что приведет либо к нарушению ограничения, либо к повторяющейся строке в ADDRESS_LIST.

Короче говоря: вы не должны «заботиться о обеих сторонах ассоциации», потому что это не двунаправленная ассоциация - на самом деле это две совершенно разные.

Обратите внимание, что для обходного пути, аналогичного подходу к работе со столбцами соединений, вам нужно будет пометить все @JoinTable "многие-к-одному" как insertable=false, а не только отдельные столбцы объединения - что-то JPA не поддерживает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...