使用的开发环境spring2.5+JPA+hibernate+struts2
模型 是一张employee表,一张client表,销售表sale,销售明细表sale_details
sale表中,包括字段employee_id,client_id以与employee、client表关联。
问题是:
在维护sale表时,增加数据填写employee、client信息时,都没错误,但是更新这两个字段信息时确出现错误提示:说把employee表里面id的原来的值给改了,因为id是主键不能修改,所以就提示错误。比如sale表中保存的employee_id为3,在employee中有条记录与此对应,现在在UI中选择id为4的用户,然后保存,则提示上面说的错误。
我查找了entity的关系设置,基本上没什么问题啊,而且使用testcase测试也没问题;
[b]问题是在保存sale表时,struts的action中为什么会去保存employee的实体呢?[/b]
我前台用的employee选择是struts2的下拉框组件。
这问题困扰了我好几天
有那位仁兄知道的,请指教,先谢谢了
[b]问题补充:[/b]
JPA里面没设置啊,我把代码写出来,您看一下
@ManyToOne(cascade=CascadeType.Refresh)
public Employee getEmployee() {
return this.employee;
}
CascadeType的几种我都试过的,都不行
@ManyToOne 什么也不加也试过,也不行
[b]问题补充:[/b]
@ManyToOne什么也不写呢?那还能产生级联更新问题吗?
麻烦告诉我设置方式,我查了一些资料,试了一些,还没找到正确方式
[b]问题补充:[/b]
现在是不需要级联更新的,如,更新sale表的employee信息时,别去更新employee实体去,我在配置sale实体与employee实体关系时使用@ManyToOne什么也没加,也出现问题。
另外补充一下:客户端action中,我用了modeldriven,在页面中使用struts2的下拉框组件
sea723 朋友遇到的问题 和我这个是一个意思
[b]问题补充:[/b]
问题已解决,感谢iampurse 和 sea723
我现在也是在action中,建立了虚拟的属性
楼上的很有才,什么叫莫名其妙的答案。
别人连代码 运行环境都没有 给你提供解决思路,你就这点态度?
出现这个问题可能有两个原因(据我猜想,也可能是你说的莫名其妙)
一是: OneToMany 和 ManyToOne配置有问题,建议你先看看书在来写。
二是:你更新级联关系的时候代码有问题,配置他的fetchType="lazy"
不要即时取出来,然后new一个新的父节点 并设置给他。
[code="java"]
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parentid")
public WsUnit getWsUnit() {
return this.wsUnit;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "wsUnit")
public Set<WsUnit> getWsUnits() {
return this.wsUnits;
}
[/code]
你修改的时候,他的父节点 被你取出来的话,直接就变成一个受管实体。
你修改的父节点的话,他自动会设置到原来的那个去。
在保存sale表时,struts的action中去保存employee的实体,那一定是jpa里配置关联关系成级联保存了
CascadeType.REFRESH(级联刷新)
http://taoistwar.iteye.com/blog/388912
sale表中保存的employee_id为3,在employee中有条记录与此对应,现在在UI中选择id为4的用户,然后保存,
这样就已经改变了关联的id值,自然保存sale的时候当然还会去检查它关联的employee是否存在之类,发现改变,就出这个问题了
这个问题也和你struts的action时保存sale的代码多少有点关系吧,特殊情况特殊解决,如果不行,可能就是jpa之类的限制,这是一定多少都有限制的,hibernate也一样嘛,就自己构建hql或sql语句进行处理,
有些特殊情况,orm框架是解决不了的,
我也碰到这个问题了,觉得hibernate处理得有点问题,为何sale保存时,一定要去检查employee呢,比如一个子类目移动到另外一个类目下,或者说一个员工从一个部门调到另外一个部门,很常见的场景啊,期待高手来解决!
无比汗 既然你是级联的
ManyToOne里头是不能设置CascadeType的
直接在OneToMany那边设置一下就可以了。
发现为撒回答问题的人就不能懂了在回答。
我碰到的问题是这样的:一个商品分类,有上级分类、有下级分类,代码如下:
@Entity
public class Category extends IdEntity {
private Category parent;
private Set children;
@ManyToOne //一个类目有一个父类目
@JoinColumn(name = "parent_id")
public Category getParent() {
return parent;
}
public void setParent(Category parent) {
this.parent = parent;
}
@OneToMany //一个类目可以有零个到多个子类目
public Set<Category> getChildren() {
return children;
}
public void setChildren(Set<Category> children) {
this.children = children;
}
}
现在有一个需求,需要将一个类目移到另外一个类目下,常规的做法是更新父类目ID即可,但是现在更新父类目ID时,就报
Caused by: org.hibernate.HibernateException: identifier of an instance of com.xx.entity.biz.Category was altered from 4 to 1
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:81)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:187)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:143)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:49)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:655)
... 121 more
不知道是不是我的设计有问题还是配置错误,请知道的同学指导一下,还请回答的同学们在给出答案之前测试一下,不要给一个莫名其妙的答案,很郁闷的,谢谢,这两天搜索了很多,发现碰到这个问题的同学还挺多,但是都没有解决方案
问题终于解决,在页面上的原来写的是 ,这样在struts自动绑定变量时,会修改model对象的parent属性的id属性(我的代码里model就是category对象),由于parent对象也是持久化对象,这样,在hibernate flush时会提交在这次session中所有修改过的持久化对象,所以parent对象也会被提交,由于id是主键,不能修改,所以就报出了不能修改主键的错误,没有跟踪到struts绑定变量的代码,大家可以跟踪一下。
to iampurse,不好意思,我不是针对你。我是看到大家在回答问题时,自己没有真正的弄明白或者没有弄清楚问题的真正场景时,就随便下结论,浪费了大家的时间,精力,也影响心情。
忘了说最终的解决办法了:将 ,改成 ,这样在需要修改model的parent属性时,根据pid新建一个parent对象赋给model对象即可