我在使用双向Many-to-one关系时,想实现数据字典管理,1的一端是数据字典类别比如"性别","学历",many一端通过外键进行引用.
1.单独对1的一端进行crud都没有问题,建好连接以后,删除1端,many同时删除有联系的记录
2.设置好了表间的联系.进行CRD没啥问题.update的时候,不对外键进行任何修改时.正常运行.修改外键时,报如下错误
javax.servlet.ServletException: org.springframework.orm.hibernate3.HibernateSystemException: identifier of an instance of com.skycity.office.bean.DictType was altered from 4028898e1ae1d3d6011ae1d4dea70001 to 4028898e1abd9f87011abdc769de0003; nested exception is org.hibernate.HibernateException: identifier of an instance of com.skycity.office.bean.DictType was altered from 4028898e1ae1d3d6011ae1d4dea70001 to 4028898e1abd9f87011abdc769de0003
网上找了很久.有的说不是many-to-many的问题.很多地方说什么merge().saveOrUpdate(),尝试了很多,网上详细的解决方案也没有.将修改时调用的方法注释了,还是会出现这种错误.有点崩溃的感觉
试了merge().这里提到merge()也碰到一个奇怪的问题.merge按正常来说应该是合并的意思.我在many端修改时.使用了merge,居然one端进行了修改
比如.我想将"性别"为"女"的类型改成"学历"(当然这是我测试),他最后修改了我的字典类别表,将"性别"类别改成了"学历"类别.不知道是什么原因.
贴出我的部分代码:
字典类别表的POJO
package com.skycity.office.bean;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "PFDICTTYPE")
public class DictType extends IdEntity{
private String name;
private String type;
private Set<DictCode> dictCode=new HashSet<DictCode>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@OneToMany(mappedBy="dictType",cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
public Set<DictCode> getDictCode() {
return dictCode;
}
public void setDictCode(Set<DictCode> dictCode) {
this.dictCode = dictCode;
}
}
字典表的POJO
package com.skycity.office.bean;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
@Entity
@Table(name = "PFDICTCODE")
public class DictCode extends IdEntity{
private String dictName;
private String dictDesc;
private String dictValue;
private DictType dictType;
@ManyToOne(cascade = { CascadeType.PERSIST,CascadeType.MERGE},fetch=FetchType.LAZY)
@JoinColumn(name = "dictType",nullable = false,updatable=true,insertable = true)
public DictType getDictType() {
return dictType;
}
public String getDictName() {
return dictName;
}
public void setDictName(String dictName) {
this.dictName = dictName;
}
public String getDictDesc() {
return dictDesc;
}
public void setDictDesc(String dictDesc) {
this.dictDesc = dictDesc;
}
public void setDictType(DictType dictType) {
this.dictType = dictType;
}
public String getDictValue() {
return dictValue;
}
public void setDictValue(String dictValue) {
this.dictValue = dictValue;
}
@SuppressWarnings("unchecked")
@Transient
public List<String> getCheckedDictTypeIds() throws Exception {
return null;// CollectionUtils.collectAsList(roles, "id");
}
}
DictCode表的Service实现
package com.skycity.office.service.impl;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.orm.hibernate.Page;
import org.springside.modules.orm.hibernate.SimpleHibernateTemplate;
import com.skycity.office.bean.DictCode;
import com.skycity.office.bean.DictType;
@Service
@Transactional(readOnly = true)
public class DictCodeServiceImpl{
private SimpleHibernateTemplate<DictCode, String> dictCodeDAO;
private SimpleHibernateTemplate<DictType, String> dictTypeDAO;
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
dictCodeDAO = new SimpleHibernateTemplate<DictCode, String>(sessionFactory, DictCode.class);
dictTypeDAO = new SimpleHibernateTemplate<DictType, String>(sessionFactory, DictType.class);
}
public Page<DictCode> getAllDictCodes(Page<DictCode> page) {
return dictCodeDAO.findAll(page);
}
public DictCode getDictCode(String id) {
return dictCodeDAO.get(id);
}
public List<DictType> getAllDictTypes() {
return dictTypeDAO.findAll();
}
DictCode Action:
package com.skycity.office.web.action;
import java.util.List;
import org.apache.struts2.config.ParentPackage;
import org.apache.struts2.config.Result;
import org.apache.struts2.config.Results;
import org.apache.struts2.dispatcher.ServletActionRedirectResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springside.modules.orm.hibernate.Page;
import com.skycity.office.bean.DictCode;
import com.skycity.office.bean.DictType;
import com.skycity.office.service.impl.DictCodeServiceImpl;
import com.skycity.office.util.Constants;
import com.skycity.office.web.struts2.CRUDActionSupport;
@ParentPackage("default")
@Results({
@Result(name=CRUDActionSupport.SUCCESS, value="/list", type=ServletActionRedirectResult.class)
})
public class DictCodeAction extends CRUDActionSupport<DictCode>{
private static final long serialVersionUID = 1L;
@Autowired
private DictCodeServiceImpl dictCodeService;
private String id;
private DictCode entity;
private List<DictType> allDictTypes;
private Page<DictCode> page = new Page<DictCode>(Constants.DEFAULT_PAGE_SIZE, true);
@Override
public String delete() throws Exception {
dictCodeService.deleteDictCode(id);
return RELOAD;
}
@Override
public String edit() throws Exception {
allDictTypes = dictCodeService.getAllDictTypes();
return INPUT;
}
@Override
public String list() throws Exception {
page=dictCodeService.getAllDictCodes(page);
return SUCCESS;
}
public String show() throws Exception{
return SHOW;
}
@Override
public String save() throws Exception {
if (null!=id && !"".equals(id)){
dictCodeService.updateDictCode(entity);
}else{
dictCodeService.saveDictCode(entity);
}
return RELOAD;
}
public void prepare() throws Exception {
if (null!=id && !"".equals(id)) {
entity = dictCodeService.getDictCode(id);
} else {
entity = new DictCode();
}
}
public DictCode getModel() {
return entity;
}
public Page<DictCode> getPage() {
return page;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public DictCode getEntity() {
return entity;
}
public void setEntity(DictCode entity) {
this.entity = entity;
}
public List<DictType> getAllDictTypes() {
return allDictTypes;
}
}
@Transactional(readOnly=false)
public void saveDictCode(DictCode authorities) {
this.dictCodeDAO.save(authorities);
}
@Transactional(readOnly=false)
public void updateDictCode(DictCode entity) throws HibernateException, SQLException {
Session session=this.dictCodeDAO.getSession();
session.clear();
session.update(entity);
}
@Transactional(readOnly=false)
public void deleteDictCode(String id) {
this.dictCodeDAO.delete(id);
}
}
因为我采用的sturts2.5+hibernate3.2所有的都支持JPA.所以都用的是JPA注释,没有其他servcie,action.dao,struts配置的xml文件.
后来
@Transactional(readOnly=false)
public void updateDictCode(DictCode entity) throws HibernateException, SQLException {
Session session=this.dictCodeDAO.getSession();
session.clear();
session.update(entity);
}
先对entity进行清空,然后在保存
预计原因.当我想改变某一个字典信息时,讲该字典信息和字典类别信息取出来,持久化了,想修改的时候无法修改.所以先clear()再存入.
在update前clear()一下.成功解决该问题
Lyyb2001