首先,我将简要介绍一下我的问题。
我正在开展一个试验项目来测试我最近在Hibernate中学到的东西。我们的想法是集成Spring,Spring MVC和Hibernate。似乎一切都运转得很好,直到我遇到这个问题,这花了我一整天但仍然没有解决方案。
这个想法非常简单。有两个实体,“角色”和“用户”。一个人可以拥有一个角色,这使得它成为多对一的关系。角色可以分配给很多人,这意味着一对多的关系。
因此,我的代码是这样的。角色:
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(length=20,nullable=false,name="rolename",unique=true)
private String name;
@OneToMany(cascade=CascadeType.ALL, mappedBy="role")
private Set<UserBean> users = new HashSet<UserBean>();
用户:
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@ManyToOne(optional=true,cascade=CascadeType.ALL,unique=true)
@JoinColumn(name="role_id")
private RoleBean role=new RoleBean();
另外,我使用Spring MVC来绑定值。这是代码:
<form:form modelAttribute="user"
action="${pageContext.request.contextPath}/add">
<div>
<form:input path="username"
/>
<form:errors path="username" />
<br>
<form:password path="password" placeholder="password" />
<form:errors path="password" />
<br> <form:select path="role.name">
<option value="clerk">clerk</option>
<option value="salesperson">salesperson</option>
<option value="manager">manager</option>
</form:select>
</div>
<input type="submit" value="submit" />
</form:form>
您会在前端页面看到我添加了<form:select>
标记,希望此标记可以使用“级联”设置来完成工作。
它运作得很好。
然而,当我进一步测试代码时,发生了一些事情。
我的期望是理想情况下,Hibernate会收到“rolename”,然后使用名称创建一个角色项,并将这个新角色保存到数据库中。如果两个或多个用户使用相同的“rolename”(在此设置下是职员,经理或销售人员)注册,则hibernate可以理解,由于{{{},hibernate不应该再次将值插入“role”表中。 1}}设置。
然后发生了一些奇怪的事情。如果我使用相同的“rolename”向两个“用户”注册两次,hibernate会给我一个错误,上面写着:
unique=true
老实说,我知道这个错误是怎么发生的。这是因为Duplicate entry 'clerk' for key 'UK_a5k2ae0srn5n63xyhst1dllhq'
设置。但是,如果我删除此设置并重新运行编程,程序可能会自动将具有相同角色名称的多个“角色”项插入到系统中,以便表格看起来像这样:
"unique=true"
显然,这不是我想要的,因为没有人会期望公司/组织可以拥有完全相同角色名称的不同角色。
我认为在hibernate映射设置或级联中必定存在我做错的事情。但即使我努力在这里和通过谷歌搜索可能的答案,我还没有找到任何解决这个问题的方法。
那么,你介意给我一个可能的解决方案吗?
答案 0 :(得分:0)
CascadeType.ALL的含义是持久性将所有EntityManager操作(PERSIST,REMOVE,REFRESH,MERGE,DETACH)传播(级联)到相关实体。
由于您不需要创建新的角色,因此您只需将其从角色中删除即可。
@OneToMany(mappedBy="role")
private Set<UserBean> users;
添加setter和getter。 。
用户相同。
答案 1 :(得分:0)
你应该改变一些事情:
rolesList
是包含所有可能角色的modelAttribute):<form:select path="role.id">
<form:options items="${rolesList}" itemValue="id" itemLabel="name"/>
</form:select>
UserBean
对象,RoleBean
设置为前端的选定角色,Hibernate将负责保存role_id
。 答案 2 :(得分:0)
首先,我要感谢您回答我的问题并提出解决方案!
最后,我按照@Mubin的建议完成了这项工作。
我在控制器中添加了一些代码:
ArrayList<RoleBean> rolelist = new ArrayList<RoleBean>();
RoleBean r1 = new RoleBean();
RoleBean r2 = new RoleBean();
RoleBean r3 = new RoleBean();
r1.setId(1);
r1.setName("clerk");
r2.setId(2);
r2.setName("salesman");
r3.setId(3);
r3.setName("manager");
rolelist.add(r1);
rolelist.add(r2);
rolelist.add(r3);
view.addObject("rolelist", rolelist);
所以,简单地说,我将总结一下您的参考资料!
首先,我最初的想法是错误的。我以为我应该通过&#34;角色&#34;从前端到后端。但是,这个想法本身就是反逻辑的。公司创建角色,并将这些角色分配给不同的员工。员工很少需要公司为他们创建角色。
所以,首先,我应该首先使用SQL在数据库中创建角色。
在我弄清楚之后,一切都显得顺利。如果数据库中的角色保持不变,我需要做的就是将信息传递给用户表中的外键,将每个人与其角色相关联。
所以我使用了这个标签:
<form:select path="role.id">
<form:options items="${rolelist}" itemValue="id" itemLabel="name"/>
</form:select>
hibernate的作用是:
它从前端获取输入,检查&#34; itemValue&#34;,即user.role.id.然后比较这个值是否已经在数据库中(绝对是&#34;是&#34;),然后将id与用户角色链接。
我认为这非常重要,因为昨天,当我试图解决问题时,有一次尝试我只是删除了rolebean的cascade = ALL,然后程序引发了一个异常:瞬态实体未保存。
这是因为没有级联,程序只会保存&#34;用户&#34;没有保存&#34;角色&#34;第一。如果没有&#34;角色&#34;在表格中,没有&#34;角色ID&#34;附上。
所以,问题解决了!谢谢!