1 双向1-N关联
对于1-N关联,Hibernate推荐使用双向关联,而且不要让1的一方控制关联关系,而使用多的一方控制关联关系。
a. 一的一方 表示班级
1@Entity 2@Table(name="team_1") 3public class Team 4{ 5 @Id 6 @GeneratedValue(strategy=GenerationType.IDENTITY) 7 @Column(name="team_id") 8 private int id; 9 private String name; 10 @OneToMany(mappedBy="team",targetEntity=Student.class,cascade=CascadeType.ALL) 11 12 13 private Set<Student>students=new HashSet<Student>(); 14//省略set get方法 15}
b.多的一方 表示学生
1@Entity 2@Table(name="student_1") 3public class Student 4{ 5 @Id 6 @GeneratedValue(strategy=GenerationType.IDENTITY) 7 @Column(name="student_id") 8 private int id; 9 private String name; 10 @ManyToOne(targetEntity=Team.class,fetch=FetchType.LAZY) 11 @JoinColumn(name="team_id",nullable=false,referencedColumnName="team_id") 12 private Team team; 13//省略set get方法 14}
c.持久化代码
1Team team=new Team(); 2 team.setName("20150225"); 3 session.persist(team); 4 Student student=new Student(); 5 student.setName("zhangsan"); 6 student.setTeam(team); 7 8 9 10 Student student2=new Student(); 11 student.setName("lisi"); 12 student2.setTeam(team); 13 14 session.save(student); 15 session.save(student2); 16 17 tx.commit();
在持久化代码中,首先创建了一的一方 team对象,并对他进行了保存, 然后创建了多的一方,并进行了保存。这是符合客观事实的,即首先要有班级,然后才能有学生从属于某个班级。如果不这样做,那么将会抛出异常。对于这样的程序,应注意:
- 最好先持久化Team对象。因为程序希望持久化student对象时,Hibernate可为Student的外键属性分配值,也就是说,象student表插入记录时,该记录的外键已制定了值,这表明他参照的主表记录已经存在。
- 先设置student与team的关联关系(student2.setTeam(team);),然后再保存student。如果顺序反过来 ,将会增加update语句。
- 不要通过team对象来设置关联关系,因为在team中已经指定了@MappedBy属性,该属性表明Team对象不能控制关联关系。所以,1.要将team的数据,赋给student,即用student的setTeam()方法去捆定team数据;2.在进行数据插入/更新session.save()/session.update()时,最后操作的是student.
- 在team一方设置了cascade属性为ALL,而在@manyToOne一方不要设置级联属性
2 N-N双向关联
双向N-N关系需要两端都使用Set集合属性,两端都增加对集合属性的访问。双向N-N关系只能采用连接表的方式。
双向N-N关联需要在两端分别使用@ManyToMany修饰Set集合属性,并在两端都是用@JoinTable显示映射连接表。如果程序希望一端放弃控制关联关系,则可在这一端的@ManyToMany注解中指定mappedby属性,这一端就无须、也不能使用@JoinTable映射连接表了。
下面示例表示课程与学生的关系。一个课程可由多个学生选择,一个学生可以选择多门课程
1@Entity 2@Table(name="course_2") 3public class Course 4{ 5 @Id 6 @GeneratedValue(strategy=GenerationType.IDENTITY) 7 @Column(name="course_id") 8 private int id; 9 private String name; 10 @ManyToMany(targetEntity=Student.class) 11 @JoinTable 12 (name="student_course", 13 joinColumns=@JoinColumn(name="courseId",referencedColumnName="course_id"), 14 inverseJoinColumns=@JoinColumn(name="studentId",referencedColumnName="student_id") 15 ) 16 17 private Set<Student> courses=new HashSet<Student>();
}
1@Entity 2@Table(name="student_2") 3public class Student 4{ 5 @Id 6 @GeneratedValue(strategy=GenerationType.IDENTITY) 7 @Column(name="student_id") 8 private int id; 9 private String name; 10 @ManyToMany(targetEntity=Course.class,cascade=CascadeType.ALL) 11 @JoinTable 12 (name="student_course", 13 joinColumns=@JoinColumn(name="studentId",referencedColumnName="student_id"), 14 inverseJoinColumns=@JoinColumn(name="courseId",referencedColumnName="course_id") 15 ) 16 17 private Set<Course> courses=new HashSet<Course>();
}
3 Cascade
(1)对于关联实体而言,Hibernate默认不会启用级联操作,当父对象被保存时,他关联的子实体不会被保存。为了启用不同持久化操作的级联行为,Hibernate定了如下级联风格
-
CascadeType.ALL:指定Hibernate将所有的持久化操作都级联到关联实体。
-
CascadeType.MERGE:指定Hibernate将级联更新操作都级联到关联实体。
-
CascadeType.PERSIST:指定Hibernate将级联保存操作都级联到关联实体。
-
CascadeType.REFRESH:指定Hibernate将级联同步操作都级联到关联实体。
-
CascadeType.REMOVE:指定Hibernate将级联移除持久化操作都级联到关联实体。
(2)Hibernate还支持一个特殊的级联策略:删除孤儿对象(可通过@OneToMany,@OneToOne的orphanRemoval属性来启动级联策略)
<span style="font-size:18px;">@OneToMany(mappedBy="team",targetEntity=Student.class,cascade=CascadeType.ALL,orphanRemoval=true)</span>
该策略只能对应当前实体1的一端,且底层数据表为主表时有效。对于启用了roaphanRemoval策略的级联操作而言,当程序通过主表实体切断与从表实体的关联关系时-虽然此时主表实体对应的记录并没有删除,但由于从表实体失去了对主表实体的引用,因此这些从表实体成为了“孤儿”,hibernate会自动删除这些记录。
(3)对于级联的设定,Hibernate有如下建议
- 在@ManyToOne中指定级联没有什么意义。级联通常在@OneToOne和@OneToMany关系中,因为级联操作应该是由主表记录传播到从表记录,通常从表记录不应该传播到主表记录。
- 如果从表记录被完全限制在主表记录之内,则可以指定cascade=Cascade.ALL,再配合orphanRemoval=true级联策略,将从表实体的生命周期完全交给主表实体管理。
- 如果经常在某个事务中同时使用主表实体和从表实体,则可以考虑cascade={CascadeType.PERSIST,CascadeType.MERGE}级联策略。
版权声明:本文为博主原创文章,未经博主允许不得转载。