hibernate--annotation关系映射

本文深入探讨数据库中一对一、一对多、多对一、多对多关联方式及中间表应用,结合实例解析主键、外键关联及联合主键等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、一对一关联

1、主键关联:两表共用同一ID

Example:每个人拥有一张身份证。

/**
  * Person类(使用@PrimaryKeyJoinColumn注解主键关联)
  */
@Entity
public class Person {
	private int id;
	private String userId;
	private String name;
	private String email;
	private IdentityCard identityCard;
	
	@Id
	//@GeneratedValue
	public int getId() {
		return id;
	}
	
	@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@PrimaryKeyJoinColumn   //这个注解只能写在生成ID的一端
	public IdentityCard getIdentityCard() {
		return identityCard;
	}
        //省略其它成员变量get/set方法...
}

/**
  * 身份证类(使用@GenericGenerator配置ID生成器为foreign,并使用@GeneratedValue配置ID生成策略根据ID生成器生成)
 */
@Entity
public class IdentityCard {
	private int id;
	private String cardId;
	private String name;
	private Date birth;
	private Person person;
	
	@OneToOne(mappedBy="identityCard")  //由mappedBy指定字段来维护双方间的关系,mappedBy只能放在非拥有的一方上注解。
	public Person getPerson() {
		return person;
	}

	@Id
	@GenericGenerator(name ="pkGenerator",strategy="foreign" ,parameters={@Parameter(name="property",value="person")}) //配置Id生成器策略为foreign
       //该表Id根据外表的Id赋值生成,Parameter中指定主表名。
        @GeneratedValue(generator="pkGenerator")  //配置Id生成策略
	public int getId() {
		return id;
	}
	
	@Temporal(TemporalType.DATE)
	public Date getBirth() {
		return birth;
	}
        //省略其它成员变量get/set方法...
 }

@Test //测试类(双方的关系都要配置)
public void test() {
	Person p = new Person();	
	p.setId(123);
	p.setUserId("zhangsan");	
	p.setName("张三");	
	p.setEmail("54895646@qq.com");	
	IdentityCard card = new IdentityCard();
	card.setCardId("35154578456554");	
	card.setName("张三");
	p.setIdentityCard(card);	
	card.setPerson(p);  //双方关系都要设置
}

2、外键关联

(1)单向外键关联

Example:每个人拥有一张身份证。

@Entity
public class Person {  //人类
	private int id;
	private String userId;
	private String name;
	private String email;
	private IdentityCard identityCard;  //身份证外键
	
        @Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	@OneToOne(cascade = CascadeType.ALL)
        @JoinColumn(name="identityCardId")   //设置外键的列名
        public IdentityCard getIdentityCard() {
           return identityCard;
        }        
        //省略其它成员变量get/set方法...
}	
@Entity
public class IdentityCard {   //身份证类
	private int id;
	private String cardId;
	private String name;
	private Date birth;

	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@Temporal(TemporalType.DATE)  //设置日期类型:DATE/TIME/TIMESTAMP
	public Date getBirth() {
		return birth;
	}        
        //省略其它成员变量get/set方法..
 }

(2)双向外键关联

@Entity
public class Person {  //人类
	private int id;
	private String userId;
	private String name;
	private String email;
	private IdentityCard identityCard;  //身份证外键
	
        @Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	@OneToOne(cascade = CascadeType.ALL)
        @JoinColumn(name="identityCardId")   //设置外键的列名
        public IdentityCard getIdentityCard() {
           return identityCard;
        }        
        //省略其它成员变量get/set方法...
}

@Entity
public class IdentityCard {   //身份证类
	private int id;
	private String cardId;
	private String name;
	private Date birth;
	private Person person; //人员外键

	@OneToOne(mappedBy="identityCard")  //由mappedBy指定字段来维护双方间的关系,mappedBy只能放在非拥有的一方上注解。
	public Person getPerson() {
		return person;
	}

	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@Temporal(TemporalType.TIMESTAMP)
	public Date getBirth() {
		return birth;
	}
        //省略其它成员变量get/set方法...
 }

二、一对多关联

Example:一个帖子对应有多个评论,一个评论对应一个帖子

(1)单向

@Entity
public class Topic implements Serializable{  //帖子类
	private int id;
	private String title;
	private Date createDate;
	private String content;
	private Set<Reply> replys = new HashSet<Reply>();
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@OneToMany(targetEntity=Reply.class)
	@JoinColumn(name="topicId") //不加该注解,则会生成Topic_Reply中间表。加上该注解则会在多方的表中生成一列"topicId"
	public Set<Reply> getReplys() {
		return replys;
	}
        //省略其它成员变量get/set方法...
 }

@Entity
public class Reply implements Serializable{   //回复类
	private int id;
	private Date createDate;
	private String content;
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
        //省略其它成员变量get/set方法...
 }

(2)双向

@Entity
public class Topic {   //帖子类
	private int id;
	private String title;
	private Date createDate;
	private String content;
	private Set<Reply> replys = new HashSet<Reply>();   
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@OneToMany(mappedBy="topic") //由mappedBy指定字段来维护双方间的关系,mappedBy只能放在非拥有的一方上注解,所以mappedBy应放在oneToMany上
	public Set<Reply> getReplys() {
		return replys;
	}
        //省略其它成员变量get/set方法...
 }

@Entity
public class Reply {   //回复类
	private int id;
	private Date createDate;
	private String content;
	private Topic topic;   //帖子外键
	
	@ManyToOne
        @JoinColumn(name="topicId")  //该字段指定多方关联一方的字段的名称,可不指定,因为mappedBy已经在多的一方自动生成外键了
        public Topic getTopic() {
		return topic;
	}
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
        //省略其它成员变量get/set方法...
}

三、多对一关联

(1)单向

@Entity
public class Topic implements Serializable{  //帖子类
	private int id;
	private String title;
	private Date createDate;
	private String content;
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
        //省略其它成员变量get/set方法...
 }

@Entity
public class Reply implements Serializable{  //回复类
	private int id;
	private Date createDate;
	private String content;
	private Topic topic;  //帖子外键
	
        @ManyToOne
        @JoinColumn(name="topicId")  //帖子外键在该表的列名
	public Topic getTopic() {
		return topic;
	}
	public void setTopic(Topic topic) {
		this.topic = topic;
	}
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
        //省略其它成员变量get/set方法...
 }

(2)双向

         等同于一对多的双向关联。

四、多对多关联

Example:一个教师教多个学生,一个学生有多个教师。

(1)单向

@Entity
public class Teacher {   //教师类
	private int id;
	private String name;
	private int age;
	private Set<Student> student = new HashSet<Student>();

	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@ManyToMany
	@JoinTable(name="Teacher_Student",   //两者之间关联的中间表的表名
	    joinColumns={
	    	@JoinColumn(name="teacherId")  //本表在中间表的外键名称
	    },
	    inverseJoinColumns={
	    	@JoinColumn(name="studentId")  //外表在中间表的外键名称
	    }
	)
        public Set<Student> getStudent() {
             return student;
        }

        /**
          * name:表字段名
          * unique:值是否唯一
          * nullable:值是否允许为空
          * length:表字段长度
          */
         @Column(name="name",unique=true,nullable = false,length = 30)
         public String getName() {
               return name;
         }
        //省略其它成员变量get/set方法...
 }

@Entity
public class Student {   //学生类
	private int id;
	private String name;
	private Date birth;
	private String sex;
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
        //省略其它成员变量get/set方法...
}

(2)双向

@Entity
public class Teacher {   //教师类
	private int id;
	private String name;
	private int age;
	private Set<Student> students = new HashSet<Student>();  //学生集合

	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@ManyToMany
	@JoinTable(name="Teacher_Student",   //两者之间关联的中间表的表名
	    joinColumns={
	    	@JoinColumn(name="teacherId")  //本表在中间表的外键名称
	    },
	    inverseJoinColumns={
	    	@JoinColumn(name="studentId")  //外表在中间表的外键名称
	    }
	)
	public Set<Student> getStudents() {
		return students;
	}
        //省略其它成员变量get/set方法...
 }

@Entity
public class Student {   //学生类
	private int id;
	private String name;
	private Date birth;
	private String sex;
	private Set<Teacher> teachers = new HashSet<Teacher>();  //教师集合

	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@ManyToMany(mappedBy="students")
	public Set<Teacher> getTeachers() {
		return teachers;
	}
        //省略其它成员变量get/set方法...
 }

五、联合主键(不重要)

(1)使用@Embeddable注解

/**
 * 主键类(注意:必须继承java.io.Serializable)
 * 重写equals()、hascode()方法
 */
@Embeddable  
public class UserPk  implements Serializable{
     private String userId;
     private String role;

     //省略其它成员变量get/set方法...
        
     @Override
     public boolean equals(Object o)
     {
         if(o instanceof UserPk)
         {
             UserPk pk= (UserPk)o;
             if(this.userId.equals(pk.getUserId())&&this.role.equals(pk.getRole()))
                  return true;
         }
         return false;
     }
     
     public int hascode()
     {
         return this.role.hashCode();
     }
 }

/**
 * 实体类(将主键类注解为该实体类Id)
 *
 */
@Entity
@Table(name="Users")
public class User {
    private UserPk userPk;
    private String sex;
    private String email;
    
    @Id
    public UserPk getUserPk() {
        return userPk;
    }
    //省略其它成员变量get/set方法...
 }

(2)使用@EmbeddedId注解

/**
 * 主键类(注意:必须继承java.io.Serializable)
 *
 */
public class UserPk  implements Serializable{
     private String userId;
     private String role;

     //省略其它成员变量get/set方法...

     @Override
     public boolean equals(Object o)
     {
         if(o instanceof UserPk)
         {
             UserPk pk= (UserPk)o;
             if(this.userId.equals(pk.getUserId())&&this.role.equals(pk.getRole()))
                  return true;
         }
         return false;
     }
     
     public int hascode()
     {
         return this.role.hashCode();
     }
 }

/**
 * 实体类(将主键类注解为EmbeddedId)
 *
 */
@Entity
@Table(name="Users")
public class User {
	private UserPk userPk;
	private String sex;
	private String email;
	
	@EmbeddedId
	public UserPk getUserPk() {
		return userPk;
	}
        //省略其它成员变量get/set方法...
 }

(3)使用@IdClass注解

/**
 * 主键类(注意:必须继承java.io.Serializable)
 *
 */
public class UserPk implements Serializable{
	private String userId;
	private String role;

       //省略其它成员变量get/set方法...
}

/**
  * 实体类(使用@IdClass注解该类,并将主键都注解为@Id)
  */
@Entity
@IdClass(UserPk.class)
@Table(name="Users")
public class User {
	private String userId;
	private String role;
	private String sex;
	private String email;
	
	@Id
	public String getUserId() {
		return userId;
	}
	
	@Id
	public String getRole() {
		return role;
	}
        //省略其它成员变量get/set方法...
}

六、中间表多字段

Example:一个产品由多个部件组成,一个部件隶属于多个产品,number为产品对应的部件数量。

(1)单主键关联

@Entity
public class Product {   //产品类
	private int id;
	private String pId;
	private String pname;
	private float price;
	private Set<PartOfProduct> poc = new HashSet<PartOfProduct>();
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@OneToMany(mappedBy="product")  
	public Set<PartOfProduct> getPoc() {
		return poc;
	}
        //省略其它成员变量get/set方法...
 }
@Entity
public class Component {   //部件类
	private int id;
	private String cId;
	private String cname;
	private Set<PartOfProduct> pop = new HashSet<PartOfProduct>();
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@OneToMany(mappedBy="component")
	public Set<PartOfProduct> getPop() {
		return pop;
	}
        //省略其它成员变量get/set方法...
 }
@Entity
public class PartOfProduct {	//中间表
	private int id;
	private Product product;
	private Component component;
	private float number;
	private String memo;
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}

	@ManyToOne
	@JoinColumn(name="productId")  //设置外键列名
	public Product getProduct() {
		return product;
	}
	
	@ManyToOne
	@JoinColumn(name="componentId")  //设置外键列名
	public Component getComponent() {
		return component;
	}
        //省略其它成员变量get/set方法...
 }

(2)多主键关联

@Entity
public class Product {   //产品类
	private int id;
	private String pId;
	private String pname;
	private float price;
	private Set<Component> components = new HashSet<Component>();

	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@ManyToMany
        @JoinTable(name="PartsOfProduct",
	  joinColumns={@JoinColumn(name="productId")},
 	  inverseJoinColumns={@JoinColumn(name="componentId")}	
        )
	public Set<Component> getComponents() {
		return components;
	}
       //省略其它成员变量get/set方法... 
 }
@Entity
public class Component {
	private int id;
	private String cId;
	private String cname;
	private Set<Product> products = new HashSet<Product>();

	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@ManyToMany(mappedBy="components")
	public Set<Product> getProducts() {
		return products;
	}
        //省略其它成员变量get/set方法...
 }
@Entity
@IdClass(P_C_Pk.class)
public class PartOfProduct {  //中间表类
	private Product product;
	private Component component;
	
	@Id
	public Product getProduct() {
		return product;
	}
	
	@Id
	public void setProduct(Product product) {
		this.product = product;
	}
        //省略其它成员变量get/set方法...
 }
public class P_C_Pk implements Serializable{  //主键类
	private Product product;
	private Component component;
	
	@ManyToOne
	@JoinColumn(name="productId")
	public Product getProduct() {
		return product;
	}
	
	@ManyToOne
	@JoinColumn(name="componentId")
	public Component getComponent() {
		return component;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜之子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值