Hibernate中的Entity类之间的ManyToMany关联,必须在数据库模式中有一个中间连接表,其中的外键作为两个实体表之间的桥梁;而实体表中没有外键。
1. ManyToMany单向关联
任选一个实体类作为owning side,设置关联如下:
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
private Long id;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Address> addresses = new ArrayList<>();
public Person() {
}
public List<Address> getAddresses() {
return addresses;
}
}
在另一个实体类中不设置任何关联,如下:
@Entity(name = "Address")
public static class Address {
@Id
@GeneratedValue
private Long id;
private String street;
private String number;
public Address() {
}
public Address(String street, String number) {
this.street = street;
this.number = number;
}
public Long getId() {
return id;
}
public String getStreet() {
return street;
}
public String getNumber() {
return number;
}
}
单向关联中,没有关联实体类的概念。
单向关联中,删除被关联对象时,首先删除所有被关联的对象,然后再重新插入没有被删除的对象,存在性能瓶颈。
2.ManyToMany双向关联
在ManyToMany双向关联中,两个实体类可以互为父子类。任选其中一个作为父实体类(owning side),其中定义集合对象引用子实体类,子实体类(inverse side)方给出(mappedBy="...")指向父实体类。
父实体类(owning side)定义如下:
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String registrationNumber;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Address> addresses = new ArrayList<>();
public Person() {
}
public Person(String registrationNumber) {
this.registrationNumber = registrationNumber;
}
public List<Address> getAddresses() {
return addresses;
}
public void addAddress(Address address) {
addresses.add( address );
address.getOwners().add( this );
}
public void removeAddress(Address address) {
addresses.remove( address );
address.getOwners().remove( this );
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
Person person = (Person) o;
return Objects.equals( registrationNumber, person.registrationNumber );
}
@Override
public int hashCode() {
return Objects.hash( registrationNumber );
}
}
子实体类(inverse side)定义如下:
@Entity(name = "Address")
public static class Address {
@Id
@GeneratedValue
private Long id;
private String street;
private String number;
private String postalCode;
@ManyToMany(mappedBy = "addresses")
private List<Person> owners = new ArrayList<>();
public Address() {
}
public Address(String street, String number, String postalCode) {
this.street = street;
this.number = number;
this.postalCode = postalCode;
}
public Long getId() {
return id;
}
public String getStreet() {
return street;
}
public String getNumber() {
return number;
}
public String getPostalCode() {
return postalCode;
}
public List<Person> getOwners() {
return owners;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
Address address = (Address) o;
return Objects.equals( street, address.street ) &&
Objects.equals( number, address.number ) &&
Objects.equals( postalCode, address.postalCode );
}
@Override
public int hashCode() {
return Objects.hash( street, number, postalCode );
}
}
3.ManyToMany双向关联与两个OneToMany双向关联的等价替换
为中间表定义一个关联实体类,定义两个@ManyToOne关联,并作为owning side。
在两个实体类中分别定义一个@OneToMany关联,都作为inverse side。
关联实体类的定义如下:
@Entity(name = "PersonAddress")
public static class PersonAddress implements Serializable {
@Id
@ManyToOne
private Person person;
@Id
@ManyToOne
private Address address;
public PersonAddress() {
}
public PersonAddress(Person person, Address address) {
this.person = person;
this.address = address;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PersonAddress that = (PersonAddress) o;
return Objects.equals( person, that.person ) &&
Objects.equals( address, that.address );
}
@Override
public int hashCode() {
return Objects.hash( person, address );
}
}
注意:其中定义了两个@ManyToOne关联,并且都是作为owning side。
一个实体类定义如下:
@Entity(name = "Person")
public static class Person implements Serializable {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String registrationNumber;
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PersonAddress> addresses = new ArrayList<>();
public Person() {
}
public Person(String registrationNumber) {
this.registrationNumber = registrationNumber;
}
public Long getId() {
return id;
}
public List<PersonAddress> getAddresses() {
return addresses;
}
public void addAddress(Address address) {
PersonAddress personAddress = new PersonAddress( this, address );
addresses.add( personAddress );
address.getOwners().add( personAddress );
}
public void removeAddress(Address address) {
PersonAddress personAddress = new PersonAddress( this, address );
address.getOwners().remove( personAddress );
addresses.remove( personAddress );
personAddress.setPerson( null );
personAddress.setAddress( null );
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
Person person = (Person) o;
return Objects.equals( registrationNumber, person.registrationNumber );
}
@Override
public int hashCode() {
return Objects.hash( registrationNumber );
}
}
注意:其中定义了一个@OneToMany关联,并且作为inverse side。
另一个实体类定义如下:
@Entity(name = "Address")
public static class Address implements Serializable {
@Id
@GeneratedValue
private Long id;
private String street;
private String number;
private String postalCode;
@OneToMany(mappedBy = "address", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PersonAddress> owners = new ArrayList<>();
public Address() {
}
public Address(String street, String number, String postalCode) {
this.street = street;
this.number = number;
this.postalCode = postalCode;
}
public Long getId() {
return id;
}
public String getStreet() {
return street;
}
public String getNumber() {
return number;
}
public String getPostalCode() {
return postalCode;
}
public List<PersonAddress> getOwners() {
return owners;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
Address address = (Address) o;
return Objects.equals( street, address.street ) &&
Objects.equals( number, address.number ) &&
Objects.equals( postalCode, address.postalCode );
}
@Override
public int hashCode() {
return Objects.hash( street, number, postalCode );
}
}
注意:其中定义了一个@OneToMany关联,并且作为inverse side。