3 OneToMany ManyToMany MappedBy Cascade

Wesley13
• 阅读 683

1 双向1-N关联

对于1-N关联,Hibernate推荐使用双向关联,而且不要让1的一方控制关联关系,而使用多的一方控制关联关系。

a. 一的一方  表示班级

@Entity
@Table(name="team_1")
public class Team
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="team_id")
    private int id;
    private String name;
    @OneToMany(mappedBy="team",targetEntity=Student.class,cascade=CascadeType.ALL)
    
    
    private Set<Student>students=new HashSet<Student>();
//省略set  get方法
}

b.多的一方  表示学生

@Entity
@Table(name="student_1")
public class Student
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="student_id")
    private int id;
    private String name;
    @ManyToOne(targetEntity=Team.class,fetch=FetchType.LAZY)
    @JoinColumn(name="team_id",nullable=false,referencedColumnName="team_id")
    private Team team;
//省略set  get方法
}

c.持久化代码

Team team=new Team();
            team.setName("20150225");
            session.persist(team);
            Student student=new Student();
            student.setName("zhangsan");
            student.setTeam(team);
            
            
            
            Student student2=new Student();
            student.setName("lisi");
            student2.setTeam(team);
            
            session.save(student);
            session.save(student2);
            
            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映射连接表了。

下面示例表示课程与学生的关系。一个课程可由多个学生选择,一个学生可以选择多门课程

@Entity
@Table(name="course_2")
public class Course
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="course_id")
    private int id;
    private String name;
    @ManyToMany(targetEntity=Student.class)
    @JoinTable
    (name="student_course",
    joinColumns=@JoinColumn(name="courseId",referencedColumnName="course_id"),
    inverseJoinColumns=@JoinColumn(name="studentId",referencedColumnName="student_id")
    )
    
    private Set<Student> courses=new HashSet<Student>();

}

@Entity
@Table(name="student_2")
public class Student
{ 
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="student_id")
    private int id;
    private String name;
    @ManyToMany(targetEntity=Course.class,cascade=CascadeType.ALL)
    @JoinTable
    (name="student_course",
    joinColumns=@JoinColumn(name="studentId",referencedColumnName="student_id"),
    inverseJoinColumns=@JoinColumn(name="courseId",referencedColumnName="course_id")
    )
    
    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}级联策略。

版权声明:本文为博主原创文章,未经博主允许不得转载。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
红烧土豆泥 红烧土豆泥
3年前
MyBatis之ResultMap玩法回顾
1、SelectResultMap自定义结果集映射规则xmlselectfromemployeewhereidid关联查询级联属性封装结果xmlselectfromemployeee,departmentdwheree.idd.id关联查询associatio
Stella981 Stella981
3年前
Django之ORM(多对多)
一、ManyToManyField1、classRelatedManager"关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。它存在于下面两种情况:1.外键关系的反向查询2.多对多关联关系简单来说就是当 点后面的对象 可能存在多个的时
Stella981 Stella981
3年前
Hibernate利用关联关系操纵对象
Hibernate利用关联关系操纵对象数据对象之间关联关系有一对一、一对多及多对多关联关系。在数据库操作中,数据对象之间的关联关系使用JDBC处理很困难。本节讲解如何在Hibernate中处理这些对象之间的关联关系。本节使用到4个类,它们分别是Student(学生)、Card(学生证)、Group(班级)和Cou
Stella981 Stella981
3年前
Hibernate一对多(双向)及多对多
1.Hibernate:2.///3.双向关联就是有“一对多”和“多对一”两个关联组合而成德,在双向关联的两端都知道对方是谁。5.下面就开始演示这种关联。7.首先定义我们需要使用的POJO对象。9.public class Member10.{11.private String 
Wesley13 Wesley13
3年前
@OneToMany、@ManyToOne以及@ManyToMany讲解(五)
一、一对多(@OneToMany)1、单向一对多模型假设通过一个客户实体可以获得多个地址信息。对于一对多的实体关系而言,表结构有两种设计策略,分别是外键关联和表关联。(1)映射策略外键关联在数据库中表customer和表结构address定义,如下:createtablecustomer(
Stella981 Stella981
3年前
Hibernate关键字inverse和cascade
维护关联关系中,是否设置inverse属性:1.保存数据有影响。如果设置控制反转,即inversetrue,然后通过部门方维护关联关系。在保存部门的时候,同时保存员工,数据会保存,但关联关系不会维护。即外键字段为NULL2.获取数据无。3.解除关联关系?有影响。inverse
Wesley13 Wesley13
3年前
ThinkPHP 根据关联数据查询 hasWhere 的使用实例
很多时候,模型关联后需要根据关联的模型做查询。场景:广告表(ad),广告类型表(ad\_type),现在需要筛选出广告类型表中id字段为1且广告表中status为1的列表先看关联的设置部分 publicfunctionadType(){return$thisbelongsTo('A
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究