级联操作
程序员文章站
2022-05-01 23:05:42
...
需求描述:
系统更新日志功能,需要在一个页面里展示主表信息+对所所有子表信息。
原始结构:
问题:
1- 级联提交需要的标记。
ChangeLog:
cascade:
级联操作的类型,{[CascadeType.PERSIST(级联新建)][,CascadeType.REMOVE(级联删除)][,CascadeType.REFRESH(级 联刷新)][,CascadeType.MERGE(级联更新)]},或者使用CascadeType.ALL,表示选择全部。
2- 级联提交后子表无主表id
完成1中设置后发现可以级联提交,但提交后changeLogItem的changeLog_id为空。
这是由于使用@OneToMany(mappedBy="changeLog")标记后系统将不再负责两个对象的关联问题,所以需要通过新建方法,给item自加设置changeLog属性的值。
此时可以完成带子项的添加操作,但添加完成后需要展示详细内容时出现“net.sf.json.JSONException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.bnm.system.domain.SysMenu.childs, no session or session was closed ”的错误。
3- 在加载主表信息时把子表信息同时加载出来,所以需要添加(或修改FetchType.LAZY)fetch=FetchType.EAGER强抽即时加载子项。
fetch: FetchType.LAZY 延迟加载;FetchType.EAGER 即时加载。
完成后发现可以正常显示,并同时添加多条子项。
但回到changeLog列表发现,出现多条相同数据,changeLog的重复个数跟其子项数量是一致的。
4- 提交后主表列表出现多条相同记录。这是由于使用FetchType.EAGER加载子项时系统默认使用了left join的查询方式。另外,在本例中列表页面不需要显示子项信息,故将FetchType.EAGER改回FetchType.LAZY,在用户需要展开详情时再通过一次查询完成加载所有内容。
至此已可以正常显示列表和详情。
5- 无法新增的问题。新增时又出现“org.hibernate.AssertionFailure: null identifier”的问题。
故需要添加一个非空判断
ok,至此主从表的关联操作已基本完成。
6- 无法单独删除子项的问题。
问题可能是特殊的,在详细信息中删除一个子项时我使用了remove(item)方法,完成后看似确实生效了,但当重新加载对应的数据时,刚才被删掉的子项又显示了出来。
修改方式是添加@Cascade (org.hibernate.annotations.CascadeType.DELETE_ORPHAN)标记
终于完成。
------
关于第6个问题参考文档,内有详细说明:
http://blog.csdn.net/zhh521125/archive/2010/10/20/5954137.aspx
系统更新日志功能,需要在一个页面里展示主表信息+对所所有子表信息。
原始结构:
/**
*
*/
package common.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* 系统更新说明
*
* @author sunhl
*
*/
@Entity
@Table(name="T_CHANGELOG")
@DomainModel(name="系统更新")
public class ChangeLog extends AbstractModel implements Serializable {
private static final long serialVersionUID = 1L;
private String title; // 标题
private List<ChangeLogItem> items = new ArrayList<ChangeLogItem>(); //详细内容
//gets and sets
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@OneToMany
public List<ChangeLogItem> getItems() {
return items;
}
public void setItems(List<ChangeLogItem> items) {
this.items = items;
}
public void addItem(ChangeLogItem item){
this.getItems().add(item);
item.setChangeLog(this);
}
}
------------
/**
*
*/
package common.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* 系统更新详细内容
*
* @author sunhl
*
*/
@Entity
@Table(name="AI_CHANGELOG_ITEM")
@DomainModel(name="系统更新详情")
public class ChangeLogItem extends AbstractModel implements Serializable {
private static final long serialVersionUID = 1L;
private ChangeLog changeLog; //所属更新说明
private String content; //内容
//--
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="changeLog_id")
public ChangeLog getChangeLog() {
return changeLog;
}
public void setChangeLog(ChangeLog changeLog) {
this.changeLog = changeLog;
}
@Column(length=2000)
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
问题:
1- 级联提交需要的标记。
ChangeLog:
@OneToMany(cascade = CascadeType.ALL,mappedBy="changeLog")
public List<ChangeLogItem> getItems() {
return items;
}
cascade:
级联操作的类型,{[CascadeType.PERSIST(级联新建)][,CascadeType.REMOVE(级联删除)][,CascadeType.REFRESH(级 联刷新)][,CascadeType.MERGE(级联更新)]},或者使用CascadeType.ALL,表示选择全部。
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="changeLog_id") //外键
public ChangeLog getChangeLog() {
return changeLog;
}
2- 级联提交后子表无主表id
完成1中设置后发现可以级联提交,但提交后changeLogItem的changeLog_id为空。
这是由于使用@OneToMany(mappedBy="changeLog")标记后系统将不再负责两个对象的关联问题,所以需要通过新建方法,给item自加设置changeLog属性的值。
//给新添加的item设置changeLog的值。
public void addItem(ChangeLogItem item){
this.getItems().add(item);
item.setChangeLog(this);
}
此时可以完成带子项的添加操作,但添加完成后需要展示详细内容时出现“net.sf.json.JSONException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.bnm.system.domain.SysMenu.childs, no session or session was closed ”的错误。
3- 在加载主表信息时把子表信息同时加载出来,所以需要添加(或修改FetchType.LAZY)fetch=FetchType.EAGER强抽即时加载子项。
@OneToMany(fetch=FetchType.EAGER,cascade = CascadeType.ALL,mappedBy="changeLog")
public List<ChangeLogItem> getItems() {
return items;
}
fetch: FetchType.LAZY 延迟加载;FetchType.EAGER 即时加载。
完成后发现可以正常显示,并同时添加多条子项。
但回到changeLog列表发现,出现多条相同数据,changeLog的重复个数跟其子项数量是一致的。
4- 提交后主表列表出现多条相同记录。这是由于使用FetchType.EAGER加载子项时系统默认使用了left join的查询方式。另外,在本例中列表页面不需要显示子项信息,故将FetchType.EAGER改回FetchType.LAZY,在用户需要展开详情时再通过一次查询完成加载所有内容。
@OneToMany(fetch=FetchType.LAZY,cascade = CascadeType.ALL,mappedBy="changeLog")
public List<ChangeLogItem> getItems() {
return items;
}
-------------------------------------------------
//在action中添加,视具体操作而定。
public void onEdit(){
changeLogService.refash(changeLog)。
}
至此已可以正常显示列表和详情。
5- 无法新增的问题。新增时又出现“org.hibernate.AssertionFailure: null identifier”的问题。
故需要添加一个非空判断
public void onEdit(){
if(changeLog.getId()!=null){
changeLogService.refash(changeLog)
}
}
ok,至此主从表的关联操作已基本完成。
6- 无法单独删除子项的问题。
问题可能是特殊的,在详细信息中删除一个子项时我使用了remove(item)方法,完成后看似确实生效了,但当重新加载对应的数据时,刚才被删掉的子项又显示了出来。
修改方式是添加@Cascade (org.hibernate.annotations.CascadeType.DELETE_ORPHAN)标记
//注:新添加的CascadeType.DELETE_ORPHAN是org.hibernate.annotations的标记。
// 而CascadeType.ALL是javax.persistence.CascadeType的
@OneToMany(fetch=FetchType.LAZY,cascade = CascadeType.ALL,mappedBy="changeLog")
@Cascade (org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
public List<ChangeLogItem> getItems() {
return items;
}
终于完成。
------
关于第6个问题参考文档,内有详细说明:
http://blog.csdn.net/zhh521125/archive/2010/10/20/5954137.aspx
上一篇: Spring Boot Thymeleaf非严格校验
下一篇: 智能合约可能出现的安全问题(三)