hibernate的关联映射
无连接表的N-1关联
使用@JoinColumn来修饰代表关联实体的属性。映射底层的外键列。
person->Address(n-1)
@Entity
@Table(name="person_inf")
public class Person
{
....
@ManyToOne(targetEntity=Address.class)
@JoinColumn(name="address_id" , nullable=false)
@Cascade(CascadeType.ALL)
private Address address;
有连接表的N-1关联
使用@JoinTable映射底层连接表的 信息
@ManyToOne(targetEntity=Address.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="person_id"
, referencedColumnName="person_id", unique=true),
inverseJoinColumns=@JoinColumn(name="address_id"
, referencedColumnName="address_id")
)
private Address address;
单向1-1
使用@OnetoOne and @JoinColumn并指定unique=true
@OneToOne(targetEntity=Address.class)
@JoinColumn(name="address_id"
, referencedColumnName="address_id" , unique=true)
private Address address;
有连接表的单向1-1
这种情况很少见,但是hibernate还是提供了支持。只要在相应的@inverseJoinColumn属性映射的外键列增加unique=true即可
@OneToOne(targetEntity=Address.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="person_id"
, referencedColumnName="person_id" , unique=true),
inverseJoinColumns=@JoinColumn(name="address_id"
, referencedColumnName="address_id", unique=true)
)
private Address address;
无连接表的单向1-N关联
在1的一端使用JoinColumn修饰集合Set属性,映射外键列即可。
@OneToMany(targetEntity=Address.class)
@JoinColumn(name="person_id" , referencedColumnName="person_id")
private Set<Address> addresses
= new HashSet<>();
有连接表的单向1-N
@OneToMany(targetEntity=Address.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="person_id"
, referencedColumnName="person_id"),
inverseJoinColumns=@JoinColumn(name="address_id"
, referencedColumnName="address_id", unique=true)
)
private Set<Address> addresses
= new HashSet<>();
单向的N-N
使用@ManyToMany @JoinTable来映射连接表。并且去掉@inverseJoinColumns属性所指定的@JoinColumn中的unique=true
@ManyToMany(targetEntity=Address.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="person_id"
, referencedColumnName="person_id"),
inverseJoinColumns=@JoinColumn(name="address_id"
, referencedColumnName="address_id")
)
private Set<Address> addresses
= new HashSet<>();
双向1-N关联
推荐使用双向1-N关联。并且让N的一端控制关联关系。
无连接表的双向1-n关联。
N的一端:@OneToMany(mappedBy=”“)
1的一端:@ManyToOne @JoinColumn来映射外键列。
@Entity
@Table(name="person_inf")
public class Person
{
....
@OneToMany(targetEntity=Address.class
, mappedBy="person")
private Set<Address> addresses
= new HashSet<>();
}
@Entity
@Table(name="address_inf")
public class Address
{
...
@ManyToOne(targetEntity=Person.class)
@JoinColumn(name="person_id" , referencedColumnName="person_id"
, nullable=false)
private Person person;
}
有连接表的双向1-N关联
1的一端无需改变
N的一端@JoinTable指定连接表
@OneToMany(targetEntity=Address.class
, mappedBy="person")
private Set<Address> addresses
= new HashSet<>();
@ManyToOne(targetEntity=Person.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="address_id"
, referencedColumnName="address_id", unique=true),
inverseJoinColumns=@JoinColumn(name="person_id"
, referencedColumnName="person_id")
)
private Person person;
}
双向N-N关联
双方都是用@ManyToMany @JoinTable属性
@ManyToMany(targetEntity=Person.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="address_id"
inverseJoinColumns=@JoinColumn(name="person_id"
, referencedColumnName="person_id")
)
private Set<Person> persons
= new HashSet<>();
@ManyToMany(targetEntity=Address.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="person_id"
inverseJoinColumns=@JoinColumn(name="address_id"
, referencedColumnName="address_id")
)
private Set<Address> addresses
= new HashSet<>();
双向1-1关联
- 基于外键
@OneToOne(targetEntity=Address.class , mappedBy="person")
private Address address;
@OneToOne(targetEntity=Person.class)
@JoinColumn(name="person_id" , referencedColumnName="person_id"
, unique=true)
private Person person;
- 有连接表
不推荐使用
@OneToOne(targetEntity=Address.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="person_id"
, referencedColumnName="person_id" , unique=true),
inverseJoinColumns=@JoinColumn(name="address_id"
, referencedColumnName="address_id", unique=true)
)
private Address address;
@OneToOne(targetEntity=Person.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="address_id"
, referencedColumnName="address_id", unique=true),
inverseJoinColumns=@JoinColumn(name="person_id"
, referencedColumnName="person_id" , unique=true)
)
private Person person;
组件属性包含的关联实体
PersonL里面包含组件Address,Address跟School是1-N的关系。
@Entity
@Table(name="person_inf")
public class Person
{
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private Address address;
}
@Embeddable
public class Address
{
@Column(name="address_detail")
private String addressDetail;
@Parent
private Person person;
@OneToMany(targetEntity=School.class)
@JoinColumn(name="address_id", referencedColumnName="person_id")
private Set<School> schools
= new HashSet<>();
}
@Entity
@Table(name="school_inf")
public class School
{
@Id @Column(name="school_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
基于复合主键的关联关系
不推荐使用。总是建议使用没有物理意义的逻辑主键。
对于1-N的双向关联,1的一端将两个属性结合起来作为复合主键。N的一端仍然使用Integer类型的普通主键。
person(1)->address(n)
@Id
private String first;
@Id
private String last;
@OneToMany(targetEntity=Address.class, mappedBy="person"
, cascade=CascadeType.ALL)
private Set<Address> addresses
= new HashSet<>();
public class Address{
@ManyToOne(targetEntity=Person.class)
@JoinColumns({
@JoinColumn(name="person_first"
, referencedColumnName="first" , nullable=false),
@JoinColumn(name="person_last"
, referencedColumnName="last" , nullable=false)
})
private Person person;
}
hibernate的继承映射
例子:现在有四个类:Person,Employee,Manager,Customer.四个持久化类,其中person还有一个Address组件。
person派生出了employee和customer,employee又派生出了manager.
1. 整个类层次对应一个表(默认)
所有类的属性都放在一个表中。并使用一个列来辨别一条记录到底是属于哪个类的实例。俗称辨别者列(discriminator)。
@Entity
@DiscriminatorColumn(name="person_type" ,
discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("普通人")
@Table(name="person_inf")
public class Person
{
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
private char gender;
@AttributeOverrides({
@AttributeOverride(name="detail",
column=@Column(name="address_detail")),
@AttributeOverride(name="zip",
column=@Column(name="address_zip")),
@AttributeOverride(name="country",
column=@Column(name="address_country"))
})
private Address address;
}
@Entity
@DiscriminatorValue("员工")
@Table(name="employee_inf")
public class Employee extends Person
{
private String title;
private double salary;
@OneToMany(cascade=CascadeType.ALL
, mappedBy="employee" , targetEntity=Customer.class)
private Set<Customer> customers
= new HashSet<Customer>();
@ManyToOne(cascade=CascadeType.ALL
,targetEntity=Manager.class)
@JoinColumn(name="manager_id", nullable=true)
private Manager manager;
}
@Entity
@DiscriminatorValue("经理")
@Table(name="manager_inf")
public class Manager extends Employee
{
private String department;
@OneToMany(cascade=CascadeType.ALL
, mappedBy="manager" , targetEntity=Employee.class)
private Set<Employee> employees
= new HashSet<Employee>();
2.连接子类的映射策略
父类保存在父类表中,子类由父类表和子类表共同保存。
在继承树的根类中,使用@Inheritance指定映射策略。
@InheritanceType.SINGLE_TABLE:整个类层次一个表
@InheritanceType.JOINED:连接子类
@InheritanceType.TABLE_PER_CLASS:每个类对应一个表。
这种策略无需指定辨别者列。
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name="person_inf")
public class Person
{
// ±êʶÊôÐÔ
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
}
@Entity
@Table(name="employee_inf")
public class Employee extends Person
{
private String title;
private double salary;
@OneToMany(cascade=CascadeType.ALL
, mappedBy="employee" , targetEntity=Customer.class)
private Set<Customer> customers
= new HashSet<>();
@ManyToOne(cascade=CascadeType.ALL
,targetEntity=Manager.class)
@JoinColumn(name="manager_id", nullable=true)
private Manager manager;
}
3.每个类一个表
不能使用@GenerationType.IDENTIFIED,@GenerationType.AUTO指定主键生成策略。
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@Table(name="person_inf")
public class Person
{
@Id @Column(name="person_id")
@GenericGenerator(name="person_hilo" , strategy="hilo")
@GeneratedValue(generator="person_hilo")
private Integer id;
}
@Entity
@Table(name="employee_inf")
public class Employee extends Person
{
private String title;
private double salary;
@OneToMany(cascade=CascadeType.ALL
, mappedBy="employee" , targetEntity=Customer.class)
private Set<Customer> customers
= new HashSet<>();