我正在为ManyToMany之间的关系构建示例:User(1)-()AccessLevel()-(1)Role

我用休眠实现在Java中实现了3个类,如下所示:

班级用户

@Entity
@Table(name="user")
public class User {
    @Id
    @GeneratedValue
    @Column(name="USER_ID")

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "access_level", joinColumns = {
            @JoinColumn(name = "user_id", nullable = false, updatable = false) },
            inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) })
    private Set<Role> roles = new HashSet<Role>(0);


类角色

@Entity
@Table(name="role")
public class Role {

    @Id
    @GeneratedValue
    @Column(name="role_id")
    private Integer id;

    @Column(name="role_name")
    private String roleName;


类访问级别

@Entity
@Table(name="access_level")
public class AccessLevel {

    @Id
    @GeneratedValue
    private Integer id;
    @Column(name="role_id")
    private Integer  roleId;
    @Column(name="user_id")
    private Integer  userId;


问题:

当我使用merge方法持久化User Bean时,会出现异常:

@Service
public class UserServiceImpl implements UserService {

    @PersistenceContext
    private EntityManager em;

    @Override
    @Transactional
    public void save(User user) {
        em.merge(user);
    }


例外

org.springframework.web.util.NestedServletException:请求过程

ing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into access_level (user_id, role_id) values (?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)


如您所见,hibernate正在尝试运行此查询:

insert into access_level (user_id, role_id) values (?, ?)


从我的角度来看,即使我已将@GeneratedValue添加到id属性,似乎休眠状态也没有为AccessLevel生成主键。

注意:
我正在使用Postgresql的生产环境和使用HSQL数据库的开发环境,该环境从一开始就根据实体描述创建所有架构。两种环境都会产生相同的问题。

问候,
克里斯蒂安·科罗拉多

最佳答案

原因:

似乎对于ManyToMany关系,您不需要为“联接表”定义一个类。因此,如果我取消AccessLevel实体,则逻辑将工作正常。我进一步解释:

说明:

在定义User类时,我还描述了与Role的关系:

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "access_level", joinColumns = {
            @JoinColumn(name = "user_id", nullable = false, updatable = false) },
            inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) })
    private Set<Role> roles = new HashSet<Role>(0);


重要的是,我已经告知休眠状态,用户实体将通过称为“ access_level”的表与角色实体相关,并且该表将具有user_id和role_id列,以便加入先前的实体。

到目前为止,所有这些都是休眠的,以便处理多对多关系,因此在合并时,它将使用该信息来创建和调整此脚本:

insert into access_level (user_id, role_id) values (?, ?)


现在,当我为AccessLevel定义一个新实体时出现了问题:

@Entity
    @Table(name="access_level")
    public class AccessLevel {

        @Id
        @GeneratedValue
        private Integer id;
        @Column(name="role_id")
        private Integer  roleId;
        @Column(name="user_id")
        private Integer  userId;


现在,我告诉休眠状态,有一个与AccessLevel实体相关的表“ access_level”,它具有3列,最重要的是Id,它是主键。

所以我两次定义了“ access_level”!

解:


我删除了用于access_level表的实体。
我重新编写了生产脚本,以便使用“ access_level”
仅user_id / role_id列。


注意:最好知道如何在联接表中添加主键而不产生问题。另一种选择是在数据库中添加一个组合的主键(user_id / role_id),该主键与休眠无关。

10-06 01:18