2013-06-26 112 views
1

我有以下類圖我想將它映射到數據庫(請注意,人有一個與Vehicle類的對象列表)。 enter image description here休眠映射與一對多的多態關係

而且我數據庫樣子: enter image description here
在數據庫中代表的汽車類的子類有超車輛的所有領域的所有表。此外,所有的關係都顯示了人與車,汽車和摩托車之間的一對多關係。

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的功能實際上是創建一個會話和交易,然後使用保存()由Hibernate提供方法將對象保存到數據庫中。

就我所知,Hibernate通常會插入到人員中,然後插入到汽車中,最後更新汽車(更新完成後將汽車表上的外鍵保存爲引用擁有汽車的人員)。然而,在這種情況下並非如此,插入Cars似乎正在被跳過。通過在上面給出的代碼上嘗試person.getOwnedVehicles().add(vehicle);而不是person.getOwnedVehicles().add(car);,我明白了Hibernate是如何工作的。
正如你可能知道的,我試圖看看Hibernate是否真正理解在哪個「子類」表中記錄應該去,這取決於Person類的ownedVehicle列表中包含的對象的類。例如,如果擁有的車輛擁有Car類和Motorcycle類的對象,那麼它們中的每一個都應該分別到汽車和摩托車表中。

注意:我正在使用Hibernate 4.2.2和HSQLDB 2.2.9。

我將不勝感激任何幫助。
謝謝。

回答

1

我認爲這只是不正確使用Hibernate的隱式多態性的問題。 您的案例的隱式多態性只能通過將您的列表更改爲具有 inverse =「true」才能起作用。當然,如果您的Vehicle類還「知道」與Person類的關係(例如,通過添加「Owner」屬性和相應的映射),則可以完成此操作。

(看一看this桌子和一個一對多的關聯「每個具體類(工會子類)表」的情況。

如果啓用日誌記錄,提高日誌級別設置爲DEBUG你會發現當前Hibernate試圖用Person_ID而不是Car表來更新Vehicles表,這是因爲inverse =「true」和Table-per-concrete-類映射策略和隱式多態性(看看文檔)

所以,通過讓Vehicle類知道它的Owner並使用inverse =「true」,您應該能夠成功在你正在嘗試做什麼。要麼是這個或者嘗試其他繼承映射策略之一(再看看文檔)。

+0

謝謝你的答案@ador。我嘗試了你的建議,但無法使其工作。我花了太多時間讓它工作,所以我最終改變了它,並使用Table per子類策略,現在工作正常。我做的改變如下:將''替換爲''。爲摩托車做同樣的事情。請注意,表示子類的表現在將只包含其字段的列,而不包含其超類的列。此外,子類不再需要FK。 – Soc

1

如果managePerson.store(...)方法沒有對「getOwnedVehicles()」中的對象進行遞歸調用,從而可以調用其「存儲」方法,那麼您不應該期望創建的「汽車」對象將被插入到表格中。

你實際上調用了「managePerson.store」而不是「manageCar.store」,我不得不看到.store(...)方法中的代碼是肯定的,但我希望它是不是對車輛進行迭代,也不是爲任何發現的車輛插入(爲什麼它應該除非你明確地建立它來做到這一點?)。

+0

我不同意你在說什麼。 「cascade = all」就是爲你做的。我用'person.getOwnedVehicles()。add(vehicle);'而不是'person.getOwnedVehicles()。add(car);'來測試完全一樣的東西,並且像魅力一樣工作。所有車輛對象都被保存到數據庫中。所以在我看來,其他的東西導致了這個問題。另外,正如你從我的錯誤信息中看到的那樣,Hibernate實際上試圖用Car對象做一些事情,但它做了一個更新,它應該在那裏進行保存然後進行更新。 – Soc

+0

順便說一句,我可以看到你對store()函數的意思,但Hibernate是一種技術,可以用來消除你自己做這些事情的痛苦。 – Soc

+0

我看你可能是對的,我不使用休眠。 10年前,我發明了自己的持久性引擎,之後就有了休眠......它不承認(使可能)這種性質的問題。 如果你使用顯式調用getOwnedVehicle()。add(vehicle)來實現它,那麼爲什麼不夠? –