我有以下类图,我想将它映射到数据库(请注意,Person有一个包含Vehicle类对象的列表)。
我的数据库看起来像:
数据库中表示Vehicle类的子类的所有表都包含超类Vehicle的所有字段。此外,所有关系都显示了从人到车,汽车和摩托车的一对多关系。
我的 hibernate映射文件如下: 的 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)。但是,这不是这种情况,并且插入汽车似乎被忽略了。通过在上面给出的代码上尝试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。
我将不胜感激任何帮助 感谢。
答案 0 :(得分:1)
如果managePerson.store(...)方法没有对“getOwnedVehicles()”中的对象进行递归调用,那么它可以调用它们的“store”方法,那么你不应该期望创建它“car”对象将被插入表中。
你实际上是在调用“managePerson.store”而不是“manageCar.store”,我必须看到.store(...)方法中的代码才能确定,但我希望它不是对车辆进行迭代并且不对任何已发现的车辆进行插入(为什么它除非你明确地将它构建成这样做?)。
答案 1 :(得分:1)
我认为这只是不正确使用Hibernate的隐式多态的问题。 您的案例的隐式多态性只能通过更改您的列表来实现 逆=“真”。当然,如果您的Vehicle类也“知道”与Person类的关系(例如,通过添加'Owner'属性和相应的映射),则可以这样做。
(看看this表和“每个具体类(union-subclass)表”和一对多关联的情况。
如果启用日志记录并将日志级别提升为DEBUG,您会看到当前Hibernate尝试使用Person_ID而不是Car表来更新Vehicles表,就像您想要的那样。这是因为inverse =“true”以及Table-per-concrete-class映射策略和隐式多态的组合的局限性(请参阅文档)。
因此,通过让Vehicle类了解其所有者并使用inverse =“true”,您应该能够成功完成您想要做的事情。要么是这个,要么尝试其他继承映射策略之一(再次查看文档)。