`
yun342173024
  • 浏览: 72694 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

hibernate和jpa注解关联总结

 
阅读更多
用hibernate和jpa annotation 大概一年多了,今天闲来无事,对他们关联关系元数据写法做一个总结。
1.一对一主键关联
这个在实际项目中用的比较少,大部分是通过用外键做关联的,这里用用户和手机号举个例子,用户和手机号是一对一的关系,代码如下:
User实体
  package com.own.model;

import java.io.Serializable;

public class Users implements Serializable{

      private static final long serialVersionUID = 1381652232198529039L;
	private int id;
	private String username;
	private String password;
	private CellphoneNumber phoneNumber;
	public CellphoneNumber getPhoneNumber() {
		return phoneNumber;
	}
	public void setPhoneNumber(CellphoneNumber phoneNumber) {
		this.phoneNumber = phoneNumber;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}

	
}



手机号实体
  package com.own.model;

import java.io.Serializable;

public class CellphoneNumber implements Serializable {
    
	private static final long serialVersionUID = -1029364968566042141L;
	
	private Integer cellPhoneId;
	private String number;
	private String attribution;//手机归属地
	private String cellphonoeType;//移动或者联通
	private Users user ;
	public Users getUser() {
		return user;
	}
	public void setUser(Users user) {
		this.user = user;
	}
	public Integer getCellPhoneId() {
		return cellPhoneId;
	}
	public void setCellPhoneId(Integer cellPhoneId) {
		this.cellPhoneId = cellPhoneId;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public String getAttribution() {
		return attribution;
	}
	public void setAttribution(String attribution) {
		this.attribution = attribution;
	}
	public String getCellphonoeType() {
		return cellphonoeType;
	}
	public void setCellphonoeType(String cellphonoeType) {
		this.cellphonoeType = cellphonoeType;
	}
	
	@Override
	public boolean equals(Object anotherObject){
		if(anotherObject == null || anotherObject.getClass() != this.getClass()){
			return false;
		}
		if(this == anotherObject){
			return true;
		}
		
		CellphoneNumber another = (CellphoneNumber) anotherObject;
		if(another.cellPhoneId.equals(this.cellPhoneId)){
			return true  ;
		}
		
		return false;
	}
	
	public int hashCode(){
		
		return cellPhoneId.hashCode();
	}
	
	
}


users映射文件
   <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping >

        <class name="com.own.model.Users"  table="users"  dynamic-update="true"  dynamic-insert="true"     >
          
           <id name="id"  column="id" >
              <generator class="native"></generator>
           </id>
           
            <property name="username"  column="username"   ></property>  
            <property name="password"  column="password" type="string"  ></property>  
            
            <!-- 这里是一对一映射 级联为所有 -->
            <one-to-one name="phoneNumber" class="com.own.model.CellphoneNumber" cascade="all"  >
            
            </one-to-one>    
            
        </class>
</hibernate-mapping>

cellPhone映射文件
   <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping >

        <class name="com.own.model.CellphoneNumber"  table="cellphone"  dynamic-update="true"  dynamic-insert="true"   >
           <!-- 这里设置外键关联 -->
           <id name="cellPhoneId"  column="id" >
              <generator class="foreign">
                  <!-- 这里设置用引用user实体的主键  -->
                <param name="property">user</param>
              </generator>
           </id>
            <property name="number"  column="cellphoneNumber" ></property>  
            <property name="attribution"  column="attribution"   ></property>  
            <property name="cellphonoeType"  column="numberType"   ></property>  
            <!-- 加上外键约束  ,使Cellphone的主键引用user表行的主键 -->
            <one-to-one name="user" constrained="true"  class="com.own.model.Users"  ></one-to-one>
        </class>
</hibernate-mapping>

在调用时,要设置关联关系
  Users u = new Users();  
			u.setPassword("admin@1973");
			u.setUsername("floatSnow");
			CellphoneNumber cellphone = new CellphoneNumber();
			cellphone.setAttribution("北京");
			cellphone.setCellphonoeType("中国移动");
			cellphone.setNumber("13476534589");
			//设置双向关联关系
			u.setPhoneNumber(cellphone);
			cellphone.setUser(u);


jpa中使用@PrimaryKeyJoinColumn 

  package com.own.model;


import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
@Entity
@org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true)
@Table(name="users")
public class Users implements Serializable{
	private static final long serialVersionUID = 1381652232198529039L;
	private int id;
	private String username;
	private String password;
	private CellphoneNumber cellphone;
	
	@OneToOne(cascade={CascadeType.ALL})
	@PrimaryKeyJoinColumn
	public CellphoneNumber getCellphone() {
		return cellphone;
	}
	public void setCellphone(CellphoneNumber cellphone) {
		this.cellphone = cellphone;
	}
	@Id
	@GeneratedValue
	@Column(name="id")
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="username")
	public String getUsername() {
		return username;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}
	
	@Column(name="password")
	public String getPassword() {
		return password;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}

	
}



2.一对一外键关联
hibernate xml文件映射,在这里使用manyToOne而不是我们想像的oneToOne,还有在  user表中加一个外键,引用另一个表的主键,这里设置双向关系,在项目中根据情况而定是否设置双向关系
映射文件
  <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping >
        <class name="com.own.model.Users"  table="users"  dynamic-update="true"  dynamic-insert="true" >
           <id name="id"  column="id" >
              <generator class="native"></generator>
           </id>
            <property name="username"  column="username"   ></property>  
            <property name="password"  column="password" type="string"  ></property> 
            <!-- 加上唯一约束,使这个关系成为真正的一对一 --> 
            <many-to-one name="phoneNumber" cascade="all" class="com.own.model.CellphoneNumber"  column="cell_id"  
              unique="true"  >
            </many-to-one>
        </class>
</hibernate-mapping>

 


jpa 映射使用oneToone,@joinColumn有两个属性 name 和 referencedColumnName
,name是表示表中外键的列名,referencedColumnName表示外键引用的表的列名。
user实体
    @OneToOne(cascade={CascadeType.ALL})
    @JoinColumn(name="cell_id",referencedColumnName="id")
	public CellphoneNumber getCellphone() {
		return cellphone;
	}
 

手机实体类
 
   
   @OneToOne(mappedBy="cellphone")
	public Users getU() {
		return u;
	}
  

3.一对一可选关联
有的时候我们的外键是可选的,也就是说user表的外键是可以为空的,这个时候我们可以把这中可选的关联映射到一张表,加一张中间表,表示实体的对应关系
Users实体映射文件

  <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping >
        <class name="com.own.model.Users"  table="users"  dynamic-update="true"  dynamic-insert="true" >
           <id name="id"  column="id" >
              <generator class="native"></generator>
           </id>
            <property name="username"  column="username"   ></property>  
            <property name="password"  column="password" type="string"  ></property> 
            <!-- 加上唯一约束,使这个关系成为真正的一对一 --> 
            <!-- optional 告诉hibernate这个关系是可选的 ,当这个属性为空时,可以不插入关联表 -->
            <join table="user_cellphoneNumber"      >
              <key column="user_id"    unique="true"  />
               <many-to-one name="phoneNumber"  cascade="save-update"      class="com.own.model.CellphoneNumber"   column="cell_id"  
              unique="true"     >
            </many-to-one>
            </join>
        </class>   
</hibernate-mapping>

jpa注解把属性映射到两张表,通过使用@SecondaryTable,使属性映射到一张中间表。
   package com.own.model;


import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;

import org.hibernate.transaction.JOnASTransactionManagerLookup;
@Entity
@org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true)
@Table(name="users")
@SecondaryTable(name="user_cellphoneNumber",pkJoinColumns={@PrimaryKeyJoinColumn(name="user_id",referencedColumnName="id")})
public class Users implements Serializable{
	private static final long serialVersionUID = 1381652232198529039L;
	private int id;
	private String username;
	private String password;
	private CellphoneNumber cellphone;
	@OneToOne(cascade={CascadeType.ALL})
    @JoinColumn(table="user_cellphoneNumber",name="cell_id",referencedColumnName="id")
	public CellphoneNumber getCellphone() {
		return cellphone;
	}
	public void setCellphone(CellphoneNumber cellphone) {
		this.cellphone = cellphone;
	}
	@Id
	@GeneratedValue
	@Column(name="id")
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="username")
	public String getUsername() {
		return username;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}
	
	@Column(name="password")
	public String getPassword() {
		return password;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}

	
}     

4.一对多关联
一对多关联通过oneToMany和ManyToMany映射,这里的多段在java里用一个集合set来表示,这个用商品category和货物Goods来举例子。
one端实体Category 映射xml

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping >
        <class name="com.own.model.Category"  table="category"  dynamic-insert="true" dynamic-update="false"      >
           <id name="category_id"  column="id" >
              <generator class="native"></generator>
           </id>
            <property name="categoryName"  column="category_name" type="string"  ></property> 
             
            <set name="goodsSet" inverse="true"  cascade="save-update"   >    <!-- 用key column 的名字表示关联表的外键的名称  -->
               <key column="category_id"    /> 
               <one-to-many  class="com.own.model.Goods"   /> 
              </set> 
        </class>
</hibernate-mapping>

many端的映射文件
    <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping   >
        <class name="com.own.model.Goods"  table="goods"  dynamic-insert="true" dynamic-update="false"      >
           <id name="id"  column="goods_id" >
              <generator class="native"></generator>
           </id>
            <property name="price"  column="goods_price" type="double"  ></property>  
            <property name="goodsName"  column="goods_name" type="string"  ></property>  
            <property name="goodsDescription"  column="goods_description" type="string"  ></property>  
            <many-to-one name="category"      fetch="join"    class="com.own.model.Category"  column="category_id"      >
            </many-to-one>
        </class>
 
</hibernate-mapping>

jpa元数据注解
Category实体

  package com.own.model;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true)
@Table(name="category")
public class Category implements Serializable {
	private static final long serialVersionUID = 1L;
	private Integer category_id;
	private String categoryName;
    private Set<Goods> goodsSet = new HashSet<Goods>();	
    
    @OneToMany(mappedBy="category",cascade={CascadeType.ALL})
	public Set<Goods> getGoodsSet() {
		return goodsSet;
	}
	public void setGoodsSet(Set<Goods> goodsSet) {
		this.goodsSet = goodsSet;
	}
	@Id
	@GeneratedValue
	@Column(name="id")
	public Integer getCategory_id() {
		return category_id;
	}
	public void setCategory_id(Integer categoryId) {
		category_id = categoryId;
	}
	
	@Column(name="category_name")
	public String getCategoryName() {
		return categoryName;
	}
	public void setCategoryName(String categoryName) {
		this.categoryName = categoryName;
	}

	
	
}


Goods实体
  package com.own.model;


import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true)
@Table(name="goods")
public class Goods implements Serializable {
	private static final long serialVersionUID = 1L;
	private Integer id;
	private  String goodsName;
	private Double price;
	private String goodsDescription;	
	private Category category;
	@ManyToOne
	@JoinColumn(name="category_id",referencedColumnName="id")
	public Category getCategory() {
		return category;
	}

	public void setCategory(Category category) {
		this.category = category;
	}

	public Goods(){}
	
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="goods_id")
	public Integer getId() {
		return id;
	}
	
	public void setId(Integer id) {
		this.id = id;
	}
	
	@Column(name="goods_name",length=40,nullable=false)
	public String getGoodsName() {
		return goodsName;
	}
	public void setGoodsName(String goodsName) {
		this.goodsName = goodsName;
	}
	
	@Column(name="goods_price")
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	
	@Column(name="goods_description")
	public String getGoodsDescription() {
		return goodsDescription;
	}
	public void setGoodsDescription(String goodsDescription) {
		this.goodsDescription = goodsDescription;
	}

	
	@Override
	public boolean equals(Object o) {
		
		if(o == null || o.getClass() != this.getClass()){
			return false;
		}
		
		if(o == this){
			return true;
		}
		
		Goods goods = (Goods) o;
		
		if(id == null ? goods.id == null : this.id.equals(goods.id)){
			return true;
		}
		
		
		return false;
	}
	
	/*@Override
	public int hashCode() {
		//return this.id.hashCode();
		return 
	}*/
	
}



5.多对多关联
多对多关联用manyToMany来映射,这里用学生和选的课程,它们是多对多的关联,多对对
关联通常需要一张中间表,这个表就两字段,学生id和课程id(这里中间表就两个字段)
在java中用两set集合来表示
student 映射文件

  <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping >
        <class name="com.own.model.Student"  table="student"  dynamic-update="true"  dynamic-insert="true" >
           <id name="studentId"  column="id" >
              <generator class="native"></generator>
           </id>
            <property name="studentName"  column="student_name"   ></property>  
            <property name="studentNum"  column="student_no" type="string"  ></property> 
            <set name="cosrseSet"    table="student_course"  >
           <!--  引用当前实体主键的外键名称   -->   
          <key  column="student_id"   />
              <many-to-many column="course_id"  class="com.own.model.Course"   ></many-to-many>
            </set>
        </class>
</hibernate-mapping>

course映射文件
  <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping   >
        <class name="com.own.model.Course"  table="course"  dynamic-update="true"     dynamic-insert="true" >
           <id name="courseId"  column="id" >
              <generator class="native"></generator>
           </id>
            <property name="courseName"  column="course_name"   ></property>  
            <property name="courseNum"   column="course_no"  ></property> 
            
          <set name="studentSet"  inverse="true"  cascade="all"    table="student_course"    >
              <key  column="course_id"   />
              <many-to-many column="student_id"  class="com.own.model.Student"   ></many-to-many>
           </set>
        </class>
</hibernate-mapping>

jpa元数据
Student实体
  package com.own.model;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name="student")
public class Student implements Serializable {
	
	private static final long serialVersionUID = 1L;
	private Integer studentId;
	private String studentName;
	private String studentNum;
	private Set<Course> cosrseSet = new HashSet<Course>();
	@ManyToMany
	@JoinTable(name="student_course",joinColumns={@JoinColumn(name="student_id")},
			   inverseJoinColumns={@JoinColumn(name="course_id")})
	public Set<Course> getCosrseSet() {
		return cosrseSet;
	}
	public void setCosrseSet(Set<Course> cosrseSet) {
		this.cosrseSet = cosrseSet;
	}
    
	@Id
	@GeneratedValue
	@Column(name="id")
	public Integer getStudentId() {
		return studentId;
	}
	public void setStudentId(Integer studentId) {
		this.studentId = studentId;
	}
	
	@Column(name="student_name")
	public String getStudentName() {
		return studentName;
	}
	public void setStudentName(String studentName) {
		this.studentName = studentName;
	}
	
	@Column(name="student_no")
	public String getStudentNum() {
		return studentNum;
	}
	public void setStudentNum(String studentNum) {
		this.studentNum = studentNum;
	}

}


Course实体
  package com.own.model;

import java.io.Serializable;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name="course")
public class Course implements Serializable {
	private static final long serialVersionUID = 1L;
	private Integer courseId;
	private String courseNum;
	private String courseName;
	private Set<Student> studentSet = new HashSet<Student>();
	
	@ManyToMany(mappedBy="cosrseSet")
	public Set<Student> getStudentSet() {
		return studentSet;
	}
	public void setStudentSet(Set<Student> studentSet) {
		this.studentSet = studentSet;
	}
	@Id
	@GeneratedValue
	@Column(name="id")
	public Integer getCourseId() {
		return courseId;
	}
	public void setCourseId(Integer courseId) {
		this.courseId = courseId;
	}
	
	@Column(name="course_no")
	public String getCourseNum() {
		return courseNum;
	}
	public void setCourseNum(String courseNum) {
		this.courseNum = courseNum;
	}
	
	@Column(name="course_name")
	public String getCourseName() {
		return courseName;
	}
	public void setCourseName(String courseName) {
		this.courseName = courseName;
	}

  /* @Override
   public boolean equals(Object o) {
	 if(o == null || o.getClass() != Course.class){
		 return false;
	 }
	     
	 if(o == this){
		 return true; 
	 }
	   
	 Course another = (Course)o;
	 if(courseId == null ? another.courseId == null : courseId.equals(another.courseId)){
		 return true;
	 }
	 
	 return  false;
	
  }

  @Override
   public int hashCode() {
	return super.hashCode();
	 // return 1;
  }*/
   
	
}


在多对对关联的情况下,用的是set集合,实体要实现hashcode和equals,不然在更新关联表的时候会更新不了,比如学生不在选择这门课程,从set集合中remove掉这个课程,然后更新这个学生实体,代码如下,在不实现hashcode和equals更新不会成功,只有实现了才可以,hibernate返回了自己写的集合,PersistenceSet而不是HashSet,这也是为什么我们在实体中写set接口,不能写HashSet ... = new HashSet,要用 Set ... = new HashSet 。
  	tc = session.beginTransaction();
		    Student s1 = (Student) session.get(Student.class,9) ;
            Course c = new Course();
           s1.getCosrseSet().remove(c);
           session.update(s1);//更新学生的选课
			tc.commit();


最后讲解一下cascade和inverse这两个属性,刚用hibernate的时候也比较不理解,首先这两个属性没有任何关系,cascade表示级联,就是被关联的一段,比如cascade='save-update',级联保存和更新,在设置了cascade的端,保存这个对象,会一并保存关联的一端,省去了我们写保存关联端的代码,inverse表示有谁来维护关联,在一段设置inverse=true,则有关联对来维护关联关系,比如上面的例子,在course端设置了inverse=true,则有student来维护中间表,只有当插入student的时候,才向中间表插入数据,如果都设置inverse=true则会插入重复数据,如果不设置,则会出错,在jpa元数据注解中 用mappedBy来表示有那方来维护关联关系
分享到:
评论
1 楼 L504919167 2018-02-21  
有个问题,“1.一对一主键关联 ”的时候。
使用XML方式配置时,会生成一个外键约束,即:从表的主键->主表的主键;
使用注解配置时,则不会生成这个外键约束。
大神有什么解决办法吗?

相关推荐

Global site tag (gtag.js) - Google Analytics