轉:http://lijiejava.iteye.com/blog/786535
Item類:
public class Item { private int id; private String name; private Set bids = new HashSet(); ••• }
Bid類:
public class Bid { private int id; private double amount; private Item item; ••• }
Item.hbm.xml:(t_item表)
<hibernate-mapping> ••• <set name="bids" table="t_bid" cascade="save-update"> <key column="item_id" not-null="true"/> <one-to-many class="value.Bid"/> </set> ••• </hibernate-mapping>
Bid.hbm.xml: (t_bid表):
<hibernate-mapping> ••• <many-to-one name="item" class="value.Item" column="item_id" not-null="true" /> ••• </hibernate-mapping>
測試代碼:
••• Item item = new Item(); item.setName("item"); Bid b1 = new Bid(); b1.setAmount(12.09); b1.setItem(item); Bid b2 = new Bid(); b2.setAmount(11.98); b2.setItem(item); Set bids = new HashSet(); bids.add(b1); bids.add(b2); item.setBids(bids); session.beginTransaction(); session.save(item); session.getTransaction().commit();
這是以前的一個"一對多雙向關聯",今天運行時拋出了如下異常:
Exception in thread "main" java.lang.ExceptionInInitializerError ••• Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: value.Bid column: item_id (should be mapped with insert="false" update="false")
仔細檢查了映射文件,發現在Item.hbm.xml配置文件的<key>元素中多了一個not-null="true"限制,將其去掉後就可以正常運行。
由<key>元素定義的列映射item_id是t_bid表的外鍵列。加入not-null="true"之後,意味著如果要增加t_bid表中的記錄,那麼外鍵列item_id一定不能為null,Item端為了確保item_id字段不為null(Item端不知道Bid端的情況,所以它不可能依賴Bid端來確保item_id不為空),會在t_bid的插入語句中為該字段賦值。
事實上,不論是單向一對多還是雙向一對多,只要在<key>元素中設置了not-null="true",那麼在t_bid表的insert語句中都會增加column屬性所指定的列(此處即item_id),以此確保item_id列不為空。以單向一對多關聯為例:如果未設定not-null="true",那麼輸出的語句為:Hibernate: insert into t_bid (amount) values (?);而如果設定了not-null="true",那麼輸出的語句就是:Hibernate: insert into t_bid (amount, item_id) values (?, ?) 。
異常的原因可以從異常信息中看出,即字段重復。通過(1)中的分析,可以很清楚地明白其中的原因。查看Bid.hbm.xml映射文件:
<many-to-one name="item" class="value.Item" column="item_id" not-null="true" />
可以看出,這是一個多對一關聯,not-null="true"表明一個Bid肯定有其對應的Item實體。column屬性指定t_bid表中item_id列是t_item表主鍵的一個外鍵。對於Bid而言,不論是否指定了not-null="true",它的insert語句都會為item_id字段賦值,即使為null。這就是異常產生的原因,這樣的設置會使Hibernate發出類似 insert into t_bid (item_id,item_id) values (•••)的語句,所以會提示重復字段異常。
1. 把<key>元素中的not-null="true"去掉,事實上在雙向關聯中根本不需要由Item端來確保外鍵列item_id不為null。
2. 可以按照提示,在Bid.hbm.xml映射文件中加入insert="false" update="false"。
加入這兩個限制,意味著對t_bid表的insert與update操作中不包含這個字段,這樣可避免重復。
3. 在Item.hbm.xml中的<set>元素內加入inverse="true",將關聯關系全部交給Bid端。http://lijiejava.iteye.com/blog/776587
4. 最無聊的方法:將<key>元素中的column值改成item_id_1等,不與item_id重復,這樣會導致數據表字段的冗余,不應該使用。
在實際應用中,不應該在<key>中加入not-null="true"限制。