1.一对一(OneToOne)
一对一关系映射分为单向一对一和多向一对一。在配置关系时必须确立控制方和被控制方。单向和双向的区别为看主控方和被控方两边是否都配置了@OneToOne,如果都有为双向一对一,反之为单向。
双向一对一关联有两条规则:
@JoinColumn必须配置在关系维护方即主控方上面;
mappedBy属性配置在被维护方的@OneToOne中,并且只能指向主控方,名称定义为主控方中包含的被控方引用名称。
/**
* person属于关系维护方
*
*/
@Entity
@Table(name="t_one_person")
public class Person {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(length=10,nullable=false)
private String name;
/*
* 双向关系一对一
* @JoinColumn在JPA中成为连接列,目的是在Person实体表中生成一个IDCard实体
* 的外键关系.外键列明可以用name指定,如果不指定,默认为目标实体对象名和_ID组合.
* 拥有@JoinColumn的是关系维护方.
*/
@OneToOne(cascade=CascadeType.ALL,optional=false)
@JoinColumn(name="idCard_id")
private IDCard idCard;
//省略get/set方法...
}
/**
* 为关系被维持方
*
*/
@Entity
@Table(name="t_one_idcard")
public class IDCard {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(length=18,nullable=false)
private String cadno;
/*
* 双向关联:一对一
* mappedBy:反转.出现该属性的是关系被维护方,所指向的则是关系维护方.
*/
@OneToOne(cascade={CascadeType.PERSIST,CascadeType.REFRESH,CascadeType.MERGE},mappedBy="idCard",optional=false,fetch=FetchType.EAGER)
private Person person;
//省略get/set方法...
}
Junit测试:
public class TestJPA {
EntityManagerFactory emf = null;
@Before
public void before() {
emf = Persistence.createEntityManagerFactory("myJPA");
}
@Test
public void add() {
Person person = new Person();
IDCard idCard = new IDCard();
person.setName("老李");
idCard.setCadno("111111111111111111");
idCard.setPerson(person);
person.setIdCard(idCard);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(person);
em.getTransaction().commit();
em.close();
}
/**
* 关闭EntityManagerFactory
*/
@After
public void after() {
if (null != emf) {
emf.close();
}
}
}
2.一对多(OneToMany)
在JPA规范中:
1<--->m 多的一方位关系维护端,关系维护端负责外键记录的更新.关系被维护端是没有权利更新外键字段的.
/**
*关系被维护方
*/
@Entity
@Table(name="t_order")
public class Order {
@Id
@Column(length=55)
private String orderId;
//总价钱
@Column(nullable=false)
private Float amount=0f;
/*订单项.一对多
* CascadeType.MERGE :级联更新
* CascadeType.PERSIST:级联保存
* CascadeType.REFRESH: 级联刷新 refresh(),才会触发
* CascadeType.REMOVE:级联删除
* CascadeType.ALL:以上所有
*
* FetchType.EAGER:立即加载 @OneToOne: 默认.
* FetchType.LAZY:懒加载. @OneToMany :默认.
*
* mappedBy:关系反转.此处有orderItem关系维护端.
*/
@OneToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY,mappedBy="order")
private Set<OrderItem> items=new HashSet<OrderItem>();
//省略get/set方法...
}
/**
*
*关系维护方
*在JPA规范中:
* 1<--->m 多的一方位关系维护端,关系维护端负责外键记录的更新.关系被维护端是没有权利更新外键字段的.
*/
@Entity
@Table(name="t_orderItem")
public class OrderItem {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(length=40,nullable=false)
private String productName;
//销售价
@Column(nullable=false)
private Float sellPrice=0f;
/*
* 订单.多对一
* optional=true :可选,对应数据库可以为null.
* @JoinColumn: 维护外键
*/
@ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},fetch=FetchType.EAGER,optional=false)
@JoinColumn(name="order_id")
private Order order;
//省略get/set方法..
}
Junit测试:
public class TestJPA {
EntityManagerFactory emf = null;
@Before
public void before() {
emf = Persistence.createEntityManagerFactory("myJPA");
}
@Test
public void add(){
OrderItem orderItem = new OrderItem();
orderItem.setProductName("电脑");
orderItem.setSellPrice(5000f);
OrderItem orderItem1 = new OrderItem();
orderItem1.setProductName("手机");
orderItem1.setSellPrice(3000f);
Order order=new Order();
//订单项关联订单
orderItem.setOrder(order);
orderItem1.setOrder(order);
order.setAmount(25.0f);
order.setOrderId(UUID.randomUUID().toString());
//订单关联订单项
order.getItems().add(orderItem);
order.getItems().add(orderItem1);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(order);
em.getTransaction().commit();
em.close();
}
/**
* 关闭EntityManagerFactory
*/
@After
public void after() {
if (null != emf) {
emf.close();
}
}
}
3.多对多(ManyToMany)
使用之间表,分为两个一对多
@Entity
@Table(name="t_many_student")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(name="name",length=10,nullable=false)
private String name;
/* @JoinTable:中间表
* inverseJoinColumns:指定被维护端的外键定义,这里指向的是Teacher
* joinColumns:指定关系维护端的外键定义,这里指向的是student
*/
@ManyToMany(cascade=CascadeType.REFRESH)
@JoinTable(name="student_teacher",inverseJoinColumns=@JoinColumn(name="teacher_ids"),joinColumns=@JoinColumn(name="student_ids"))
private Set<Teacher> teachers=new HashSet<Teacher>();
/**
* </pre>
* 添加老师和学生的关系
* </pre>
*/
public void addTeacher(Teacher teacher){
this.teachers.add(teacher);
}
/**
* </pre>
* 解除老师和学生的关系
* </pre>
*/
public void removeTeacher(Teacher teacher){
if(this.teachers.contains(teacher)){
this.teachers.remove(teacher);
}
}
//省略get/set方法...
}
@Entity
@Table(name="t_many_teacher")
public class Teacher {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(name="name",length=10,nullable=false)
private String name;
@ManyToMany(cascade={CascadeType.REFRESH},fetch=FetchType.LAZY,mappedBy="teachers")
private Set<Student> students=new HashSet<Student>();
//省略get/set方法...
}
Junit测试:
public class TestJPA {
EntityManagerFactory emf = null;
@Before
public void before() {
emf = Persistence.createEntityManagerFactory("myJPA");
}
/**
* </pre>
* 添加老师和学生
* </pre>
*/
@Test
public void add(){
Student student = new Student("学生");
Teacher teacher=new Teacher("老师");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(teacher);
em.persist(student);
em.getTransaction().commit();
em.close();
}
/**
* </pre>
* 建立老师和学生的关系
* </pre>
*/
@Test
public void buildTS(){
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Student student = em.find(Student.class, 1);
student.addTeacher(em.getReference(Teacher.class, 1));
em.persist(student);
em.getTransaction().commit();
em.close();
}
/**
* </pre>
* 解除老师和学生的关系
* </pre>
*/
@Test
public void deleteTS(){
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Student student = em.find(Student.class, 1);
student.removeTeacher(em.getReference(Teacher.class, 1));
em.persist(student);
em.getTransaction().commit();
em.close();
}
/**
* </pre>
*删除老师
* </pre>
*/
@Test
public void deleteTeacher(){
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Student student = em.find(Student.class, 1);
Teacher teacher = em.getReference(Teacher.class, 1);
//先解除老师和学生的关系
student.removeTeacher(teacher);
//然后在删除老师
em.remove(teacher);
em.getTransaction().commit();
em.close();
}
/**
* </pre>
*删除学生
* </pre>
*/
@Test
public void deleteStudent(){
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Student student = em.find(Student.class, 1);
em.remove(student);//因为student是关系维护端,有权进行中间表进行修改,不需要解除关系.
em.getTransaction().commit();
em.close();
}
/**
* 关闭EntityManagerFactory
*/
@After
public void after() {
if (null != emf) {
emf.close();
}
}
}
4.复合主键
/**
* 复合主键必须要实现Serializable,无参构造,必须重写hashCode,equals.
* @author HH
*
*/
@Embeddable//用于实体里面的时候,告诉JPA实现产品只使用这个复合主键类的属性
public class AirLinePK implements Serializable{
@Column(length=3)
private String startCity;
@Column(length=3)
private String endCity;
//省略get/set方法...
//....
//省略重写的hashCode和equals方法...
}
@Entity
public class AirLine {
@EmbeddedId//专门用于复合主键类
private AirLinePK id;
@Column(length=20)
private String name;
//省略get/set方法..
}
Junit测试:
public class TestJPA {
EntityManagerFactory emf = null;
@Before
public void before() {
emf = Persistence.createEntityManagerFactory("myJPA");
}
@Test
public void add(){
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(new AirLine(new AirLinePK("PEK","SHA"),"北京飞上海"));
em.getTransaction().commit();
em.close();
}
/**
* 关闭EntityManagerFactory
*/
@After
public void after() {
if (null != emf) {
emf.close();
}
}
}