Hibernate的关联映射(7)-双向1-1关联

忘是亡心i 2022-07-21 11:19 217阅读 0赞

双向1-1关联

双向1-1关联需要修改两端的持久化代码,让两个持久化类都增加引用关联实体的属性,并为该属性提供setter和getter方法;

-————————————————————————————————————————————————————————————————————————————————————-

1>基于外键的双向1-1关联1

对于双向1-1关联而言,两端都需要使用@OneToOne注解进行映射;

对于基于外键的双向1-1关联,外键可以存放在任意一端,存放外键的一端,需要增加@joinColumn注解来映射外键列,与前面介绍相同的是,还应该为@JoinColumn注解增加uniique=true属性来表示该实体实际上是1的一端;

对于1-1的关联关系,两个实体原本处于平等状态,但当选择任意一端来增加外键后,(增加@JoinColumn注解的实体端),该表即变成从表,而另一个表则成为主表;

对于双向1-1关联的主表对应的实体,也不应该控制关联关系,(否则会导致生成额外的update语句,从而引起性能下降),因此主表对应的实体中使用@OneToOne注解时,应该增加@mappedBy属性,该属性用于表明该实体不管理关联关系,这一端对应的数据表将作为主表使用,不能使用@JoinColumn映射外键列;

下面是双向1-1关联的主表一端,使用@OneToOne时增加了mappedBy属性,没有使用@JoinColumn注解修饰代表关联实体的属性:

  1. <span style="font-size:18px;">package com.anlw.entity;
  2. import javax.persistence.Column;
  3. import javax.persistence.Entity;
  4. import javax.persistence.GeneratedValue;
  5. import javax.persistence.GenerationType;
  6. import javax.persistence.Id;
  7. import javax.persistence.OneToOne;
  8. import javax.persistence.Table;
  9. @Entity
  10. @Table(name = "person_inf")
  11. public class Person {
  12. // 标识属性
  13. @Id
  14. @Column(name = "person_id12")
  15. @GeneratedValue(strategy = GenerationType.IDENTITY)
  16. private Integer id;
  17. private String name;
  18. private int age;
  19. // 定义该Person实体所有关联的Address实体
  20. @OneToOne(targetEntity = Address.class,mappedBy="person")
  21. private Address address;
  22. public Integer getId() {
  23. return id;
  24. }
  25. public void setId(Integer id) {
  26. this.id = id;
  27. }
  28. public String getName() {
  29. return name;
  30. }
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34. public int getAge() {
  35. return age;
  36. }
  37. public void setAge(int age) {
  38. this.age = age;
  39. }
  40. public Address getAddress() {
  41. return address;
  42. }
  43. public void setAddress(Address address) {
  44. this.address = address;
  45. }
  46. }</span>

上面注解@OneToOne映射指定了mappedBy属性,表明该Perosn实体不再控制关联关系;

下面是双向1-1关联从表的一端,使用@OneToOne时不指定mappedBy属性,需要使用@JoinColumn注解修饰代表关联实体的属性,用于显式定义外键列;

  1. <span style="font-size:18px;">package com.anlw.entity;
  2. import javax.persistence.Column;
  3. import javax.persistence.Entity;
  4. import javax.persistence.GeneratedValue;
  5. import javax.persistence.GenerationType;
  6. import javax.persistence.Id;
  7. import javax.persistence.JoinColumn;
  8. import javax.persistence.OneToOne;
  9. import javax.persistence.Table;
  10. @Entity
  11. @Table(name = "address_inf")
  12. public class Address {
  13. // 标识属性
  14. @Id
  15. @Column(name = "address_id")
  16. @GeneratedValue(strategy = GenerationType.IDENTITY)
  17. private int addressId;
  18. // 定义地址详细的成员变量
  19. private String addressDetail;
  20. // 定义该Address实体关联的Person实体
  21. @OneToOne(targetEntity = Person.class)
  22. // 用于映射person_id外键列,参照person_inf表的person_id列
  23. // 指定了unique=true表明是1-1关联
  24. @JoinColumn(name = "person_id", referencedColumnName = "person_id12", unique = true)
  25. private Person person;
  26. public int getAddressId() {
  27. return addressId;
  28. }
  29. public void setAddressId(int addressId) {
  30. this.addressId = addressId;
  31. }
  32. public String getAddressDetail() {
  33. return addressDetail;
  34. }
  35. public void setAddressDetail(String addressDetail) {
  36. this.addressDetail = addressDetail;
  37. }
  38. public Person getPerson() {
  39. return person;
  40. }
  41. public void setPerson(Person person) {
  42. this.person = person;
  43. }
  44. }
  45. </span>

上面的@JoinColumn注解显式的映射了底层的外键列,并指定unique=true,这代表了1-1关联;

上面的映射策略可以互换,即让Person端存放外键,使用@JoinColumn注解映射关联属性,但Address端则使用@OneToOne时增加mappedBy属性,但不要两端都使用相同的注解进行映射;

-————————————————————————————————————————————————————————————————————————————————————-

2>有连接表的双向1-1关联

采用连接表的双向1-1关联是相当罕见的情形,映射相当复杂,数据模型繁琐,通常不推荐使用这种策略;

有连接表的双向1-1关联需要在两端分别使用@OneToOne修饰代表关联实体的属性,并在两端都使用@JoinTable显式的映射连接表,在映射连接表时,两端指定的连接表的表名应该相同,而且两端使用@JoinTable时指定的外键列的列名也是相互对应的;

需要说明的是,如果程序希望某一端放弃控制关联关系,则可在这一端的@OneToOne注解中指定mappedBy属性,这一端就无须也不能使用@JoinTable映射连接表了,由于此时是1-1关联,因此使用@JoinTable注解时指定的@JoinColumn都需要增加unique=true;

下面的示例让Person实体类与Address实体类保留双向1-1关联关系,而且双方都能控制关联关系,因此程序需要在两端分别使用@ObeToOne,@JoinTable映射连接表;

下面是双向1-1关联的Person实体类的代码,程序使用了@JoinTable和@OneToOne修饰代表关联实体的属性:

  1. <span style="font-size:18px;">package com.anlw.entity;
  2. import javax.persistence.Column;
  3. import javax.persistence.Entity;
  4. import javax.persistence.GeneratedValue;
  5. import javax.persistence.GenerationType;
  6. import javax.persistence.Id;
  7. import javax.persistence.JoinColumn;
  8. import javax.persistence.JoinTable;
  9. import javax.persistence.OneToOne;
  10. import javax.persistence.Table;
  11. @Entity
  12. @Table(name = "person_inf")
  13. public class Person {
  14. // 标识属性
  15. @Id
  16. @Column(name = "person_id12")
  17. @GeneratedValue(strategy = GenerationType.IDENTITY)
  18. private Integer id;
  19. private String name;
  20. private int age;
  21. // 定义该Person实体所有关联的Address实体
  22. @OneToOne(targetEntity = Address.class)
  23. //映射底层连接表,表明为p_a
  24. @JoinTable(name="p_a",
  25. //映射连接表的外键列,增加unique=true表明是1-1关联
  26. joinColumns=@JoinColumn(name="person_id"
  27. ,referencedColumnName="person_id12",unique=true),
  28. //映射连接表的外键列,增加unique=true表明是1-1关联
  29. inverseJoinColumns=@JoinColumn(name="address_id"
  30. ,referencedColumnName="address_id",unique=true))
  31. private Address address;
  32. public Integer getId() {
  33. return id;
  34. }
  35. public void setId(Integer id) {
  36. this.id = id;
  37. }
  38. public String getName() {
  39. return name;
  40. }
  41. public void setName(String name) {
  42. this.name = name;
  43. }
  44. public int getAge() {
  45. return age;
  46. }
  47. public void setAge(int age) {
  48. this.age = age;
  49. }
  50. public Address getAddress() {
  51. return address;
  52. }
  53. public void setAddress(Address address) {
  54. this.address = address;
  55. }
  56. }</span>

下面是双向1-1关联的Address实体类代码,程序通常使用@JoinTable和@OneToOne修饰代表关联实体的属性:

  1. <span style="font-size:18px;">package com.anlw.entity;
  2. import javax.persistence.Column;
  3. import javax.persistence.Entity;
  4. import javax.persistence.GeneratedValue;
  5. import javax.persistence.GenerationType;
  6. import javax.persistence.Id;
  7. import javax.persistence.JoinColumn;
  8. import javax.persistence.JoinTable;
  9. import javax.persistence.OneToOne;
  10. import javax.persistence.Table;
  11. @Entity
  12. @Table(name = "address_inf")
  13. public class Address {
  14. // 标识属性
  15. @Id
  16. @Column(name = "address_id")
  17. @GeneratedValue(strategy = GenerationType.IDENTITY)
  18. private int addressId;
  19. // 定义地址详细的成员变量
  20. private String addressDetail;
  21. // 定义该Address实体关联的Person实体
  22. @OneToOne(targetEntity = Person.class)
  23. // 映射底层连接表,表明为p_a
  24. @JoinTable(name = "p_a",
  25. // 映射连接表的外键列,增加unique=true表明是1-1关联
  26. joinColumns = @JoinColumn(name = "address_id", referencedColumnName = "address_id", unique = true),
  27. // 映射连接表的外键列,增加unique=true表明是1-1关联
  28. inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "person_id12", unique = true))
  29. private Person person;
  30. public Address(){}
  31. public int getAddressId() {
  32. return addressId;
  33. }
  34. public void setAddressId(int addressId) {
  35. this.addressId = addressId;
  36. }
  37. public String getAddressDetail() {
  38. return addressDetail;
  39. }
  40. public void setAddressDetail(String addressDetail) {
  41. this.addressDetail = addressDetail;
  42. }
  43. public Person getPerson() {
  44. return person;
  45. }
  46. public void setPerson(Person person) {
  47. this.person = person;
  48. }
  49. }
  50. </span>

从上面的两个关联实体的注解来看,他们双方所使用的注解是对等的,他们双方映射的表名是相同的,映射连接表中的外键列也是相互对应的,因此这两个实体都可用于控制关系,并且双方的地位是绝对平等的;

发表评论

表情:
评论列表 (有 0 条评论,217人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Hibernate--关联映射

           hibernate是持久层ORM框架,关系映射解决了对象型实体与关系型数据库不相匹配的问题,它是Hibernate的核心内容,在实际操作中我们必须要根据数据表的相