Hibernate实战_笔记17(持久化实体类)(二)

2014-11-24 01:25:14 · 作者: · 浏览: 1
ategory"); if (null != childCategory.getParentCategory()) { childCategory.getParentCategory().getChildCategories().remove( childCategory); childCategory.setParentCategory(this); this.childCategories.add(childCategory); } } addChildCategory()方法不仅在处理Category对象时减少了代码行,而且加强了关联的基数性(cardinality)。它避免了漏掉两个必需动作中的其中一个时产生的错误。如果可能的话,应该始终对关联提供这种操作的分组。
由于想要addChildCategory()成为子类中唯一外部可见的存储器方法(mutator method)(可能还要加上removeChildCateogry()方法),你可以让setChildCategories()方法为私有,或者删除它,。
在Category和Item类之间存在着一种不同的关系:一个双向的多对多关联,如图3-4所示.
对于多对多的关联,两侧都用集合值属性实现。添加访问Item关系的新属性和方法到Category类:
public class Category {
	private String name;// 类型名称
	private Category parentCategory;// 父类型
	private Set
  
    childCategories = new HashSet
   
    ();// 子类型 private Set
    
      items = new HashSet
     
      ();// 商品列表 }
     
    
   
  
Item类的代码(多对多关联的另一侧)类似于Category类的代码。添加集合属性,标准的访问方法,以及简化关系管理的一种方法
public class Item implements Serializable {
	private static final long serialVersionUID = 2473606759362725264L;


	private String name;
	private String description;
	private BigDecimal initialPrice;
	private BigDecimal reservePrice;
	private Date startDate;
	private Date endDate;
	private ItemState state;
	private Date approvalDatetime;
	private Set
  
    categories = new HashSet
   
    (); public void addCategory(Category category) { if (null == category) throw new IllegalArgumentException("Null category"); category.getItems().add(this); categories.add(category); } }
   
  
addCategory()方法类似于Category类的addChildCategory()便利方法。它被客户端用来操作Item和Category之间的链接。为了增加可读性,后面的代码样例中将不显示便利方法了,并假设你会根据自己的偏好来添加它们。
给关联处理使用便利方法并不是改善领域模型实现的唯一途径。也可以把逻辑添加到你的访问方法中。
把逻辑添加到访问方法
我们喜欢使用JavaBean风格的访问方法的原因之一在于它们提供封装:一个属性的内部隐藏实现可以不做任何改变地变换为公共接口。
例如,如果 数据库把用户名称保存为单个NAME列,但是User类有firstname和lastname属性,你可以把下列持久化的name属性添加到这样类:
public class User implements Serializable {
	private static final long serialVersionUID = -7811634244303955773L;


	private String firstname;
	private String lastname;


	// ...
	public String getName() {
		return firstname + lastname;
	}


	public void setName(String name) {
		// StringTokenizer是一个用来分隔String的应用类
		StringTokenizer t = new StringTokenizer(name, " ");
		this.firstname = t.nextToken();
		this.lastname = t.nextToken();
	}
	// ...
}
稍后,你会明白Hibernate定制类型是处理多个这种情况的一种更好的方法。然而,有多种选择的话也自有好处。
访问方法也可以执行验证。例如,在下列例子中,setFirstName()方法验证大写的名称:
public class User implements Serializable {
	private static final long serialVersionUID = -7811634244303955773L;


	private String firstname;


	// ...
	public String getFirstname() {
		return firstname;
	}


	public void setFirstname(String firstname) throws InvalidNameException {
		if (!StringUtil.isCapitalizedName(firstname))
			throw new InvalidNameException(firstname);
		this.firstname = firstname;
	}
}
另一个要考虑的问题是脏检查。Hibernate自动侦测对象状态的改变,以便使更新过的状态与数据库同步。从获取方法返回一个不同的对象,通常比由Hibernate传递到设置方法的对象来得安全。Hibernate按值比较对象――不是按对象同一性――来确定一个属性的持久化状态是否需要被更新。例如,下列获取方法就不会导致不必要的SQL UPDATE(更新):
public String getFirstname() {
		return new String(firstname);
	}
还有个重要的例外:集合是按同一性比较的!对于一个被映射为持久化集合的属性,你应该从获取方法中返回与Hibernate传递到设置方法中完全相同的集合实例。如果没有,Hibernate将更新数据库,即使不需要更新,保存在内存中的状态每次也都会与数据库同步。
最后,必须知道访问方法中的异常如何处理,如果你在加载和存储实例时配置Hibernate来使用这些方法的话。如果抛出RuntimeException,当前的事务就被