I have a question about hibernate and order-by clause. I have a mySQL database containing 3 tables: A, B and C. The Java code corresponding to those tables is hereafter.
Class 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;
}
}
Class 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;
}
}
Class 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;
}
}
The associated .hbm files are here
Table A 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="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>
Table 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>
Table 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>
My question is about the "order-by" clause in the A.hbm file. I would like to order not following c.Id, but c.Num
<set name="listB" cascade="all, delete-orphan" inverse="true" lazy="true" fetch="select" order-by="c.Num asc">
Unfortunatly, when I do so, I get the following exception:
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
I am new to hibernate, I read some things about criteria that could help me, but I don't see how to use them into hbm files.
Thanks for helping,
Lauriane
After trying the ideas you gave me, I still don't have the answer. First, I wrote the following method to enter data into the 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);
}
It gives me 2 instances of A, each one with a list of 4 instances of B.
Then, I tried this 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();
}
The list I obtain contains 4 times each instance of A, and the output is:
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,
So I tried to change the getter of listB in the A class, to:
public List<B> getListB() {
Criteria crit =
HibernateUtil.currentSession().createCriteria(B.class);
Criteria critc = crit.createCriteria("c");
critc.addOrder(Order.asc("num"));
return critc.list();
}
and run the following code:
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();
}
And the output was:
2, 3, 5, 7, 10, 11, 13, 14,
2, 3, 5, 7, 10, 11, 13, 14,
There is no difference made between the instances of B refering to one or the other instance of A, and I don't see how it could work...
Thanks for your help,
Lauriane
Kindly correct property name "Num" to "num" for C class mapping.
Order By Clause in A
Criteria Query
Sample code
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 for 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
The only drawback is B cannot be managed independently and you need to remove column "id" from B and make a_id and c_id as composite primary key for insert/update/delete operation, for select query above changes are sufficient.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With