2013-05-30 12 views
5

Ho una domanda sull'ibernazione e sulla clausola order-by. Ho un database mySQL contenente 3 tabelle: A, B e C. Il codice Java corrispondente a queste tabelle è qui di seguito.Clausola order-by complessa in file hibernate .hbm

Classe A Codice:

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

} 

Codice classe B:

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

Codice classe C:

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

I file .hbm associati sono qui

Tabella A mappatura:

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

Tabella B mappatura:

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

Tabella C mappatura:

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

La mia domanda riguarda il "order-by" clausola nel file A.hbm. Vorrei ordinare non aver seguito c.Id, ma c.Num

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

Purtroppo, quando lo faccio, ottengo la seguente eccezione:

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 

Sono nuovo di letargo, ho letto alcune cose sui criteri che potrebbero aiutarmi, ma non vedo come usarli in file hbm.

Grazie per l'aiuto,

Lauriane

Dopo aver provato le idee che mi hai dato, io ancora non ho la risposta. In primo luogo, ho scritto il seguente metodo per inserire i dati nel database:

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

Mi dà 2 istanze di A, ognuno con una lista di 4 istanze di B.

Poi, ho provato questo codice:

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

L'elenco ottengo contiene 4 volte ogni istanza di A, e il risultato è:

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, 

Così ho cercato di cambiare il getter elencoB nella classe a, a:

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

ed eseguire il seguente codice:

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

    } 

e la produzione ammontava:

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

Non c'è differenza fatta tra le istanze di B riferendosi ad una o l'altra istanza di A, e non vedo come potrebbe funzionare .. .

Grazie per il vostro aiuto,

Lauriane

+0

penso che potrebbe essere utile se si guarda e si pubblica lo sql generato da Hibernate. – Carsten

risposta

4

gentilmente corretto nome della proprietà "Num" per "num" per la mappatura di classe C.

  1. clausola ORDER BY in A

    • Non sarà in grado di impostare l'ordine in C da A, come A non è direttamente collegato a C.
    • Il motivo per cui ha funzionato per c .id è perché B contiene la colonna c_id (mappatura della classe C) e la clausola order by viene applicata sulla colonna c_id sulla tabella B e non la colonna id su C
    • Quando si imposta c.num, la sospensione tenterà di cercare la colonna in tabella B che non abbiamo.
  2. criteri di query

    • Per utilizzare criteri di interrogazione primo ordine-by rimuovere clausola da A o utilizzare valido un
    • interrogazione Criteri deve essere creato con "sessione" in codice Java e non essere configurato nel file hbm.

codice di esempio

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 per 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> 

codice Java

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

L'unico inconveniente è B non può essere gestita in modo indipendente ed è necessario rimuovere colonna "id" da B e fare a_id e c_id come chiave primaria composta per l'operazione di inserimento/aggiornamento/cancellazione, per la query di selezione sopra le modifiche sono sufficienti.


+0

Il fatto è che non capisco. Dove devo scrivere il codice dei criteri? Se scrivo nel metodo "getListB()" di A, ottengo tutte le istanze di B, anche quelle che non sono collegate ad A. Altrimenti, se scrivo prima di ottenere un'istanza di A, non c'è ordine. – user2436719

+0

devi scrivere per esempio in una classe DAO – nachokk

Problemi correlati