Hibernate JPA 之关联映射

本文详细介绍了Java实体类中的一对多、多对一及多对多关系的配置与实现,包括外键、级联保存、维护端与被维护端的概念,以及多对多关系的维护端和被维护端如何确定。通过实例代码展示了如何在控制器中正确配置这些关系,避免只保存一方实体而不保存多方实体的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一对多

  • 一方
@Entity
@Table(name="test_user")
public class User {
private String id;
private List<LoginHistory> loginHistories;
@Id
@GeneratedValue(generator = "uuid-gen")
@GenericGenerator(name = "uuid-gen", strategy = "uuid")
@Column(name ="id",length=32)
public String getId() {
    return id;
}
public void setId(String id) {
    this.id = id;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
public List<LoginHistory> getLoginHistories() {
    return loginHistories;
}
public void setLoginHistories(List<LoginHistory> loginHistories) {
    this.loginHistories = loginHistories;
}
}

以上是一方的配置,mappedBy=”被维护端外键属性”,mappedBy指明两个关联的实体Bean中,被维护方的外键属性。只能配置在一方,即关系维护方。

多方

@Entity
@Table(name="test_login_history")
public class LoginHistory {
private String id;
@Id
@GeneratedValue(generator = "uuid-gen")
@GenericGenerator(name = "uuid-gen", strategy = "uuid")
@Column(name ="id",length=32)
public String getId() {
    return id;
}
public void setId(String id) {
    this.id = id;
}
@ManyToOne(cascade = { CascadeType.REFRESH, CascadeType.MERGE,}, optional = true)
@JoinColumn(name = "user_id",nullable=true) 
public User getUser() {
    return user;
}
public void setUser(User user) {
    this.user = user;
}
}

一对多操作实例

@RequestMapping("login")
public String login(User user,ModelMap map){
    LoginHistory loginHistory=new LoginHistory();
    Date d=new Date();
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String datestr=sdf.format(d);
    //NO.1 为多方设置外键属性(即一方的实体)
    loginHistory.setUser(user);
    loginHistory.setLoginDate(datestr);
    loginHistory.setLoginIP("127.0.0.1");
    List<LoginHistory> lhlist=new ArrayList<LoginHistory>();
    lhlist.add(loginHistory);
    //NO.2 将多方的实体,赋值给一方
    user.setLoginHistories(lhlist);
    //NO.3 只保存一方对象,即可级联保存。
    userService.addUser(user);
    map.put("status", "success");
    return "welcome";
    }

许多新手配置时,只有关键的NO.2,NO.3 没有设置NO.1 ,这导致数据库,只保存了一方的实体,而没有级联保存多方的实体。

多对多

下面以User和Role为例子,介绍下多对多。直接上代码了,请自行阅读。

@Entity
@Table(name="test_user")
public class User {
private String id;
@Id
@GeneratedValue(generator = "uuid-gen")
@GenericGenerator(name = "uuid-gen", strategy = "uuid")
@Column(name ="id",length=32)
public String getId() {
    return id;
}
public void setId(String id) {
    this.id = id;
}
private List<Role> roles;
/*
  joinColumns写的是本表在中间表的外键名称,
  inverseJoinColumns写的是另一个表在中间表的外键名称。
 */
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "fc_role_user", joinColumns = @JoinColumn(name = "fk_user_id"), inverseJoinColumns = @JoinColumn(name = "fk_role_id"))
public List<Role> getRoles() {
    return roles;
}
public void setRoles(List<Role> roles) {
    this.roles = roles;
}
}


@Entity
@Table(name="test_role")
public class Role {
    private String id;//角色id
    private String rolename;//角色名称
    private List<User> users;
    @Id
    @GeneratedValue(generator = "uuid-gen")
    @GenericGenerator(name = "uuid-gen", strategy = "uuid")
    @Column(name ="id",length=32)
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    @Column(name="role_name",length=50)
    public String getRolename() {
        return rolename;
    }
    public void setRolename(String rolename) {
        this.rolename = rolename;
    }
    @ManyToMany(fetch = FetchType.LAZY,cascade={CascadeType.PERSIST,CascadeType.MERGE},mappedBy = "roles")
    public List<User> getUsers() {
        return users;
    }
    public void setUsers(List<User> users) {
        this.users = users;
    }

}

// 多对多保存实例【controller】
    @RequestMapping("login")
    public String login(User user,ModelMap map){

        Role role=null;
        role=roleService.getRoleByName("admin2");
        if(role==null){
            role=new Role();
            role.setRolename("admin2");
            roleService.addRole(role);
        }
        List<Role> rolelist=new ArrayList<Role>();
        rolelist.add(role);
        user.setRoles(rolelist);
        userService.saveUser(user);
        return "welcome";
    }

关于多对多的维护端和被维护端,如何确定,我要啰嗦几句。之前因为搞不明白,没少让坑。网上关于维护端和被维护的介绍,大都一笔带过,而且概念模糊,对本人开发,造成了很大的误导。我经过实践,总结如下:
所谓的维护端,就是级联关系的主导方,一般对应多对多关系中“少数”一方,何为“少数”,就拿上边的例子解释,一个系统可以有几万个用户,但角色肯定不会也是几万个,最多也就是十几个,那么角色就是“少数”方,也就是维护方。你的级联属性,要在“少数”方配置,级联保存的时候,你可以直接将少数方,作为一个常用属性,赋值给多的一方,直接保存多的一方,你们之间的关系,也就被保存了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值