Hibernate中联合主键映射时有一个也是外键的一种解决办法

Hibernate中联合主键映射时有一个也是外键的一种解决方法
     昨天遇到一个联合主键的问题,困扰了我很久,最后发现《Hibernate in Action》里有讲到,因为在实际环境中老是报错,也不知配置的对不对,然后回家写了一个DEMO,发现可以保存。
表结构大致如下:
ITEM(ID,NAME)其中id是PK
CATEGORY(ID,NAME),其中ID是PK
CATEGORY_ITEM(ITEM_ID,CATEGORY_ID,THIRD_ID,ADDED_DATE),其中ITEM_ID,CATEGORY_ID分别是ITEM和CATEGORY的外键,而他们与THIRD_ID一起组成CATETORY_ITEM表的联合主键。
下面给出具体实现:
一、Item.java

/**
 * @author Terrence
 *
 */
public class Item implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Integer id;
	private String name;
	private Set<CategorizedItem> categorizedItems = new HashSet<CategorizedItem>();
	/**
	 * 
	 */
	public Item() {
		super();
	}
	/**
	 * @return the id
	 */
	public Integer getId() {
		return id;
	}
	/**
	 * @param id the id to set
	 */
	public void setId(Integer id) {
		this.id = id;
	}
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
	/**
	 * @return the categorizedItems
	 */
	public Set<CategorizedItem> getCategorizedItems() {
		return categorizedItems;
	}
	/**
	 * @param categorizedItems the categorizedItems to set
	 */
	public void setCategorizedItems(Set<CategorizedItem> categorizedItems) {
		this.categorizedItems = categorizedItems;
	}
	
	
}

二、Category.java
/**
 * @author Terrence
 *
 */
public class Category implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Integer id;
	private String name;
	private Set<CategorizedItem> categorizedItems = new HashSet<CategorizedItem>();
	
	public Category() {
		super();
	}
	/**
	 * @return the id
	 */
	public Integer getId() {
		return id;
	}
	/**
	 * @param id the id to set
	 */
	public void setId(Integer id) {
		this.id = id;
	}
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
	/**
	 * @return the categorizedItems
	 */
	public Set<CategorizedItem> getCategorizedItems() {
		return categorizedItems;
	}
	/**
	 * @param categorizedItems the categorizedItems to set
	 */
	public void setCategorizedItems(Set<CategorizedItem> categorizedItems) {
		this.categorizedItems = categorizedItems;
	}
	
	
}

三、CategorizedItem.java

/**
 * @author Terrence
 *
 */
public class CategorizedItem implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public static class Id implements Serializable {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private Integer thirdId;
		private Integer categoryId;
		private Integer itemId;
		/**
		 * 
		 */
		public Id() {
			super();
		}
		
		/**
		 * @return the thirdId
		 */
		public Integer getThirdId() {
			return thirdId;
		}

		/**
		 * @param thirdId the thirdId to set
		 */
		public void setThirdId(Integer thirdId) {
			this.thirdId = thirdId;
		}

		/**
		 * @return the categoryId
		 */
		public Integer getCategoryId() {
			return categoryId;
		}
		/**
		 * @param categoryId the categoryId to set
		 */
		public void setCategoryId(Integer categoryId) {
			this.categoryId = categoryId;
		}
		/**
		 * @return the itemId
		 */
		public Integer getItemId() {
			return itemId;
		}
		/**
		 * @param itemId the itemId to set
		 */
		public void setItemId(Integer itemId) {
			this.itemId = itemId;
		}
		/* (non-Javadoc)
		 * @see java.lang.Object#hashCode()
		 */
		@Override
		public int hashCode() {
			return this.categoryId.hashCode()+this.itemId.hashCode();
		}
		/* (non-Javadoc)
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@Override
		public boolean equals(Object obj) {
			if(obj!=null&&obj instanceof Id){
				Id that = (Id)obj;
				return this.categoryId.equals(that.categoryId)&&this.itemId.equals(that.itemId);
			}else{
				return false;
			}
		}
		
	}
	
	private Id id = new Id();
	private Date dateAdded;
	private Item item;
	private Category category;
	/**
	 * 
	 */
	public CategorizedItem() {
		super();
	}
	/**
	 * @return the id
	 */
	public Id getId() {
		return id;
	}
	/**
	 * @param id the id to set
	 */
	public void setId(Id id) {
		this.id = id;
	}
	/**
	 * @return the dateAdded
	 */
	public Date getDateAdded() {
		return dateAdded;
	}
	/**
	 * @param dateAdded the dateAdded to set
	 */
	public void setDateAdded(Date dateAdded) {
		this.dateAdded = dateAdded;
	}
	/**
	 * @return the item
	 */
	public Item getItem() {
		return item;
	}
	/**
	 * @param item the item to set
	 */
	public void setItem(Item item) {
		this.item = item;
		this.id.itemId = item.getId();
		item.getCategorizedItems().add(this);
	}
	/**
	 * @return the category
	 */
	public Category getCategory() {
		return category;
	}
	/**
	 * @param category the category to set
	 */
	public void setCategory(Category category) {
		this.category = category;
		this.id.categoryId = category.getId();
		category.getCategorizedItems().add(this);
	}
	/**
	 * @return the thirdId
	 */
	public Integer getThirdId() {
		return this.id.getThirdId();
	}

	/**
	 * @param thirdId the thirdId to set
	 */
	public void setThirdId(Integer thirdId) {
		this.id.thirdId = thirdId;
	}
	
}

四、*.hbm.xml,这里节省时间空间写在了一起
<hibernate-mapping package="org.terrence.hrsystem.model">
	<class name="Item" table="ITEM">
      <id name="id" type="integer" column="ITEM_ID">
         <generator class="identity" />
      </id>
      <property name="name" type="string" not-null="true"
         update="false" column="ITEM_NAME" />
      <set name="categorizedItems" cascade="all, delete-orphan"
         inverse="true" lazy="false">
         <key column="ITEM_ID" not-null="true" />
         <one-to-many class="CategorizedItem" />
      </set>
   </class>

<class name="Category" table="CATEGORY">
      <id name="id" type="integer" column="CATEGORY_ID">
         <generator class="identity" />
      </id>
      <property name="name" type="string" column="CATEGORY_NAME" not-null="true"/>
      <set name="categorizedItems" cascade="all, delete-orphan"
         inverse="true" lazy="false">
         <key column="CATEGORY_ID" not-null="true" />
         <one-to-many class="CategorizedItem" />
      </set>
   </class>

<class name="Category" table="CATEGORY">
      <id name="id" type="integer" column="CATEGORY_ID">
         <generator class="identity" />
      </id>
      <class name="CategorizedItem" table="CATEGORIZED_ITEM" mutable="false">
	<composite-id name="id" class="CategorizedItem$Id">
	<key-property name="thirdId" column="THIRD_ID" type="integer"/>
	<key-property name="categoryId" column="CATEGORY_ID"
				type="integer" />
	<key-property name="itemId" column="ITEM_ID" type="integer" />
	</composite-id>
	<property name="dateAdded" column="ADDED_ON" type="timestamp"
			not-null="true" />

	<many-to-one name="item" class="Item" column="ITEM_ID"
			not-null="true" insert="false" update="false" />
	<many-to-one name="category" class="Category" column="CATEGORY_ID"
			not-null="true" insert="false" update="false" />
	</class>
</hibernate-mapping>


五、测试代码
/**   
* @Title: TestDao.java 
* @Package test 
* @Description: TODO(用一句话描述该文件做什么) 
* @author Terrence.zhung chguxing@163.com   
* @date 2011-3-29 上午02:45:05 
* @version V1.0   
*/ 

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.terrence.hrsystem.dao.CategorizedItemDao;
import org.terrence.hrsystem.dao.CategoryDao;
import org.terrence.hrsystem.dao.ItemDao;
import org.terrence.hrsystem.model.CategorizedItem;
import org.terrence.hrsystem.model.Category;
import org.terrence.hrsystem.model.Item;

/**
 * @author Terrence
 *
 */
public class TestDao {

	/**
	 * @param args
	 */
	private static ItemDao itemDao;
	private static CategoryDao categoryDao;
	private static CategorizedItemDao  categorizedItemDao;
	private static ApplicationContext ctx;
	
	public static void init(){
		if(ctx==null){
			ctx = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext.xml","classpath:daoContext.xml"});
		}
		itemDao = (ItemDao)ctx.getBean("itemDao");
		categoryDao = (CategoryDao)ctx.getBean("categoryDao");
		categorizedItemDao = (CategorizedItemDao)ctx.getBean("categorizedItemDao");
	}
	public static void main(String[] args) throws Exception {
		init();
		saveItem();
		saveCategory();
		saveCategoryItem();
	}
	
	public static void saveItem() throws Exception{
		Item item = new Item();
		item.setName("item2");
		itemDao.save(item);
	}
	
	public static void saveCategory() throws Exception{
		Category category = new Category();
		category.setName("category2");
		categoryDao.save(category);
	}
	
	public static void saveCategoryItem() throws Exception{
		Item item = itemDao.get(1);
		Category category = categoryDao.get(1);
		CategorizedItem categorizedItem = new CategorizedItem();
		categorizedItem.setItem(item);
		categorizedItem.setCategory(category);
		categorizedItem.setDateAdded(new java.util.Date());
		categorizedItem.setThirdId(5);
		categorizedItemDao.save(categorizedItem);
	}

}



六、说明
    因为用了spring,在配置文件配好环境,表可以用hibernate直接生成,不用写SQL语句。
1 楼 168_ccxx 2011-10-30  
CategorizedItem 的配置文件貌似没看到啊..
2 楼 zhongrf 2011-11-07  
168_ccxx 写道
CategorizedItem 的配置文件貌似没看到啊..

不好意思,贴错了,现在补上了,谢谢哈
3 楼 abcd880129 2011-11-07  
是不是写错了,应该是Item的主键、Category的主键是CategorizedItem的外键,然后又和thirdId组成CategorizedItem的联合主键,看标题让我兴奋了一下,原来不是