}
至此,我们已经展示了很多跟关联有关的声明定义以及属性细节. 下面我们将深入介绍@JoinTable注解,该注解定义了联接表的表名, 联接列数组(注解中定义数组的格式为{ A, B, C }), 以及inverse联接列数组. 后者是关联表中关联到Employee主键的列(the "other side").
正如前面所示,被关联端不必也不能描述物理映射: 只需要一个简单的mappedBy参数,该参数包含了主体端的属性名,这样就绑定双方的关系.
2.2.5.3.3.2. 默认值
和其他许多注解一样,在多对多关联中很多值是自动生成. 当双向多对多关联中没有定义任何物理映射时,Hibernate根据以下规则生成相应的值. 关联表名:主表表名+_下划线+从表表名, 关联到主表的外键名:主表名+_下划线+主表中的主键列名. 关联到从表的外键名:主表中用于关联的属性名+_下划线+从表的主键列名. 以上规则对于双向一对多关联同样有效.
@Entity
public class Store {
@ManyToMany(cascade = CascadeType.PERSIST)
public Set
...
}
}
@Entity
public class City {
... //no bidirectional relationship
}
上面这个例子中,Store_Table作为联接表. Store_id列是联接到Store表的外键. 而implantedIn_id列则联接到City表.
当双向多对多关联中没有定义任何物理映射时, Hibernate根据以下规则生成相应的值 关联表名: :主表表名+_下划线+从表表名, 关联到主表的外键名:从表用于关联的属性名+_下划线+主表中的主键列名. 关联到从表的外键名:主表用于关联的属性名+_下划线+从表的主键列名. 以上规则对于双向一对多关联同样有效.
@Entity
public class Store {
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
public Set
...
}
}
@Entity
public class Customer {
@ManyToMany(mappedBy="customers")
public Set
...
}
}
在上面这个例子中,Store_Customer作为联接表. stores_id列是联接到Store表的外键, 而customers_id列联接到City表.
2.2.5.4. 用cascading实现传播性持久化(Transitive persistence)
也许你已经注意到了cascade属性接受的值为CascadeType数组. 在EJB3中的cascade的概念和Hibernate中的传播性持久化以及cascade操作非常类似, 但是在语义上有细微的区别,支持的cascade类型也有点区别:
? CascadeType.PERSIST: 如果一个实体是受管状态, 或者当persist()函数被调用时, 触发级联创建(create)操作
? CascadeType.MERGE: 如果一个实体是受管状态, 或者当merge()函数被调用时, 触发级联合并(merge)操作
? CascadeType.REMOVE: 当delete()函数被调用时, 触发级联删除(remove)操作
? CascadeType.REFRESH: 当refresh()函数被调用时, 触发级联更新(refresh)操作
? CascadeType.ALL: 以上全部
关于cascading, create/merge的语义请参考EJB3规范的6.3章节.
2.2.5.5. 关联关系获取
通过Hibernate你可以获得直接或者延迟获取关联实体的功能. fetch参数可以设置为FetchType.LAZY 或者 FetchType.EAGER. EAGER通过outer join select直接获取关联的对象, 而LAZY(默认值)在第一次访问关联对象的时候才会触发相应的select操作. EJBQL提供了fetch关键字,该关键字可以在进行特殊查询的时候覆盖默认值. 这对于提高性能来说非常有效,应该根据实际的用例来判断是否选择fetch关键字.
2.2.6. 映射复合主键与外键
组合主键使用一个可嵌入的类作为主键表示,因此你需要使用@Id 和@Embeddable两个注解. 还有一种方式是使用@EmbeddedId注解.注意所依赖的类必须实现 serializable以及实现equals()/hashCode()方法. 你也可以如Mapping identifier properties一章中描述的办法使用@IdClass注解.
@Entity
public class RegionalArticle implements Serializable {
@Id
public RegionalArticlePk getPk() { ... }
}
@Embeddable
public class RegionalArticlePk implements Serializable { ... }
或者
@Entity
public class RegionalArticle implements Serializable {
@EmbeddedId
public RegionalArticlePk getPk() { ... }
}
public class RegionalArticlePk implements Serializable { ... }
@Embeddable 注解默认继承了其所属实体的访问类型, 除非显式使用了Hibernate的@AccessType注解(这个注解不是EJB3标准的一部分). 而@JoinColumns,即@JoinColumn数组, 定义了关联的组合外键(如果不使用缺省值的话). 显式指明referencedColumnNames是一个好的实践方式, 否则,Hibernate认为你使用的列顺序和主键声明的顺序一致.
@Entity
public class Parent implements Serializable {
@Id
public ParentPk id;
public int age;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumns ({
@JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
@JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
@JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
})
public Set
...
}
@Entity
public class Child implements Serializable {
@Id @GeneratedValue
public Integer id;
@ManyToOne
@JoinColumns ({
@JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
@JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
@JoinColumn(name="parentFirstName", referencedColumnName = "firstName")

