【问题标题】:Hibernate mapping with one-to-many polymorphic relationship具有一对多多态关系的休眠映射
【发布时间】:2013-06-26 16:36:33
【问题描述】:

我有以下类图,我想将其映射到数据库(请注意,Person 有一个包含 Vehicle 类对象的列表)。

我的 数据库 看起来像:
数据库中表示 Vehicle 类的子类的所有表都具有超类 Vehicle 的所有字段。此外,所有关系都显示了从人到车辆、汽车和摩托车的一对多关系。

我的休眠映射文件如下: Person.hbm.xml

<hibernate-mapping package="...."> 
    <class name="Person" table="Persons"> 
        <id name="key" column="Person_ID"> 
            <generator class="native"/> 
        </id> 
        <list name="ownedVehicles" inverse="false" cascade="all">
            <key column="Person_ID" not-null="true" />
            <list-index column="idx"/>
            <one-to-many class="Vehicle"/>
        </list>
    </class> 
</hibernate-mapping>

Vehicle.hbm.xml

<hibernate-mapping package="..."> 
    <class name="Vehicle" table="Vehicles"  polymorphism="implicit"> 
        <id name="id" type="int" column="Vehicle_ID"> 
            <generator class="increment"/>
        </id> 
        <property name="numOfSeats"/>
        <union-subclass name="Car" table="Cars"></union-subclass>
        <union-subclass name="Motorcycle" table="Motorcycles"></union-subclass>
    </class> 
</hibernate-mapping>

问题(我得到的错误)如下:

Hibernate: insert into Persons (Person_ID) values (default)
2013-06-26 15:41:52 WARN  JdbcCoordinatorImpl:424 - HHH000386: ResultSet had no statement associated with it, but was not yet registered
Hibernate: update Car set numOfSeats=? where Vehicle_ID=?
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

我在运行时收到此错误:

Car car = new Car();
car.setNumOfSeats(5);
Person person = new Person();
person.getOwnedVehicles().add(car);
ManagePerson managePerson = new ManagePerson();
Integer personID = managePerson.store(person);

ManagePerson 的store() 函数实际上是创建一个会话和一个事务,然后使用Hibernate 提供的save() 方法将对象持久化到数据库中。

据我所知,Hibernate 通常会插入 Persons,然后插入 Cars,最后更新 Cars(更新是为了将外键保存在 Cars 表上,该表将引用拥有汽车的 Person)。但是,情况并非如此,插入 Cars 似乎被跳过了。我通过在上面给出的代码上尝试 person.getOwnedVehicles().add(vehicle); 而不是 person.getOwnedVehicles().add(car); 来了解 Hibernate 的工作原理。
正如您可能理解的那样,我试图查看 Hibernate 是否真正了解记录应该放在哪个“子类”表中,具体取决于 Person 类的ownedVehicle 列表中包含的对象的类。例如,如果ownedVehicles 有一个 Car 类对象和一个 Motorcycle 类对象,那么这些对象中的每一个都应该分别转到 Cars 和 Motorcycle 表。

注意:我使用的是 Hibernate 4.2.2 和 HSQLDB 2.2.9。

如果有任何帮助,我将不胜感激。
谢谢。

【问题讨论】:

    标签: java hibernate data-binding one-to-many hibernate-mapping


    【解决方案1】:

    我认为这只是对 Hibernate 的隐式多态性的错误使用的问题。 您的案例的隐式多态性只能通过将列表更改为 逆=“真”。如果您的 Vehicle 类也“知道”与 Person 类的关系(例如,通过添加“Owner”属性和相应的映射),这当然可以做到。

    (查看this 表和“每个具体类(联合子类)的表”和一对多关联的情况。

    如果您启用日志记录并将日志级别提高到 DEBUG,您会看到当前 Hibernate 尝试使用 Person_ID 更新 Vehicles 表,而不是像您想要的那样使用 Car 表。这是因为 inverse="true" 以及 Table-per-concrete-class 映射策略和隐式多态性组合的限制(查看文档)。

    因此,通过让 Vehicle 类知道其所有者并使用 inverse="true" 您应该能够成功地完成您想要做的事情。要么这样做,要么尝试其他继承映射策略之一(再次查看文档)。

    【讨论】:

    • 感谢@ador 的回答。我尝试了您的建议,但无法使其正常工作。我花了太多时间让它工作,所以我终于改变了它并使用了每个子类的表策略,现在工作正常。我所做的更改如下:将&lt;union-subclass ...... /&gt; 替换为&lt;joined-subclass name="Car" table="Cars" extends="Vehicle"&gt; &lt;key column="Vehicle_ID"/&gt; &lt;/joined-subclass&gt;。对摩托车做同样的事情。请注意,表示子类的表现在将只包含其字段的列,而不包含其超类的列。子类也不再需要 FK。
    【解决方案2】:

    如果 managePerson.store(...) 方法没有递归调用“getOwnedVehicles()”中的对象,这样它就可以调用它们的“store”方法,那么你不应该期望创建的“汽车”对象将被插入到表中。

    您实际上是在调用“managePerson.store”而不是“manageCar.store”,但我必须查看 .store(...) 方法中的代码才能确定,但​​我希望它不是对车辆进行迭代,而不是对任何发现的车辆进行插入(除非您明确构建它来执行此操作,否则为什么要这样做?)。

    【讨论】:

    • 我不同意你所说的。 “cascade=all”就是为你做的。我已经使用person.getOwnedVehicles().add(vehicle); 而不是person.getOwnedVehicles().add(car); 测试了与我上面已经写过的完全相同的东西,并且工作起来就像一个魅力。所有车辆对象都被持久化到数据库中。因此,在我看来,是其他原因导致了问题。此外,正如您从我的错误消息中看到的那样,Hibernate 实际上尝试对 Car 对象执行某些操作,但它执行了更新,它应该真正执行保存然后更新。
    • 顺便说一下,我可以理解您对 store() 函数的意思,但 Hibernate 是用来消除您自己做这些事情的痛苦的技术。
    • 我看你可能是对的,我不使用休眠。 10 年前,我发明了自己的持久性引擎,在休眠之前……它不承认(使)这种性质的问题。如果您使用对 getOwnedVehicle().add(vehicle) 的显式调用来使其工作,那为什么还不够呢?
    • 我只是说这是 Hibernate 应该注意的事情,否则他们没有充分的理由使用它。我确信可能有一个作弊/黑客可以用来做这件事,但我真的不想在我的代码上这样做。我需要一个干净的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多