复杂的order-by子句到.hbm hibernate文件中

时间:2013-05-30 13:59:27

标签: java mysql hibernate sql-order-by

我对hibernate和order-by子句有疑问。 我有一个包含3个表的mySQL数据库:A,B和C.以下是与这些表对应的Java代码。

A类代码:

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

}

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

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

相关的.hbm文件在这里

表A映射:

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

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

表C映射:

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

我的问题是关于A.hbm文件中的“order-by”子句。我想订购的不是c.Id,而是c.Num

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

不幸的是,当我这样做时,我得到以下例外:

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

我是hibernate的新手,我读了一些可以帮助我的标准,但是我没有看到如何将它们用到hbm文件中。

感谢您的帮助,

Lauriane

在尝试了你给我的想法后,我仍然没有答案。首先,我编写了以下方法将数据输入数据库:

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

它给了我2个A的实例,每个实例都有4个B实例的列表。

然后,我尝试了这段代码:

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

我获得的列表包含A的每个实例4次,输出为:

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, 

所以我尝试将A类中listB的getter更改为:

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

并运行以下代码:

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

    }

输出结果为:

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

B的实例引用A的一个或另一个实例之间没有区别,我看不出它是如何工作的......

感谢您的帮助,

Lauriane

1 个答案:

答案 0 :(得分:4)

请为C类映射更正属性名称“Num”到“num”。

  1. 在A中按条款命令

    • 您将无法在A上设置C的顺序,因为A未直接连接到C.
    • 它适用于c.id的原因是因为B包含列c_id(C类映射),order by子句应用于表B上的c_id列而不是C上的id列
    • 当你设置c.num时,hibernate将尝试在表B中查找我们没有的列。
  2. 条件查询

    • 要使用条件查询,请先从A中删除order-by子句或使用有效的
    • 条件查询将在java代码中使用“session”创建,而不是在hbm文件中配置。
  3. 示例代码

    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
    

    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代码

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

    唯一的缺点是B无法独立管理,您需要从B中删除列“id”并将a_id和c_id作为复合主键进行插入/更新/删除操作,对于选择查询,上面的更改就足够了。