5

我有一个关于休眠和排序条款的问题。我有一个包含 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文件。

感谢您的帮助,

劳里安

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

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

谢谢你的帮助,

劳里安

4

1 回答 1

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 代码中的“会话”创建,而不是在 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

爪哇

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


于 2013-06-05T06:30:42.457 回答