双向1-N关联
对于1-N关联,Hibernate推荐使用双向关联,而且不要让1的一端控制关联关系,而使用N端控制。双向的1-N关联与N-1关联完全相同,两端都需要增加对关联属性的访问,N的一端增加引用到关联实体的属性,1的一端增加集合属性,集合元素为关联实体。
无连接表的双向1-N关联
N端使用@ManyToOne来修饰代表关联实体的属性,1端使用OneToMany来修饰。由于不希望1端控制关联关系,所以需要为1端的OneToMany指定mappedBy属性来接触这一端的控制权。放弃了控制权,就没法使用JoinColumn或者@JoinTable修饰代表的关联实体的属性了。
@Entity @Table(name = "personb_inf") public class PersonB { @Id @Column(name = "person_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; private int age; @OneToMany(targetEntity = Address.class, mappedBy = "person") private Set<Address> address = new HashSet<>(); }
这个Person类中使用了OneToMany并且设定了mappedBy属性修饰Set集合,该集合用于记录关联的一系列Address实体。这个实体不控制关联关系。
@Entity @Table(name = "address_inf") public class Address { @Id @Column(name = "addrress_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private int addressId; private String addressDetail; @ManyToOne(targetEntity = Person.class) @JoinColumn(name = "personB_id", referencedColumnName = "person_id", nullable = false) private PersonB person; public Address() { } public Address(String addressDetail) { this.addressDetail = addressDetail; } }
Address端需要增加一个Person属性。哪一端不控制,哪一端就使用这个属性,表明Address与Person存在N-1的关系。
private static void createAndStorePersons() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); PersonB p=new PersonB(); p.setName("alvin"); p.setAge(23); session.save(p); Address a=new Address("beijing"); a.setPerson(p); session.persist(a); Address a1=new Address("shanghai"); a1.setPerson(p); session.persist(a1); tx.commit(); session.close(); }
mysql> select * from persone_inf;
+-----------+-----+-------+
| person_id | age | name |
+-----------+-----+-------+
| 1 | 23 | alvin |
+-----------+-----+-------+
mysql> select * from addresse_inf;
+-------------+---------------+-----------+
| addrress_id | addressDetail | person_id |
+-------------+---------------+-----------+
| 1 | beijing | 1 |
| 2 | shanghai | 1 |
+-------------+---------------+-----------+
Address中使用JoinColumn映射外键列,在address_inf中增加名为person_id的外键列,也就意味着address_inf作为从表。测试代码保存的p对象相当于向person_inf中插入一条。之后又保存了两个address对象,并建立person与address的关联关系。这里我们要注意最好先持久化Person对象,因为程序希望持久化address对象时,address的外键已经存在。先设定person与address的关系再保存address对象,否则address中的外键没有值。等到设置关联关系,还得再使用一次update语句更新address表中的外键值。不要通过person设置address,而是要通过address来设置person,因为person没有控制权。
有连接表的双线1-N关联
此时1端无需任何改变,只需要在N端使用@JoinTable指定连接表。address中代码如下
@OneToMany(targetEntity = PersonB.class) @JoinTable(name = "person_address", joinColumns = @JoinColumn(name = "addredd_id", referencedColumnName = "address_id", unique = true), inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "person_id")) private Set<Address> address = new HashSet<>();
person类的代码与不使用连接表完全相同。如果希望person也得到控制权,则需要在person中也适用JoinTable,指定同一张表。由于使用了连接表管理关联关系,无所谓主表从表。持久化顺序没有下影响。
双向N-N关联
要求两端都使用Set集合属性,两端都增加对集合属性的访问。这种方式只能通过连接表来实现。两边分别使用ManyToMany标注Set属性也都是用JoinTable指定连接表。
双向1-1关联
两端都奥增加引用相关实体的属性。
基于外键的双向1-1关联
两端都使用@OneToOne注解。基于外键时,外键可以存放在任意一端,存放外键的一端需要使用JoinColumn注解来映射外键,并且制定它的unique=true来标识这一段是1。本来平等的两个表,由于有一端增加了外键,因此就变成了从表。主表应该使用mappedBy解除控制权。
基于连接表的双线1-1关联
这种情况相当罕见。两端都要使用@JoinTable,也都要使用@OneToOne。双方的注解是对等的,双方的映射表是一样的,两者都有控制权。
本文出自 “指尖轻飞” 博客,谢绝转载!