将复杂的顺序子句放入.hbm hibernate文件中



我有一个关于hibernate和order-by子句的问题。我有一个mySQL数据库,包含3个表: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文件中使用它们。

谢谢你的帮助,

季军我试了你给我的建议,我还是不知道答案。首先,我编写了以下方法将数据输入数据库:

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的一个实例或另一个实例之间没有区别,我不明白它是如何工作的…

谢谢你的帮助,

季军

请将C类映射的属性名"Num"改为"Num"

  1. 订单条款

    • 您将无法从A设置C的订单,因为A没有直接连接到C。
    • 它对c.id有效的原因是因为B包含列c_id (C类映射),order by子句应用于表B上的c_id列,而不是C上的id列
  2. 当你设置c.num时,hibernate会尝试查找B表中没有的列。
  3. 标准查询
    • 要使用条件查询,首先从A中删除order-by子句或使用有效子句
    • 标准查询将在java代码中使用"session"创建,而不是在hbm文件中配置。

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

  • 如果b表可以作为中间表,在这种情况下,不需要b类,A可以通过连接表b (http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/associations.html#assoc-bidirectional-join)与C相关联,那么你可以在hbm文件中使用order-by子句,如下所示:

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作为插入/更新/删除操作的复合主键,对于选择查询,上述更改就足够了。


  • 更多细节请参考:http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html
  • 除了条件查询,您可以使用hbm查询:http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html
  • 你也可以开始使用注解和JPA

最新更新