2013-05-30 4 views
5

Ich habe eine Frage zu Hibernate und Order-by-Klausel. Ich habe eine MySQL-Datenbank mit 3 Tabellen: A, B und C. Der Java-Code für diese Tabellen ist nachfolgend.Komplexe Order-by-Klausel in .hbm Hibernate-Dateien

Klasse A Code:

package database; 

import java.util.Set; 

public class A implements java.io.Serializable { 

    private Integer id; 
    private Set<B> listB; 

    public A() { 
    } 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public Set<B> getListB() { 
     return listB; 
    } 

    public void setListB(Set<B> listB) { 
     this.listB = listB; 
    } 

} 

Klasse B Code:

package database; 

public class B implements java.io.Serializable { 

    private Integer id; 
    private A a; 
    private C c; 

    public B() { 
    } 

    public Integer getId() { 
     return this.id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public A getA() { 
     return a; 
    } 

    public void setA(A a) { 
     this.a = a; 
    } 

    public C getC() { 
     return c; 
    } 

    public void setC(C c) { 
     this.c = c; 
    } 
} 

Klasse C-Code:

package database; 

public class C implements java.io.Serializable { 

    private Integer id; 
    private int num; 

    public C() { 
    } 

    public Integer getId() { 
     return this.id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public int getNum() { 
     return this.num; 
    } 

    public void setNum(int num) { 
     this.num = num; 
    } 
} 

Die zugehörigen .hbm Dateien sind hier

Tabelle A Zuordnung:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > 
<hibernate-mapping package="database"> 
    <class name="A" table="A"> 
     <id 
      column="id" 
      name="Id" 
      type="integer" 
     > 
      <generator class="increment" /> 
     </id> 
     <set name="listB" cascade="all, delete-orphan" inverse="true" lazy="true" fetch="select" order-by="c.Id asc"> 
      <key column="a_id"/> 
      <one-to-many class="B"/> 
     </set> 
    </class> 
</hibernate-mapping> 

Tabelle B-Mapping:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > 
<hibernate-mapping package="database"> 
    <class name="B" table="B"> 
     <id 
      column="id" 
      name="Id" 
      type="integer" 
     > 
      <generator class="increment" /> 
     </id> 
     <many-to-one name="a" class="A" fetch="select"> 
      <column name="a_id" not-null="true" /> 
     </many-to-one> 
     <many-to-one name="c" class="C" fetch="select"> 
      <column name="c_id" not-null="true" /> 
     </many-to-one> 
    </class> 
</hibernate-mapping> 

Tabelle C-Mapping:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > 
<hibernate-mapping package="database"> 
    <class name="C" table="C"> 
     <id 
      name="Id" 
      type="integer" 
      column="id" 
     > 
      <generator class="increment"/> 
     </id> 
     <property 
      name="Num" 
      column="num" 
      type="integer" 
      not-null="true" 
      length="10" 
     /> 
    </class> 
</hibernate-mapping> 

Meine Frage bezieht sich auf die "Order-by-Klausel" in der A.hbm Datei. Ich möchte nicht nach c.Id bestellen, aber c.Num

<set name="listB" cascade="all, delete-orphan" inverse="true" lazy="true" fetch="select" order-by="c.Num asc"> 

Unfortunatly, wenn ich dies tun, ich die folgende Ausnahme erhalten:

Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not initialize a collection: [database.A.listB#1] 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 
    at org.hibernate.loader.Loader.loadCollection(Loader.java:2069) 
    at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:62) 
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:628) 
    at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:83) 
    at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1853) 
    at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:366) 
    at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108) 
    at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186) 
    at Test.main(Test.java:36) 
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'listb0_.c.Num' in 'order clause' 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) 
    at java.lang.reflect.Constructor.newInstance(Unknown Source) 
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) 
    at com.mysql.jdbc.Util.getInstance(Util.java:386) 
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1054) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4120) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4052) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2503) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2664) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815) 
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155) 
    at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2322) 
    at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208) 
    at org.hibernate.loader.Loader.getResultSet(Loader.java:1849) 
    at org.hibernate.loader.Loader.doQuery(Loader.java:718) 
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:270) 
    at org.hibernate.loader.Loader.loadCollection(Loader.java:2062) 
    ... 8 more 

Ich bin hier zu überwintern, ich lese einige Dinge über Kriterien, die mir helfen könnten, aber ich sehe nicht, wie man sie in hbm-Dateien verwendet.

Danke für die Hilfe,

Lauriane

Nach den Ideen versucht du mir gegeben hast, habe ich noch nicht die Antwort. Zuerst schrieb ich die folgende Methode, um Daten in die Datenbank eingeben:

private static void create() { 
    A a = new A(); 
    HibernateUtil.save(a); 

    C c1 = new C(); 
    c1.setNum(5); 
    HibernateUtil.save(c1); 

    C c2 = new C(); 
    c2.setNum(2); 
    HibernateUtil.save(c2); 

    C c3 = new C(); 
    c3.setNum(7); 
    HibernateUtil.save(c3); 

    C c4 = new C(); 
    c4.setNum(3); 
    HibernateUtil.save(c4); 

    B b1 = new B(); 
    b1.setA(a); 
    b1.setC(c1); 
    HibernateUtil.save(b1); 

    B b2 = new B(); 
    b2.setA(a); 
    b2.setC(c4); 
    HibernateUtil.save(b2); 

    B b3 = new B(); 
    b3.setA(a); 
    b3.setC(c3); 
    HibernateUtil.save(b3); 

    B b4 = new B(); 
    b4.setA(a); 
    b4.setC(c2); 
    HibernateUtil.save(b4); 

    A a2 = new A(); 
    HibernateUtil.save(a2); 

    C c5 = new C(); 
    c5.setNum(13); 
    HibernateUtil.save(c5); 

    C c6 = new C(); 
    c6.setNum(11); 
    HibernateUtil.save(c6); 

    C c7 = new C(); 
    c7.setNum(10); 
    HibernateUtil.save(c7); 

    C c8 = new C(); 
    c8.setNum(14); 
    HibernateUtil.save(c8); 

    B b5 = new B(); 
    b5.setA(a2); 
    b5.setC(c5); 
    HibernateUtil.save(b5); 

    B b6 = new B(); 
    b6.setA(a2); 
    b6.setC(c8); 
    HibernateUtil.save(b6); 

    B b7 = new B(); 
    b7.setA(a2); 
    b7.setC(c7); 
    HibernateUtil.save(b7); 

    B b8 = new B(); 
    b8.setA(a2); 
    b8.setC(c6); 
    HibernateUtil.save(b8); 
} 

Es gibt mir zwei Instanzen von A, das jeweils mit einer Liste von vier Instanzen von B.

Dann habe ich versucht, diesen Code:

Criteria crit = HibernateUtil.currentSession().createCriteria(A.class); 
Criteria critb = crit.createCriteria("listB"); 
Criteria critc = critb.createCriteria("c"); 
critc.addOrder(Order.asc("num")); 
List<A> list = critc.list(); 
    // Code to iterate over listA 
    for (A a : list) { 

     List<B> listB = a.getListB(); 
     for (B b : listB) { 

      System.out.print(b.getC().getNum() + ", "); 

     } 
     System.out.println(); 
    } 

Die Liste I erhalten enthält 4 mal jede Instanz von A, und der Ausgang ist:

2, 7, 3, 5, 
2, 7, 3, 5, 
2, 7, 3, 5, 
2, 7, 3, 5, 
14, 13, 10, 11, 
14, 13, 10, 11, 
14, 13, 10, 11, 
14, 13, 10, 11, 

Also habe ich versucht, den Getter zu ändern ListeB in der A-Klasse an:

public List<B> getListB() { 
      Criteria crit = 
    HibernateUtil.currentSession().createCriteria(B.class); 
    Criteria critc = crit.createCriteria("c"); 
    critc.addOrder(Order.asc("num")); 
    return critc.list(); 
} 

und führen Sie den folgenden Code ein:

List<A> list = (List<A>) HibernateUtil.getList("from A"); 
    for (A a : list) { 

     List<B> listB = a.getListB(); 
     for (B b : listB) { 

      System.out.print(b.getC().getNum() + ", "); 

     } 
     System.out.println(); 

    } 

Und der Ausgang war:

2, 3, 5, 7, 10, 11, 13, 14, 
2, 3, 5, 7, 10, 11, 13, 14, 

Es gibt keinen Unterschied zwischen den Instanzen von B refering auf die eine oder andere Instanz von A, und ich sehe nicht, wie es funktionieren könnte gemacht ist ..

.

Danke für Ihre Hilfe,

Lauriane

+0

mit Anmerkungen und JPA beginnen kann ich denke, es könnte hilfreich sein, wenn Sie sich die von Hibernate generierte SQL ansehen und posten. – Carsten

Antwort

4

Bitte richtige Eigenschaftsnamen "Num" auf "num" für C-Klasse-Mapping.

  1. ORDER BY-Klausel in A

    • Sie werden nicht in der Lage sein, um von A auf C eingestellt werden, wie A nicht direkt an C.
    • Der Grund, warum es für c gearbeitet verbunden ist .id ist, weil B die Spalte c_id (C-Klassenzuordnung) enthält und die Klausel order by in Spalte c_id in Tabelle B und nicht in Spalte id auf C
    • angewendet wird. Wenn Sie c.num festlegen, versucht der Ruhezustand, die Spalte zu suchen Tabelle B, die wir nicht haben.
  2. Criteria Abfrage

    • Kriterien verwenden Abfrage erste Order-by-Klausel von A entfernen oder gültige
    • Criteria Abfrage ist in Java-Code verwenden "Session" erstellt werden und nicht in der hbm-Datei konfiguriert.

Beispielcode

Criteria crit = session.createCriteria(A.class); 
Criteria critb = crit.createCriteria("listB"); 
Criteria critc = critb.createCriteria("c"); 
critc.addOrder(Order.asc("num")); 
List<A> listA = critc.list(); 
// Code to iterate over listA 

A.java

// remove listB and add following 
private Set<C> listC; 
// Add getters/setters 

Mapping für A

// remove listB mapping and add following 
<set name="listC" table="b" fetch="select" inverse="true"> 
    <key column="a_id"/> 
    <many-to-many column="c_id" unique="true" class="C" order-by="num asc" /> 
</set> 

Java-Code

Criteria crit = session.createCriteria(A.class); 
List<A> listA = crit.setFetchMode("listC", FetchMode.JOIN).list(); 
// iterate or use listA 

Der einzige Nachteil ist, B nicht unabhängig verwaltet werden können, und Sie müssen Spalte "id" von B entfernen und a_id machen und c_id als zusammengesetzter Primärschlüssel für die Einfüge-/Aktualisierungs-/Löschoperation, für ausgewählte Abfragen über Änderungen sind ausreichend.


+0

Tatsache ist, dass ich es nicht verstehe. Wo muss ich den Kriteriencode schreiben? Wenn ich es in die Methode "getListB()" von A schreibe, bekomme ich alle Instanzen von B, auch solche, die nicht mit A verknüpft sind. Ansonsten, wenn ich es schreibe, bevor ich eine Instanz von A erhalte, gibt es keine Reihenfolge. – user2436719

+0

müssen Sie beispielsweise in eine DAO-Klasse schreiben – nachokk