如果Address类没有OID,那它就是组件类。由于Address类没有OID,因此不能通过EntityManager或Session来单独保存、更新、删除或加载一个Address对象。例如,以下每行代码都会抛出IllegalArgumentException异常:
entityManager.find(Address.class,Long.valueOf(1));
entityManager.persist(address);
entityManager.remove(address);
以上代码运行时抛出IllegalArgumentException异常,错误原因为“Unknown entity class: mypack.Address”。
为何称Address类是未知的实体类呢?这是因为Hibernate把持久化类的属性分为两种:值(Value)类型和实体(Entity)类型。
值类型和实体类型的最重要的区别是前者没有OID,不能被单独持久化,它的生命周期依赖于所属的持久化类的对象的生命周期,组件类型就是一种值类型;而实体类型有OID,可以被单独持久化。
假定Customer类有以下属性:
private String name;
private int age;
private Date birthday;
//Customer和Address类是组成关系
private Address homeAddress;
private Address comAddress;
//Customer和Company类是多对一关联关系
private Company currentCompany;
//Customer和Order类是一对多关联关系
private Set orders;
在以上属性中,name、age、birthday、homeAddress及comAddress都是值类型属性,而currentCompany是实体类型属性,orders集合中的Order对象也是实体类型属性。
当删除一个Customer持久化对象时,Hibernate会从数据库中删除所有值类型属性对应的数据,但是实体类型属性对应的数据有可能依然保留在数据库中,也有可能被删除,这取决于是否在设置了级联删除。假如对orders集合设置了级联删除,那么删除Customer对象时,也会删除orders集合中的所有Order对象。假如没有对currentCompany属性设置级联删除,那么删除一个Customer对象时,currentCompany 属性引用的Company对象依然存在。
Address类作为值类型没有OID,因此不能建立从其他持久化类到Address类的关联关系(注意关联是有方向性的)。假如在Customer类中按如下方式映射currentCompany属性和homeAddress属性:
@ManyToOne
@JoinColumn(name="COMPANY_ID")
Company currentCompany;
@OneToOne
Address homeAddress;
以上代码对currentCompany属性做了正确的映射,但对homeAddress属性的映射是不正确的。以上代码意味着在数据库中,CUSTOMERS表参照Address类所对应的表,而实际上Address类在数据库中根本没有对应的表。