随笔-42  评论-578  文章-1  trackbacks-0
近来,在做的一个NewsMS项目中,需要用到多对多关联映射,以下是项目中用到的两个实体类:用户类User和角色类Role,它们之间是多对多的关系。
//用户表
@Entity
@Table(name
="rong_user")
public class User{

    
//省略其它内容

    
private Set<Role> roles = new LinkedHashSet<Role>();    //角色集合
    
    @ManyToMany(cascade 
= {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name 
= "rong_user_role", joinColumns = { @JoinColumn(name ="user_id" )}, inverseJoinColumns = { @JoinColumn(name = "role_id") })
    @OrderBy(
"id")
    
public Set<Role> getRoles() {
        
return roles;
    }

    
public void setRoles(Set<Role> roles) {
        
this.roles = roles;
    }

}

//角色表
@Entity
@Table(name
="rong_role")
public class Role{
    
    
//省略其它内容

    
private Set<User> user = new LinkedHashSet<User>();        //用户集合

    @ManyToMany(cascade 
= {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "roles", fetch = FetchType.LAZY)
    
public Set<User> getUser() {
        
return user;
    }

    
public void setUser(Set<User> user) {
        
this.user = user;
    }

}


         这两个生成数据库中的三个表,分别是rong_user, rong_role和一个中间表rong_user_role。
         Hibernate和JPA控制关联关系的,只能是一方,不能双方控制的,上面的程序中,我通过在Role类中设置mappedBy="roles"来设置由User来控制关系,
         这样,问题就出现了:当我在要删除角色Role时,如果没有用户拥有这个角色的话,就能成功删除;如果有用户拥有这个角色的时候,就不能删除,会抛以下异常:
12:53:33,125  WARN JDBCExceptionReporter:100 - SQL Error: 1451, SQLState: 23000
12:53:33,125 ERROR JDBCExceptionReporter:101 - Cannot delete or update a parent row: a foreign key constraint fails (`newsms/rong_user_role`, CONSTRAINT `FKF1698421A337A5FA` FOREIGN KEY (`role_id`) REFERENCES `rong_role` (`id`))
12:53:33,171 ERROR AbstractFlushingEventListener:324 - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
/****堆栈信息略****/
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`newsms/rong_user_role`, CONSTRAINT `FKF1698421A337A5FA` FOREIGN KEY (`role_id`) REFERENCES `rong_role` (`id`))
/******堆栈信息略*****/

      当我设置成单向关系映射时,即把Role类中,Set<User>信息去掉,这样,也不能删,原因也是说有外键约束!怎么办?
      苦恼了好几天,最后,只能归于Hibernate(JPA)的多对多关联映射设计得有点不符实际!就像上面我说的例子,有人选了某角色,就不能删掉该角色。还有一种做法是,在Role类中:
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE,CascadeType.REMOVE}, mappedBy = "roles", fetch = FetchType.LAZY)
    
public Set<User> getUser() {
        
return user;
    }
        即加多一个“CascadeType.REMOVE”,这样能把角色Role给删掉了,但连拥有该角色的所有用户User也被级联删掉了。这样来看,某个用户拥有许多角色,就因为其中有这一个角色,就被级联删了整个自己,那不是很冤枉。这也不符合实际!
        个人认为,Hibernate(JPA)在设置多对多关联映射时,应该有做法能使得双方都能控制关联关系才好,才符合实际吧!但事实上,好像还没有发现有Hibernate(JPA)这种能力!


本文原创,转载请注明出处,谢谢!http://www.blogjava.net/rongxh7(心梦帆影JavaEE技术博客)
    

posted on 2009-06-08 13:33 心梦帆影 阅读(26922) 评论(15)  编辑  收藏 所属分类: HibernateJPA

评论:
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2009-06-08 18:18 | 虎啸龙吟
这样就是符合实际啊:当某个用户拥有某个角色的时候,不应该删除该角色吧!  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2009-06-08 18:26 | 心梦帆影
@虎啸龙吟
用户与角色是多对多的关系,如果系统不需要或个角色了,而因为有用户跟这个角色有关联,而删不了!那怎么对角色进行管理?只能添加,修改,不能删除?  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2009-06-08 19:20 | YangL
LZ也在用SpringSide吧,呵呵  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2009-06-08 21:01 | 心梦帆影
@YangL
被你看穿了,呵呵
但我没有直接把Springside当组件用,而是学习它!
有兴趣交流一下不?我QQ:121040245,呵呵  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2009-06-08 21:18 | 小人物
学习了!  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2009-06-09 20:44 | huliqing
这不应该是hibernate的不完美之处,数据库的这个作法是正确的,这涉及到数据完整与安全性的问题。我认为你应该先明确的处理掉相关的持有该角色的相关用户的对于该角色的关系。也就是说先删除相关用户对该角色的持有关系,再删除该角色就没有问题。
或者选择不作外键约束,但是这样就会对比较严格的系统造成数据冗余,不完整,还包括安全问题。  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2009-06-11 00:33 | 虎啸龙吟
@YangL
可以先去掉该用户的角色,再删除该角色啊  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2012-12-23 11:32 | lin
双方都用OneToMany就行了  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处[未登录] 2013-06-15 13:01 | James
关联关系不要双方配置 只在主表配置  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处[未登录] 2013-06-15 13:03 | James
@ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE})
@JoinTable(name = "adgroup_ad", joinColumns = { @JoinColumn(name = "adgroup_id") }, inverseJoinColumns = { @JoinColumn(name = "ad_version_id") })
这是我的项目的主表部分的注解配置 测试增加修改都可以 删除也只删除关联关系  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处[未登录] 2013-06-15 13:10 | James
汗 SORRY 发现我的问题和你的不一样的 我这里还是会出现你说的这种情况 SORRY 看来它还真是设计有点不合理的  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2013-09-02 10:49 | phevose
这在业务逻辑上是完全合理的,正在被使用的角色是不应该被删除的,如果删除那么应该做级联删除,对应的用户也应该一并删除,或者应该先解除关联关系后再删除该角色。  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2014-11-14 16:16 | 雪妮星迹
楼主想要的级联功能,可以使用数据库的外键约束控制。  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2015-01-27 15:20 | lp
@心梦帆影
可以不建立外键关联,通过应用控制数据的完整性。  回复  更多评论
  
# re: Hibernate(JPA)多对多(ManyToMany)关联映射不完美之处 2016-04-07 15:10 | coolcjava
只有两个实体类都配置了joinColumns和inverseJoinColumns属性,并且位置互相调换,就可以使用双向维护  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: