对于mappedBy复习下:
a) 只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性,ManyToOne不存在该属性;
b) mappedBy标签一定是定义在the owned side(被拥有方的),他指向the owning side(拥有方);
c) 关系的拥有方负责关系的维护,在拥有方建立外键。所以用到@JoinColumn
d)mappedBy跟JoinColumn/JoinTable总是处于互斥的一方
@OneToMany(cascade=CascadeType.ALL,orphanRemoval=true,mappedBy="shop")
private Set employees;
@ManyToOne(cascade = { CascadeType.ALL })
@JoinColumn(name="shop")
private Shop shop;
@OneToOne
@JoinColumn(name = "details_id")
private PhoneDetails details;
Phone表中添加关联字段
@OneToOne(mappedBy="phone",cascade=CascadeType.ALL,orphanRomval=true FetchType.LAZY)
private PhoneDetails details; //Phone类
//添加删除
public void addDetails(PhoneDetails details) {
details.setPhone( this );
this.details = details;
}
public void removeDetails() {
if ( details != null ) {
details.setPhone( null );
this.details = null;
}
}
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "phone_id") //外键在PhoneDetails表中
private Phone phone;//PhoneDetails类
---------
Phone phone = new Phone( "123-456-7890" );
PhoneDetails details = new PhoneDetails( "T-Mobile", "GSM" );
phone.addDetails( details ); //级联保存
entityManager.persist( phone );//通过保存Phone级联保存details
INSERT INTO Phone ( number, id )VALUES ( '123 - 456 - 7890', 1 )
INSERT INTO PhoneDetails ( phone_id, provider, technology, id )VALUES ( 1, 'T - Mobile, GSM', 2 )
---------
@ManyToOne
@JoinColumn(name = "person_id",
foreignKey = @ForeignKey(name = "PERSON_ID_FK")
)
@ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE})//一般不会配置级联删除,因为可以别的Person可能还与address关联着
private List addresses = new ArrayList<>();
----------------
CREATE TABLE Address (
id BIGINT NOT NULL ,
number VARCHAR(255) ,
street VARCHAR(255) ,
PRIMARY KEY ( id )
)
CREATE TABLE Person (
id BIGINT NOT NULL ,
PRIMARY KEY ( id )
)
CREATE TABLE Person_Address (
Person_id BIGINT NOT NULL ,
addresses_id BIGINT NOT NULL
)
ALTER TABLE Person_Address
ADD CONSTRAINT FKm7j0bnabh2yr0pe99il1d066u
FOREIGN KEY (addresses_id) REFERENCES Address
ALTER TABLE Person_Address
ADD CONSTRAINT FKba7rc9qe2vh44u93u0p2auwti
FOREIGN KEY (Person_id) REFERENCES Person
----------------
Person person1 = new Person();
Person person2 = new Person();
Address address1 = new Address( "12th Avenue", "12A" );
Address address2 = new Address( "18th Avenue", "18B" );
person1.getAddresses().add( address1 );
person1.getAddresses().add( address2 );
person2.getAddresses().add( address1 );
entityManager.persist( person1 ); //级联保存address1和address2
entityManager.persist( person2 );
//插入Person1,插入address1,插入address2,插入Person2,向中间表中插入person1关联的address1和address2,向中间插入person2关联的address1
entityManager.flush();
//从中间表删除person_id=person1 id的数据,再向中间表插入person1关联的address2
person1.getAddresses().remove( address1 );
@Id
@GeneratedValue
private Long id;
@NaturalId
private String registrationNumber;
@ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE})
private List addresses = new ArrayList<>();
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 ); //自然主键
}
@ManyToMany(mappedBy = "addresses") //指向拥有方,让Address类维护关系
private List owners = new ArrayList<>();
@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 );
}
-----------
同上的person和address,当person1.removeAddress( address1 );只会删除中间表的一条数据,而不会先都删除在添加没有删除的数据
如果双向@OneToMany协会执行更好的去除或改变子元素的顺序时,@ManyToMany关系不能受益于这样的优化,因为外键不控制。为了克服这个限制,必须直接接触和联系表格分成两个双向@OneToMany @ManyToMany协会的关系。
-------------
//表Person
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
private List addresses = new ArrayList<>();
public void addAddress(Address address) {
PersonAddress personAddress = new PersonAddress( this, address );
addresses.add( personAddress );
this.address.getOwners().add( personAddress );
}
//只是删除中间表的数据,而不删除address表中的数据
public void removeAddress(Address address) {
PersonAddress personAddress = new PersonAddress( this, address );
address.getOwners().remove( personAddress );
this.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 );
}
//中间表类 PersonAddress
@Id
@ManyToOne
private Person person;
@Id
@ManyToOne
private 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 );
}
//表类 Address
@OneToMany(mappedBy = "address", cascade = CascadeType.ALL, orphanRemoval = true)
private List owners = new ArrayList<>();
@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 );
}
@ManyToMany(mappedBy="categories")
private Set brands=new HashSet<>();
@ManyToMany(/*cascade={ CascadeType.ALL}*/)
@JoinTable(
name="tb_brand_category",
joinColumns=@JoinColumn(name="brand_id"),
inverseJoinColumns=@JoinColumn(name="category_id")
)
private Set categories=new HashSet<>();
public void addCategory(Category category){
category.getBrands().add(this);
this.categories.add(category);
}
public void removeAllCategory(){
this.categories.clear();
}
public void removeCategory(String code){
Category c=null;
for (Category category : categories) {
if(category.getCode().equals(code)){
c=category;
break;
}
}
this.categories.remove(c);
}
public void addAll(List category){
removeAllCategory();
category.forEach((c)->{
addCategory(c);
});
}
1集合
@Entity(name = "Person")
public static class Person {
@Id
private Long id;
@ElementCollection
private List phones = new ArrayList<>();
public List getPhones() {
return phones;
}
}
//@ElementCollection 添加和删除所有元素比较简单,删除某个元素则要重新组件集合
person.getPhones().remove(0);
DELETE FROM Person_phones WHERE Person_id = 1 //删除所有
INSERT INTO Person_phones ( Person_id, phones )VALUES ( 1, '456-000-1234' ) //把没有删除的重新插入数据库
2.顺序集合
@ElementCollection
@OrderColumn(name = "order_id")
private List phones = new ArrayList<>();
//**@OrderColumn从集合的尾部删除时,该列最适用**,因为它只需要一个删除语句。从集合的头部或中间移除需要删除额外的元素并更新其余元素以保留元素顺序。
3.可插入类型集合
@Embeddable
public static class Phone {
private String type;
@Column(name = "`number`")
private String number;
}
@Entity(name = "Person")
public static class Person {
@Id
private Long id;
@ElementCollection
private List phones = new ArrayList<>();
}
/*@ElementCollection
@CollectionTable(name = "tb_orders_items", joinColumns = @JoinColumn(name = "orders_id")) 指定值集合表名和外键名
*/
3.一对多单向关联(很想值集合)
@Entity(name = "Person")
public static class Person {
@Id
private Long id;
@OneToMany(cascade = CascadeType.ALL)
private List phones = new ArrayList<>();
}
@Entity(name = "Phone")
public static class Phone {
@Id
private Long id;
private String type;
@Column(name = "`number`")
private String number;
}
当设置CascadeType.ALL级联操作时,单向关联生命周期变得非常类似于值类型集合。
在删除或重新排列元素方面,效率不高,父端不能标识每个单独的孩子,因此会删除所有关联的字表行,再重新添加他他们
4.双向关联则提高效率
@Entity(name = "Person")
public static class Person {
@Id
private Long id;
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
private List phones = new ArrayList<>();
public Person() {
}
public Person(Long id) {
this.id = id;
}
public List getPhones() {
return phones;
}
public void addPhone(Phone phone) {
phones.add( phone );
phone.setPerson( this );
}
public void removePhone(Phone phone) {
phones.remove( phone );
phone.setPerson( null );
}
}
@Entity(name = "Phone")
public static class Phone {
@Id
private Long id;
private String type;
@Column(name = "`number`", unique = true)
@NaturalId
private String number;
@ManyToOne
private Person person;
public Phone() {
}
public Phone(Long id, String type, String number) {
this.id = id;
this.type = type;
this.number = number;
}
public Long getId() {
return id;
}
public String getType() {
return type;
}
public String getNumber() {
return number;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
Phone phone = (Phone) o;
return Objects.equals( number, phone.number );
}
@Override
public int hashCode() {
return Objects.hash( number );
}
}
@OneToMany(cascade = CascadeType.ALL)
@OrderBy("number") //查询sql通过phones表的number字段 order by phones.number
private List phones = new ArrayList<>();
//指定多个字段@OrderBy("name ASC, type DESC"))