public class User implements Serializable { private static final long serialVersionUID = -7811634244303955773L; private String username; private Address address; public User() { super(); } public User(String username, Address address) { super(); this.username = username; this.address = address; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } // 计算价格 public MonetaryAmount calcShippingCosts(Address fromLocation) { return null; } }Hibernate不要求持久化类实现Serializable(可序列化)。然而,当对象被存储在一个HttpSession中,或者用RMI按值传递时,就需要序列化。类可以是抽象的,必要时,可以扩展非持久化的类。
public class Category { private String name;// 类型名称 private Category parentCategory;// 父类型 private Set<Category> childCategories = new HashSet<Category>();// 子类型 public Category() { super(); } public Category(String name, Category parentCategory, Set<Category> childCategories) { super(); this.name = name; this.parentCategory = parentCategory; this.childCategories = childCategories; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Category getParentCategory() { return parentCategory; } public void setParentCategory(Category parentCategory) { this.parentCategory = parentCategory; } public Set<Category> getChildCategories() { return childCategories; } public void setChildCategories(Set<Category> childCategories) { this.childCategories = childCategories; } }管理两个Category实例之间的链接,比在数据库字段中设置外键值更难。依据我们的经验,开发人员经常不知道从一个包含双向引用的网络对象模型中所产生的这种复杂性。我们将一步一步地探讨这个问题。
Category aParent = new Category(); Category aChild = new Category(); aChild.setParentCategory(aParent); aParent.getChildCategories().add(aChild);说明:Hibernate中的托管关系——Hibernate不管理持久化关联。如果你要操作一个关联,必须编写与没有Hibernate时要编写完全相同的代码。如果关联是双向的,则关系的两侧都必须考虑。编程模型(如EJB2.1实体bean)通过引入容器托管的关系扰乱了这个行为——如果一侧被应用程序修改,容器就会自动改变关系的另一侧。这就是为什么使用EJB2.1实体bean的代码不能在容器之外被重用的原因之一。EJB3.0关联是透明的,就像在Hibernate中一样。如果你不理解Hibernate中关联的这种行为,就问问你自己:“没有Hibernate时我会怎么做?”Hibernate不会改变一般的Java语义。
public void addChildCategory(Category childCategory) { if (null == childCategory) throw new IllegalArgumentException("Null child category"); if (null != childCategory.getParentCategory()) { childCategory.getParentCategory().getChildCategories().remove( childCategory); childCategory.setParentCategory(this); this.childCategories.add(childCategory); } }addChildCategory()方法不仅在处理Category对象时减少了代码行,而且加强了关联的基数性(cardinality)。它避免了漏掉两个必需动作中的其中一个时产生的错误。如果可能的话,应该始终对关联提供这种操作的分组。
public class Category { private String name;// 类型名称 private Category parentCategory;// 父类型 private Set<Category> childCategories = new HashSet<Category>();// 子类型 private Set<Item> items = new HashSet<Item>();// 商品列表 }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<Category> categories = new HashSet<Category>(); 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之间的链接。为了增加可读性,后面的代码样例中将不显示便利方法了,并假设你会根据自己的偏好来添加它们。
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定制类型是处理多个这种情况的一种更好的方法。然而,有多种选择的话也自有好处。
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将更新数据库,即使不需要更新,保存在内存中的状态每次也都会与数据库同步。
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.jbit.entity"> <class name="Category" table="TBL_CATEGORY"> <id name="id" column="CATEGORY_ID"> <generator class="native" /> </id> <property name="NAME" column="NAME" type="string" /> </class> </hibernate-mapping>在这个例子中有意省略了集合和关联映射。关联尤其是集合映射更加复杂,因此后续将再回到这个话题。
Hibernate实战_笔记17,布布扣,bubuko.com
原文:http://blog.csdn.net/com185272358/article/details/21117445