一、一对多和多对一 双向一对多关系,一是关系维护端(owner side),多是关系被维护端(inverse side)。在关系被维护端建立外键列指向关系维护端的主键列 例: Order.java @SuppressWarnings("serial") @Entity @Table(name = "Orders") public class Order implements Serializable { private Integer orderid; private Float amount; private Set<OrderItem> orderItems = new HashSet<OrderItem>(); private Date createdate; @Id @GeneratedValue public Integer getOrderid() { return orderid; } public void setOrderid(Integer orderid) { this.orderid = orderid; } public Float getAmount() { return amount; } public void setAmount(Float amount) { this.amount = amount; } @OneToMany(mappedBy="order",cascade = CascadeType.ALL, fetch = FetchType.LAZY) @OrderBy(value = "id ASC") public Set<OrderItem> getOrderItems() { return orderItems; } public void setOrderItems(Set<OrderItem> orderItems) { this.orderItems = orderItems; } @Temporal(value=TemporalType.TIMESTAMP) public Date getCreatedate() { return createdate; } public void setCreatedate(Date createdate) { this.createdate = createdate; } public void addOrderItem(OrderItem orderitem) { if (!this.orderItems.contains(orderitem)) { this.orderItems.add(orderitem); orderitem.setOrder(this); } } public void removeOrderItem(OrderItem orderitem) { orderitem.setOrder(null); this.orderItems.remove(orderitem); } } 上面声明一个Set 变量orderItems 用来存放多个OrderItem对象, 注释@OneToMany(mappedBy="order",cascade =CascadeType.ALL, fetch = FetchType.LAZY)指明Order 与OrderItem 关联关系为一对多关系,下面是@OneToMany注释的属性介绍: 1.targetEntity :Class 类型的属性,定义关系类的类型,默认是该成员属性对应的类类型,所以通常不需要提供定义 2.mappedBy String 类型的属性,定义类之间的双向关系。如果类之间是单向关系,不需要提供定义,如果类和类之间形成双向关系,我们就需要使用这个属性进行定义,否则可能引起数据一致性的问题 3.cascade CascadeType[]类型,该属性定义类和类之间的级联关系。定义的级联关系将被容器视为对当前类对象及其关联类对象采取相同的操作,而且这种关系是递归调用的。举个例子:Order 和OrderItem 有级联关系,那么删除Order 时将同时删除它所对应的OrderItem 对象。而如果OrderItem 还和其他的对象之间有级联关系,那么这样的操作会一直递归执行下去,cascade 的值只能从CascadeType.PERSIST(级联新建)、CascadeType.REMOVE(级联删除)、CascadeType.REFRESH(级联刷新)、CascadeType.MERGE(级联更新)中选择一个或多个。还有一个选择是使用CascadeType.ALL,表示选择全部四项。 4.fatch FetchType 类型的属性。 可选择项包括:FetchType.EAGER 和FetchType.LAZY。前者表示关系类(本例是OrderItem 类)在主类(本例是Order类)加载的时候同时加载,后者表示关系类在被访问时才加载。默认值是FetchType. LAZY。 @OrderBy(value = "id ASC")注释指明加载OrderItem 时按id 的升序排序 addOrderItem 和removeOrderItem 方法用来添加/删除订单项。 OrderItem.java @SuppressWarnings("serial") @Entity @Table(name = "OrderItems") public class OrderItem implements Serializable { private Integer id; private String productname; private Float price; private Order order; public OrderItem() { } public OrderItem(String productname, Float price) { this.productname = productname; this.price = price; } @Id @GeneratedValue public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getProductname() { return productname; } public void setProductname(String productname) { this.productname = productname; } public Float getPrice() { return price; } public void setPrice(Float price) { this.price = price; } @ManyToOne(cascade=CascadeType.REFRESH,optional=false) @JoinColumn(name = "order_id") public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } } 注释@ManyToOne 指明OrderItem 和Order 之间为多对一关系,多个OrderItem 实例关联的都是同一个Order 对象。 @ManyToOne 注释有四个属性:targetEntity、cascade、fetch 和optional,前三个属性的具体含义和@OneToMany注释的同名属性相同,但@ManyToOne 注释的fetch 属性默认值是FetchType.EAGER。 optional 属性是定义该关联类是否必须存在,值为false 时,关联类双方都必须存在,如果关系被维护端不存在,查询的结果为null。值为true 时, 关系被维护端可以不存在,查询的结果仍然会返回关系维护端,在关系维护端中指向关系被维护端的属性为null。optional 属性的默认值是true。optional 属性实际上指定关联类与被关联类的join 查询关系,如optional=false 时join 查询关系为inner join, optional=true 时join 查询关系为 left join. @JoinColumn(name = "order_id")注释指定OrderItem 映射表的order_id 列作为外键与Order 映射表的主键列关联。 二、一对一 一个人(Person)只有唯一的身份证号(IDCard),Person 与IDCard 是一对一关系 例: Person.java @SuppressWarnings("serial") @Entity @Table(name = "Person") public class Person implements Serializable{ private Integer personid; private String name; private IDCard idcard; @Id @GeneratedValue public Integer getPersonid() { return personid; } public void setPersonid(Integer personid) { this.personid = personid; } @OneToOne(optional = true,cascade = CascadeType.ALL, mappedBy = "person") public IDCard getIdcard() { return idcard; } public void setIdcard(IDCard idcard) { this.idcard = idcard; } } @OneToOne 注释指明Person 与IDCard 为一对一关系,@OneToOne 注释五个属性:targetEntity、cascade、fetch、optional 和mappedBy, 前四个属性的具体含义与@ManyToOne 注释的同名属性一一对应,请大家参考前面章节中的内容,fetch 属性默认值是FetchType.EAGER。mappedBy 属性的具体含义与@OneToMany 注释的同名属性相同。上面的optional = true 设置idcard 属性可以为null,也就是允讦没有身份证,未成年人就是没有身份证的 IDCard.java @SuppressWarnings("serial") @Entity @Table(name = "IDCard") public class IDCard implements Serializable{ private Integer id; private String cardno; private Person person; public IDCard() { } public IDCard(String cardno) { this.cardno = cardno; } @Id @GeneratedValue public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(nullable=false,length=18,unique = true) public String getCardno() { return cardno; } public void setCardno(String cardno) { this.cardno = cardno; } @OneToOne(optional = false, cascade = CascadeType.REFRESH) @JoinColumn(name = "Person_ID", referencedColumnName = "personid",unique = true) public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } } @OneToOne 注释指明IDCard 与Person 为一对一关系,IDCard 是关系被维护端,optional = false 设置person 属性值不能为null,也就是身份证必须有对应的主人。@JoinColumn(name = "Person_ID", referencedColumnName ="personid",unique = true)指明IDCard 对应表的Person_ID列作为外键与Person对应表的personid列进行关联, unique= true 指明Person_ID 列的值不可重复 三、多对多 学生和老师就是多对多的关系。一个学生有多个老师,一个老师教多个学生。多对多映射采取中间表连接的映射策略,建立的中间表将分别引入两边的主键作为外键。EJB3 对于中间表的元数据提供了可配置的方式,用户可以自定义中间表的表名,列名 Student.java @SuppressWarnings("serial") @Entity @Table(name = "Student") public class Student implements Serializable{ private Integer studentid; private String StudentName; private Set<Teacher> teachers = new HashSet<Teacher>(); public Student() {} public Student(String studentName) { StudentName = studentName; } @Id @GeneratedValue public Integer getStudentid() { return studentid; } public void setStudentid(Integer studentid) { this.studentid = studentid; } @Column(nullable=false, length=32) public String getStudentName() { return StudentName; } public void setStudentName(String studentName) { StudentName = studentName; } @ManyToMany(mappedBy = "students") public Set<Teacher> getTeachers() { return teachers; } public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; } } @ManyToMany 注释表示Student 是多对多关系的一边,mappedBy 属性定义了Student 为双向关系的维护端 Teacher.java @SuppressWarnings("serial") @Entity @Table(name = "Teacher") public class Teacher implements Serializable{ private Integer teacherid; private String TeacherName; private Set<Student> students = new HashSet<Student>(); public Teacher() {} public Teacher(String teacherName) { TeacherName = teacherName; } @Id @GeneratedValue public Integer getTeacherid() { return teacherid; } public void setTeacherid(Integer teacherid) { this.teacherid = teacherid; } @Column(nullable=false, length=32) public String getTeacherName() { return TeacherName; } public void setTeacherName(String teacherName) { TeacherName = teacherName; } @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY) @JoinTable(name = "Teacher_Student", joinColumns = {@JoinColumn(name = "Teacher_ID", referencedColumnName = "teacherid")}, inverseJoinColumns = {@JoinColumn(name = "Student_ID", referencedColumnName = "studentid")}) public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } public void addStudent(Student student) { if (!this.students.contains(student)) { this.students.add(student); } } public void removeStudent(Student student) { this.students.remove(student); } } @ManyToMany 注释表示Teacher 是多对多关系的一端。@JoinTable 描述了多对多关系的数据表关系。name 属性指定中间表名称,joinColumns 定义中间表与Teacher 表的外键关系。上面的代码中,中间表Teacher_Student的Teacher_ID 列是Teacher 表的主键列对应的外键列,inverseJoinColumns 属性定义了中间表与另外一端(Student)的外键关系 |