----转载过来的。根据自己的理解修改了一下,便于以后阅读
默认情况下,JPA 持续性提供程序在映射多对多关联(或在单向的一对多关联中)的拥有方上的实体关联时使用一个连接表。连接表名称及其列名均在默认情况下指定,且 JPA 持续性提供程序假设:在关系的拥有方上的实体主表中,每个主键列有一个连接列。
通过表关联的方式来映射一对多或者多对多的关系时,要使用@JoinTable这个标记。该标记的定义如下所示。
@Target({METHOD, FIELD})
public @interface JoinTable {
String name() default "";
String catalog() default "";
String schema() default "";
JoinColumn[] joinColumns() default {};
JoinColumn[] inverseJoinColumns() default {};
UniqueConstraint[] uniqueConstraints default {};
}
在使用此@JoinTable标记时,需要注意以下几个问题。
l 该标记与@Table注释类似,用于标注用于关联的表。可以标注在方法或者属性上,属性catalog、schema和uniqueConstraint与@Table注释中的属性意义类似,请读者参阅@Table注释说明的部分。
l name属性为连接两个表的表名称。若不指定,则使用默认的表名称如下所示。
“表名1”+“_”+“表名2”。
例如以上的代码中,如果不指定name的名称,默认的保存关系的名称如下所示。
“customer_address”。
l joinColumns属性表示,在保存关系中的表中,所保存关联关系的外键的字段。并配合@JoinColumn标记使用。
例如以下的映射配置,表示字段customer_id为外键关联到customer表中的id字段。
joinColumns={
@JoinColumn(name="customer_id",referencedColumnName="id")
}
l inverseJoinColumns属性与joinColumns属性类似,它保存的是保存关系的另一个外键字段。
例如以下的映射配置,表示字段address_id为外键关联到address表中的id字段。
inverseJoinColumns={
@JoinColumn(name="address_id",referencedColumnName="id")
}
提示:@JoinTable不仅能够定义一对多的关联,也可以定义多对多表的关联
默认情况下,在实体关联中,JPA 持续性提供程序使用一个基于现有名称(如字段或属性名称)的数据库模式,以便它可以自动确定要使用的单个连接列(包含外键的列)。
在以下条件下使用 @JoinColumn
@JoinColumn 属性
属性 | 必需 | 说明 |
---|---|---|
|
可选 |
默认值:空 JPA 使用最少量 SQL 创建一个数据库表列。 如果需要使用更多指定选项创建列,请将 |
|
可选
|
默认值: 默认情况下,JPA 持续性提供程序假设它可以插入到所有表列中。 如果该列为只读,请将 |
|
可选
|
默认值:如果使用一个连接列,则 JPA 持续性提供程序假设外键列的名称是以下名称的连接:
如果实体中没有这样的引用关系属性或字段(请参阅 @JoinTable),则连接列名称格式化为以下名称的连接:实体名称 +“_”+ 被引用的主键列的名称。 这是外键列的名称。如果连接针对“一对一”或“多对一”实体关系,则该列位于源实体的表中。如果连接针对“多对多”实体关系,则该列位于连接表(请参阅 @JoinTable)中。 如果连接列名难于处理、是一个保留字、与预先存在的数据模型不兼容或作为数据库中的列名无效,请将 |
|
可选
|
默认值: 默认情况下,JPA 持续性提供程序假设允许所有列包含空值。 如果不允许该列包含空值,请将 |
|
可选
|
默认值:如果使用一个连接列,则 JPA 持续性提供程序假设在实体关系中,被引用的列名是被引用的主键列的名称。 如果在连接表(请参阅 @JoinTable)中使用,则被引用的键列位于拥有实体(如果连接是反向连接定义的一部分,则为反向实体)的实体表中。 要指定其他列名,请将 |
|
可选
|
默认值:JPA 持续性提供程序假设实体的所有持久字段存储到一个名称为实体类名称的数据库表中(请参阅 @Table)。 如果该列与辅助表关联(请参阅 @SecondaryTable),请将 |
|
可选
|
默认值: 默认情况下,JPA 持续性提供程序假设允许所有列包含重复值。 如果不允许该列包含重复值,请将 |
|
可选
|
默认值: 默认情况下,JPA 持续性提供程序假设它可以更新所有表列。 如果该列为只读,则将 |
下例显示了如何使用此批注使 JPA 将数据库表 Employee
列 ADDR_ID
用作连接列。
@Entity public class Employee implements Serializable { ... @ManyToOne @JoinColumn(name="ADDR_ID") public Address getAddress() { return address; } }
附录上当时写的一个student、course、score三者之间的一个映射关系:
说明如下:
Student和Course之间是多对多的关系,以Score作为中间表,连接他们两者之间的关系。由于联合组建使用麻烦,给Score表外加一个主键。Score对Student之间是多对一,Score对Course之间是多对一。
代码摘录:
Student实体类
package com.bjsxt.hibernate;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name="_student")
public class Student {
private int id;
private String name;
private Set courses = new HashSet();
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany(
targetEntity=com.bjsxt.hibernate.Course.class,
cascade={CascadeType.ALL}
)
//默认情况下,JPA 持续性提供程序在映射多对多关联(或在单向的一对多关联中
//)的拥有方上的实体关联时使用一个连接表
@JoinTable(//用于标注用于关联的表
//name="student_course"
//name属性为连接两个表的表名称。若不指定,则使用默认的表名称如下所示。
//“表名1”+“_”+“表名2”。
name="_score",//要连接的是score实体类对应的数据库表。保持与score实体类声明的数据库表名一致
//joinColumns ={@JoinColumn (name="student_id", referencedColumnName="id")},
//inverseJoinColumns={@JoinColumn (name="course_id" , referencedColumnName="id")}
//joinColumns属性表示,在保存关系中的表中,所保存关联关系的外键的字段
//如下表示:在保存关联关系的表_score表中,字段"student_id"为外键关联到student表中的id字段
joinColumns ={@JoinColumn(name="student_id",referencedColumnName="id")},
//保存的是保存关系的另一个外键字段。 例如以下的映射配置,
//表示字段address_id为外键关联到address表中的id字段。
inverseJoinColumns={@JoinColumn(name="course_id", referencedColumnName="id")}
/*
* 默认值:如果使用一个连接列,则 JPA 持续性提供程序假设在实体关系中,被引用的列名是被引用的主键列的名称。
* 如果在连接表(请参阅 @JoinTable)中使用,则被引用的键列位于拥有实体(如果连接是反向连接定义的一部分,则为反向实体)的实体表中。
*/
/*JoinColumn
*属性name:如果连接针对“一对一”或“多对一”实体关系,则该列位于源实体的表中。如果连接针对“多对多”实体关系,则该列位于连接表
*
*/
)
public Set getCourses() {
return courses;
}
public void setCourses(Set courses) {
this.courses = courses;
}
}
package com.bjsxt.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="_course")
public class Course {
private int id;
private String name;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Score实体类
package com.bjsxt.hibernate;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="_score")
public class Score {
private int id;
private double score;
private Student student;
private Course course;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@ManyToOne(cascade = {CascadeType.ALL})
@JoinColumn(name="student_id")
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
@ManyToOne(cascade = {CascadeType.ALL})
@JoinColumn(name="course_id")
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
}
生成的数据库表之间的模式如下:
注意:上面的生成并不符合我的原意:_score表的主键并不是我设置的。我设置的是id为主键。在看尚学堂马士兵说的这一节的视频中说,这个是Hibernate的一个小Bugger。具体是否如他所说,暂时在探索中。