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(); } } }