2009-02-02 18 views
7

Ich verstehe nicht das Verhalten von Hibernate beim Mapping einer bidirektionalen Liste. Die SQL-Anweisungen, die Hibernate erzeugt, scheinen mir nicht optimal zu sein. Kann mich jemand aufklären?Mapping einer bidirektionalen Liste mit Hibernate

Das Szenario ist das folgende: Ich habe eine Eins-zu-viele-Eltern-Kind-Beziehung. Ich ordnet diese Beziehung einer bidirektionalen Liste zu.

Nach dem Hibernate Annotation Reference Guide (Kapitel: Bidirektionale Verbindung mit indexierten Sammlungen) der Abbildung sollte wie folgt aussehen:

@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; 

... 

Aber in diesem Fall Hibernate produziert drei SQL-Anweisungen, wenn ein Elternteil mit einem Kind persistierenden:

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=? 

Die dritte Anweisung scheint redundant zu sein, denn parent_id und parent_index scheinen bereits in der zweiten Anweisung gesetzt zu sein.

Wenn ich die Zuordnung ändern, und wiederholen Sie die Attribute 'aktualisierbar = false, einführbar = false' auf die Erklärung des @JoinColumn in der Eltern wie folgt aus:

@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; 

... 

... dann Hibernate scheint viel optimierte SQL zu erzeugen:

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

Der Client-Code wie folgt aussieht:

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(); 

Ich benutze Hibernate-Entitymanager 3.4.0.GA.

Was fehlt mir? Ist der Hibernate Reference Guide nicht korrekt oder übersehe ich etwas?

Antwort

6

Ok, ich habe das Annotations-Referenzhandbuch nicht gründlich genug gelesen.

In Kapitel 2.2.5.3.1.1. Bidirectional klar gesagt wird:

Um eine bidirektionale one to many Karte, mit der One-to-many-Seite wie die besitzende Seite haben Sie die mappedBy Element zu entfernen und legen Sie die vielen zu einer @JoinColumn als einfügbar und aktualisierbar auf false. Diese Lösung ist offensichtlich nicht optimiert und wird einige zusätzliche UPDATE-Anweisungen erzeugen.

Es würde wahrscheinlich nicht schaden, diese Information in Chapter 2.4.6.2.1. Bidirectional association with indexed collections zu wiederholen.

Nun bleibt die Frage: wenn ich die @JoinColumn Attribute 'updatable = false' und 'insertable = false' im Parent (siehe Code im ersten Post) wiederhole, werden die zusätzlichen Updateanweisungen nicht erzeugt ... das eine legitime Problemumgehung? Oder führt dies zu einem anderen Problem?