`
sunnyhl
  • 浏览: 78985 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多
需求描述:
  系统更新日志功能,需要在一个页面里展示主表信息+对所所有子表信息。

原始结构:
/**
 * 
 */
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
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics