Отображение двунаправленного списка с помощью Hibernate - PullRequest
7 голосов
/ 03 февраля 2009

Я не понимаю поведение Hibernate при отображении двунаправленного списка. Операторы SQL, которые создает Hibernate, кажутся мне неоптимальными. Может ли кто-нибудь просветить меня?

Сценарий следующий: у меня отношения один-ко-многим родитель-ребенок. Я сопоставляю эти отношения с двунаправленным списком.

В соответствии с Справочным руководством по Hibernate (Глава: Двунаправленная связь с индексированными коллекциями) отображение должно выглядеть следующим образом:

@Entity
public class Parent {

    @Id  @GeneratedValue private long id;
    @Version  private int version;
    private String name;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "parent_id", nullable=false)
    @org.hibernate.annotations.IndexColumn(name = "parent_index")
    List<Child> children = new ArrayList<Child>();

...

@Entity
public class Child {

    @Id @GeneratedValue private Long id;
    @Version private int version;
    private String name;

    @ManyToOne
    @JoinColumn(name = "parent_id", updatable = false, insertable = false, nullable=false)
    private Parent parent;

...

Но в этом случае Hibernate создает три оператора SQL при сохранении родителя с одним дочерним элементом:

Hibernate: insert into Parent (name, version, id) values (?, ?, ?)
Hibernate: insert into Child (name, price, version, parent_id, parent_index, id) values (?, ?, ?, ?, ?, ?)
Hibernate: update Child set parent_id=?, parent_index=? where id=?

Третье утверждение представляется излишним, поскольку parent_id и parent_index, похоже, уже заданы во втором утверждении.

Когда я изменяю отображение и повторяю атрибуты ' updatable = false, вставляемый = false ' для объявления @ JoinColumn в Parent следующим образом:

@Entity
public class Parent {

    @Id  @GeneratedValue private long id;
    @Version  private int version;
    private String name;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "parent_id", updatable = false, insertable = false, nullable=false)
    @org.hibernate.annotations.IndexColumn(name = "parent_index")
    List<Child> children = new ArrayList<Child>();

...

@Entity
public class Child {

    @Id @GeneratedValue private Long id;
    @Version private int version;
    private String name;

    @ManyToOne
    @JoinColumn(name = "parent_id", updatable = false, insertable = false, nullable=false)
    private Parent parent;

...

... тогда Hibernate производит гораздо более оптимизированный SQL:

Hibernate: insert into Parent (name, version, id) values (?, ?, ?)
Hibernate: insert into Child (name, price, version, parent_id, parent_index, id) values (?, ?, ?, ?, ?, ?)

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

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();

    Parent newParent = new Parent();
    newParent.setName("Parent1");

    Child newChild = new Child();
    newChild.setName("Child1");

    newParent.getChildren().add(newChild);
    newChild.setParent(newParent);

    em.persist(newParent);

    em.flush();
    tx.commit();

Я использую hibernate-entitymanager 3.4.0.GA.

Что мне не хватает? Справочное руководство по Hibernate неверно или я что-то упускаю?

1 Ответ

6 голосов
/ 07 февраля 2009

Хорошо, я недостаточно внимательно читал Справочное руководство по аннотациям.

В главе 2.2.5.3.1.1. Двунаправленный четко указано:

Чтобы отобразить двунаправленный канал «один-ко-многим» со стороной «один-ко-многим» в качестве стороны-владельца, вы должны удалить элемент mappedBy и установить для «многие» один «@JoinColumn» для вставки и обновления для «ложь». Это решение, очевидно, не оптимизировано и выдаст несколько дополнительных операторов UPDATE .

Вероятно, не помешает повторить эту информацию в Глава 2.4.6.2.1. Двунаправленная связь с проиндексированными коллекциями .

Теперь остается вопрос: если я повторю атрибуты @JoinColumn 'updatable = false' и 'inserttable = false' на Parent (см. Код в первом посте), дополнительные операторы обновления, похоже, не создаются ... это законный обходной путь? Или это приводит к другой проблеме?

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