2013-05-30 10 views
5

Mam pytanie dotyczące klauzuli hibernate i order-by. Mam bazę danych mySQL zawierającą 3 tabele: A, B i C. Kod Java odpowiadający tym tabelom jest poniżej.Złożone klauzule kolejności do plików hibernacji .hbm

klasy Kod:

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

} 

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

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

powiązanych plików .hbm tutaj

Tabela A mapowanie:

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

tabela odwzorowania B:

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

Tabela C mapowanie:

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

pytanie jest o "kolejność" po klauzuli pliku A.hbm. Chciałbym zamówić nie po c.Id, ale c.Num

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

niestety, kiedy nie tak, pojawia się następujący wyjątek:

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 

Jestem nowy w hibernacji, czytam kilka rzeczy o kryteriach, które mogą mi pomóc, ale nie widzę, jak używać ich w plikach hbm.

Dzięki za pomoc,

Lauriane

Po wypróbowaniu pomysły mi dałeś, ja wciąż nie mam odpowiedzi. Po pierwsze, napisałem następujące metody wprowadzania danych do bazy danych:

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

Daje mi 2 instancje, każdy z listą 4 wystąpień B.

Następnie próbowałem ten kod:

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

Lista mogę otrzymać zawiera 4 razy każdej instancji, a wyjście jest:

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, 

Więc starałem się zmienić pochłaniacza listB w klasie a, w celu:

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

i uruchom następujący kod:

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

    } 

a wyjście było:

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

Nie ma różnicy pomiędzy wystąpieniami B odnosząc się do jednej lub drugiej instancji, a ja nie rozumiem, jak to może działać .. .

Dzięki za pomoc,

Lauriane

+0

myślę, że mógłby być pomocnym, jeśli przyjrzysz się i zwrócisz sql, który zostanie wygenerowany przez Hibernate. – Carsten

Odpowiedz

4

Uprzejmie poprawna nazwa właściwości "Num" na "num" do mapowania klasy C.

  1. Uporządkuj według klauzula

    • Nie będzie mógł ustawić kolejność na C z A, a A nie jest bezpośrednio podłączony do C.
    • powód, dla którego pracował dla c .id jest, ponieważ B zawiera kolumnę c_id (mapowanie klasy C), a kolejność klauzuli jest stosowana w kolumnie c_id w tabeli B, a nie w kolumnie identyfikatora na C
    • Po ustawieniu wartości c.num, hibernacja spróbuje wyszukać kolumnę w tabela B, której nie mamy.
  2. kryteria zapytania

    • do stosowania kryteriów kwerendy najpierw usunąć zamówień przez klauzuli z A lub użyć właściwego jeden
    • kryteria zapytania ma być tworzone przy użyciu „sesji” w kodzie java i nie być skonfigurowane w pliku hbm.

Kod próbki

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 

odwzorowanie dla

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

kod Java

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

Jedyną wadą jest to B nie mogą być zarządzane niezależnie i trzeba usunąć kolumny "id" z B i dokonać a_id oraz c_id jako złożony klucz podstawowy dla operacji wstawiania/aktualizacji/usuwania, ponieważ zapytanie o powyższe zmiany jest wystarczające.


+0

Faktem jest, że go nie rozumiem. Gdzie muszę napisać kod Kryteria? Jeśli zapiszę to do metody "getListB()" A, otrzymam wszystkie wystąpienia B, nawet te, które nie są połączone z A. W przeciwnym razie, jeśli napiszę to przed otrzymaniem instancji A, nie będzie żadnego porządku. – user2436719

+0

musisz napisać na przykład w klasie DAO – nachokk

Powiązane problemy