级联操作

需求描述:
系统更新日志功能,需要在一个页面里展示主表信息+对所所有子表信息。

原始结构:

/**
*
*/
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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值