• HIbernate 领域模型关联


    简介

    关联关系,描述了两个及以上的实体基于数据库连接语义,形成关系

    • @ManyToOne
    • @OneToMany
    • @OneToOne
    • @ManyToMany

    @ManyToOne

    image-20210907221008727

    @Entity(name = "Person")
    public static class Person {
        
    	@Id
    	@GeneratedValue
    	private Long id;
    
    }
    
    @Entity(name = "Phone")
    public static class Phone {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	@Column(name = "`number`")
    	private String number;
    
    	@ManyToOne
    	@JoinColumn(name = "person_id",
    			foreignKey = @ForeignKey(name = "PERSON_ID_FK")
    	)
    	private Person person;
    
    }
    
    @Test
    public void test() {
        Person person = new Person();
        
        // INSERT INTO Person ( id ) VALUES ( 1 )
        session.save(person);
    
        Phone phone  = new Phone();
        phone.setNumber("111-222-333");
        phone.setPerson(person);
        
        // INSERT INTO Phone ( number, person_id, id ) VALUES ( '123-456-7890', 1, 2 )
        session.save(phone);
        
        transaction.commit();
    }
    

    @OneToMany

    OneToMany 表示,一个父类实体,有一个或多个子类实体。

    • 单向连接:@OneToMany 在子类中没有一个对应的 @ManyToOne ,需要一张关联表,删除子类有些麻烦
    • 双向连接:@OneToMany 在子类中有一个对应的 @ManyToOne ,不需要关联表,删除子类很方便

    单向连接

    image-20210908110550573

    @Entity(name = "Person")
    public static class Person {
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    	private List<Phone> phones = new ArrayList<>();
    }
    
    @Entity(name = "Phone")
    public static class Phone {
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	@Column(name = "`number`")
    	private String number;
    }
    
    @Test
    public void save() {
        // INSERT INTO Person (id) VALUES (1)
        Person person = new Person();
        
        // INSERT INTO Phone (number, id) VALUES ('123-456-7890', 2)
        // INSERT INTO Phone (number, id) VALUES ('321-654-0987', 3)
        Phone phone1 = new Phone( "123-456-7890" );
        Phone phone2 = new Phone( "321-654-0987" );
    
        // INSERT INTO Person_Phone (Person_id, phones_id) VALUES (1, 2)
        // INSERT INTO Person_Phone (Person_id, phones_id) VALUES (1, 3)
        person.getPhones().add( phone1 );
        person.getPhones().add( phone2 );
    
        session.save(person);
        transaction.commit();
    }
    
    // 删除父类
    @Test
    public void deleteParent() {
        /* select person0_.id as id1_0_0_ from person person0_ where person0_.id=?
        
        select
            phones0_.Person_id as Person_i1_1_0_,
            phones0_.phones_id as phones_i2_1_0_,
            phone1_.id as id1_2_1_,
            phone1_.number as number2_2_1_
        from person_phone phones0_
        inner join phone phone1_
        on phones0_.phones_id=phone1_.id
        where phones0_.Person_id=? */
        
        // delete from person_phone where Person_id=?
        // delete from phone where id=?
        // delete from person where id=?
        Person person = session.get(Person.class, 1l);
        session.delete(person);
        transaction.commit();
    }
    
    // 不支持删除子类
    @Test
    public void deleteChild() {
        /*
        select
            phone0_.id as id1_2_0_,
            phone0_.number as number2_2_0_ 
        from phone phone0_  where phone0_.id=?
        
        delete from phone where id=?
        */
        // org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions ERROR: Cannot delete or update a parent row:
        Phone phone = session.get(Phone.class, 25l);
        session.delete(phone);
        transaction.commit();
    }
    

    会自行创建一张实体关系表,并自动进行外键关联

     Hibernate: 
     
        create table person_phone (
            Person_id bigint not null,
            phones_id bigint not null
        )
    Hibernate:    
    
        alter table person_phone 
            drop constraint UK_n18iu022oaxft4wgo5ptpvsq9
    Hibernate: 
        
        alter table person_phone 
            add constraint UK_n18iu022oaxft4wgo5ptpvsq9 unique (phones_id)
    Hibernate: 
        
        alter table person_phone 
            add constraint FKcr8ypojbtlpbtim9b95m6a968 
            foreign key (phones_id) 
            references phone (id)
    Hibernate: 
        
        alter table person_phone 
            add constraint FK9pbvaylxtjku5s7dle5wwq2oc 
            foreign key (Person_id) 
            references person (id)
    

    双向关联

    image-20210908123149628

    @Entity(name = "Person")
    public static class Person {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
    	private List<Phone> phones = new ArrayList<>();
    
    	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
    	@GeneratedValue
    	private Long id;
    
    	@NaturalId
    	@Column(name = "`number`", unique = true)
    	private String number;
    
    	@ManyToOne
    	private 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 );
    	}
    }
    
    @Test
    public void test() {
    
        /*
        INSERT INTO Person ( id ) VALUES ( 1 )
        INSERT INTO Phone ( "number", person_id, id ) VALUES ( '123-456-7890', 1, 2 )
        INSERT INTO Phone ( "number", person_id, id ) VALUES ( '321-654-0987', 1, 3 )
        */
        Person person = new Person();
        Phone phone1 = new Phone("123-457890");
        Phone phone2 = new Phone("123-456-7890");
    
        person.addPhone(phone1);
        person.addPhone(phone2);
    
        session.save(person);
        transaction.commit();
    }
    
    @Test
    public void deleteChild() {
        /*
        select
            phone0_.id as id1_1_0_,
            phone0_.`number` as number2_1_0_,
            phone0_.person_id as person_i3_1_0_,
            person1_.id as id1_0_1_ 
        from Phone phone0_ 
        left outer join Person person1_ on phone0_.person_id=person1_.id 
        where phone0_.id=?
        
        delete from Phone where id=?
        */
       
        Phone phone = session.get(Phone.class, 5l);
        session.delete(phone);
        transaction.commit();
    }
    
    @Test
    public void deleteParent() {
        /*
        select person0_.id as id1_0_0_ from Person person0_ where person0_.id=?
        
        select
            phones0_.person_id as person_i3_1_0_,
            phones0_.id as id1_1_0_,
            phones0_.id as id1_1_1_,
            phones0_.`number` as number2_1_1_,
            phones0_.person_id as person_i3_1_1_ 
        from Phone phones0_ 
        where phones0_.person_id=?
       
        delete from Phone where id=?
        delete from Person where id=?
        */
        Person person = session.get(Person.class, 4l);
        session.delete(person);
        transaction.commit();
    }
    

    @OneToOne

    • 单向连接:遵循,关系数据库,外键规则,子端控制连接
    • 双向连接:父类会有一个 mappedBy @OneToOne

    单向连接

    image-20210908135312799

    @Entity(name = "Phone")
    public static class Phone {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	@Column(name = "`number`")
    	private String number;
    
        // 与 @ManyToOne 比较类似,遵循关系数据库的外键规则
    	@OneToOne
    	@JoinColumn(name = "details_id")
    	private PhoneDetails details;
    
    }
    
    @Entity(name = "PhoneDetails")
    public static class PhoneDetails {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	private String provider;
    
    	private String technology;
    
    }
    

    双向连接

    image-20210908135947786

    @Entity(name = "Phone")
    public static class Phone {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	@Column(name = "`number`")
    	private String number;
    
        // mappedBy 对应的是,子类的中,OneToOne 的对象
    	@OneToOne(
    		mappedBy = "phone",
    		cascade = CascadeType.ALL,
    		orphanRemoval = true,
    		fetch = FetchType.LAZY
    	)
    	private PhoneDetails details;
    
    	public void addDetails(PhoneDetails details) {
    		details.setPhone( this );
    		this.details = details;
    	}
    
    	public void removeDetails() {
    		if ( details != null ) {
    			details.setPhone( null );
    			this.details = null;
    		}
    	}
    }
    
    @Entity(name = "PhoneDetails")
    public static class PhoneDetails {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	private String provider;
    
    	private String technology;
    
    	@OneToOne(fetch = FetchType.LAZY)
    	@JoinColumn(name = "phone_id")
    	private Phone phone;
    }
    
    @Test
    public void test() {
        
        // insert into phone (`number`, id) values (?, ?)
        // insert into phonedetails (phone_id, provider, technology, id) values (?, ?, ?, ?)
        Phone phone = new Phone("123-456-7890");
        Phonedetail detail = new Phonedetail("T-Mobile", "GSM");
    
        phone.addDetails(detail);
        session.save(phone);
        transaction.commit();
    }
    

    @ManyToMany

    @ManyToMany 需要一个关联表来表示实体之间的关系,就像 @OneToMany,同时,@ManyToMany 也可以是双向或者单向的

    双向连接,有一个拥有者,和一个映射方

    单向连接

    image-20210908141749746

    @Entity(name = "Person")
    public static class Person {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    	private List<Address> addresses = new ArrayList<>();
    }
    
    @Entity(name = "Address")
    public static class Address {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	private String street;
    
    	@Column(name = "`number`")
    	private String number;
    }
    

    单向的 @ManyToMany 跟 单向的 @OneToMany 很相像

    // 当 entity 中的集合,删除一个元素后,先将连接表中对应的集合元素全部删除,再重新创建当前的集合信息
    @Test
    public void deleteParent() {
        /*
        select person0_.id as id1_1_0_ from Person person0_  where person0_.id=?
        
        select
            addresses0_.Person_id as Person_i1_2_0_,
            addresses0_.addresses_id as addresse2_2_0_,
            address1_.id as id1_0_1_,
            address1_.`number` as number2_0_1_,
            address1_.street as street3_0_1_ 
        from Person_Address addresses0_ 
        inner join Address address1_ on addresses0_.addresses_id=address1_.id 
        where addresses0_.Person_id=?
        
        delete from Person_Address where Person_id=?
        
        insert into Person_Address (Person_id, addresses_id) values(?, ?)
        */
        Person person = session.get(Person.class, 15l);
        person.getAddressList().remove(1);
        session.update(person);
        transaction.commit();
    }
    

    双向连接

    image-20210908151231397

    @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 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 );
    	}
    }
    
    @Entity(name = "Address")
    public static class Address {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	private String street;
    
    	@Column(name = "`number`")
    	private String number;
    
    	private String postalCode;
    
    	@ManyToMany(mappedBy = "addresses")
    	private List<Person> 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 );
    	}
    }
    

    @OneToMany 转换

    有些时候,双向的@ManyToMany 在删除或者更新数据的时候,没有 双向的@OneToMany 有效

    image-20210908151600707

    @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 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 );
    	}
    }
    
    @Entity(name = "PersonAddress")
    public static class PersonAddress implements Serializable {
    
    	@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 );
    	}
    }
    
    @Entity(name = "Address")
    public static class Address implements Serializable {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	private String street;
    
    	@Column(name = "`number`")
    	private String number;
    
    	private String postalCode;
    
    	@OneToMany(
    		mappedBy = "address",
    		cascade = CascadeType.ALL,
    		orphanRemoval = true
    	)
    	private List<PersonAddress> 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 );
    	}
    }
    

    级联关系 cascade

    • CascadeType.PERSIST:级联新增(又称级联保存):对order对象保存时也对items里的对象也会保存。对应EntityManagerpresist 方法。

      例子:只有A类新增时,会级联B对象新增。若B对象在数据库存(跟新)在则抛异常(让B变为持久态)

    • CascadeType.MERGE:级联合并(级联更新):若items属性修改了那么order对象保存时同时修改items里的对象。对应 EntityManagermerge 方法 。
      例子:指A类新增或者变化,会级联B对象(新增或者变化)

    • CascadeType.REMOVE:级联删除:对order对象删除也对items里的对象也会删除。对应 EntityManagerremove 方法。

      例子:REMOVE只有A类删除时,会级联删除B类;

    • CascadeType.REFRESH:级联刷新:获取order对象里也同时也重新获取最新的items时的对象。对应 EntityManagerrefresh(object)方法有效。即会重新查询数据库里的最新数据。

    • `CascadeType.ALL:以上四种都是。

    @Entity(name = "Person")
    public static class Person {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
        // 不包括 CascadeType.remove
    	@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    	private List<Address> addresses = new ArrayList<>();
        
    }
    
    
    // 此时进行删除
    @Test
    public void deleteParent() {
        /*
        delete from Person_Address where Person_id=?
        delete from Person where id=?
        */
        Person person = session.get(Person.class, 26l);
        session.delete(person);
        transaction.commit();
    }
    
    @Entity(name = "Person")
    public static class Person {
    
    	@Id
    	@GeneratedValue
    	private Long id;
    
        // 包括 CascadeType.remove
    	@ManyToMany(cascade = { CascadeType.remove, CascadeType.PERSIST, CascadeType.MERGE})
    	private List<Address> addresses = new ArrayList<>();
        
    }
    
    
    // 此时进行删除
    @Test
    public void deleteParent() {
        /*
        delete from Person_Address where Person_id=?
        delete from Address where id=?
        delete from Person where id=?
        */
        Person person = session.get(Person.class, 26l);
        session.delete(person);
        transaction.commit();
    }
    

    与外键之间的关系

    如果一个实体的某个字段指向另一个实体的主键,就称为 外键
    被指向的实体,称之为主实体(主表),也叫父实体(父表)。
    负责指向的实体,称之为从实体(从表),也叫子实体(子表)

    image-20210908123149628

    表之间的关系

    • 一对一
    • 一对多
    • 多对多

    级联操作

    on update、on delete

    决定了在主表数据发生改变时,与之关联的从表数据应该如何处理

    属性:

    • cascade:关联操作,如果主表被更新或删除,从表也会执行相应的操作
    • set null:表示从表数据不指向主表任何记录
    • restrict:拒绝主表的相关操作(默认情况)

    参考网站:

    Hibernate 官网
    https://docs.jboss.org/hibernate/orm/5.5/userguide/html_single/Hibernate_User_Guide.html#associations

  • 相关阅读:
    HAL 分析
    Ubuntu 11.04 安装后要做的20件事情
    IOStableViewCell自适应高度cell里面放的是UIlable
    IOS支持的字体
    IOS TableView学习资源
    产品与市场
    软件质量与公司盈利
    计算机流派
    让你的软件支持繁体中文
    系统规划设置心得
  • 原文地址:https://www.cnblogs.com/Kevin-QAQ/p/15246293.html
Copyright © 2020-2023  润新知