martes, 21 de junio de 2022

Spring Data Jpa Entity RelationShip Mappings @OneToOne Bidirection (No middle table)

Spring Data Jpa Entity RelationShip Mappings @OneToOne Bidirection (No middle table)



The relation between two entities of bidirectional kind, is emulated by the hibernate layer. Naturally only considering the possibilities of the relationship at database table Person_picture can have many relations to person. breaking the one to one relation desired. But the one to one relation is controlled at hibernate level, The same way the bidirectional relation of the one to one entities is achieved. Let do the Test to see if this is true.

Java Entities

Person Entity

@Entity
@NoArgsConstructor
@Table(name = "person", schema = "public")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO,generator = "public.person_seq")
private Long id;
private String name;
@OneToOne(mappedBy="person", cascade = CascadeType.ALL)
private PersonPicture personPicture;

public Person(String name) {
this.name = name;
}

public void addPicture(PersonPicture personPicture){
this.setPersonPicture(personPicture);
personPicture.setPerson(this);
}

public void removePicture(){
this.getPersonPicture().setPerson(null);
this.setPersonPicture(null);
}


Person_Picture Entity

@Entity
@NoArgsConstructor
@Table(name = "person_picture", schema = "public")
public class PersonPicture {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "public.person_picture_seq")
private Long id;
private String data;
@OneToOne
@JoinColumn(name = "person_id")
private Person person;

public PersonPicture(String data) {
this.data = data;
}

public void addPerson(Person person){
person.setPersonPicture(this);
this.setPerson(person);
}

public void removePerson(){
this.getPerson().setPersonPicture(null);
this.setPerson(null);
}


Hibernate creates automatically the tables the next way

Tables

    create table public.person (
       id int8 not null,
        name varchar(255),
        primary key (id)
    )

    create table public.person_picture (
       id int8 not null,
        data varchar(255),
        person_id int8,
        primary key (id)
    )

Hibernate: 
    
    alter table if exists public.person_picture 
       add constraint FK2knwerrgm9a9iagkvyh7s7itp 
       foreign key (person_id) 
       references public.person

Test the behaviour

@Transactional
public void createPersonAndPicture(){
Person person1 = new Person("Jose Alberto");
PersonPicture personPicture = new PersonPicture("picture of Person ...");
person1.addPicture(personPicture);
personRepository.save(person1);
}

At the output the queries generated by hibernate on this test.

Saving Person insert also Person_Picture

Hibernate: 
    select
        nextval ('public.person_seq')
Hibernate: 
    select
        nextval ('public.person_picture_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.Person
        */ insert 
        into
            public.person
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.PersonPicture
        */ insert 
        into
            public.person_picture
            (data, person_id, id) 
        values
            (?, ?, ?)


@Transactional
public void createPictureAndPerson(){
PersonPicture personPicture = new PersonPicture("picture of Person :)");
Person _person = new Person("Jose Alberto");
personRepository.save(_person); // must save otherwise
//person must save otherwise object references an unsaved transient instance - save the transient instance before flushin
personPicture.addPerson( _person);
personPictureRepository.save(personPicture);
}

At the output the queries generated by hibernate on this test.

Saving PersonPicture require previous save Person in order to insert also Person.

Hibernate: 
    select
        nextval ('public.person_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.Person
        */ insert 
        into
            public.person
            (name, id) 
        values
            (?, ?)
Hibernate: 
    select
        nextval ('public.person_picture_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.PersonPicture
        */ insert 
        into
            public.person_picture
            (data, person_id, id) 
        values
            (?, ?, ?)


@Transactional
public void createPersonAddPicture_checkBidirection(){
createPersonAndPicture();

Person _person = personRepository.findById(1L).get();
log.info("_person: {}", _person);

PersonPicture _personPicture = _person.getPersonPicture();
log.info("_person.getPersonPicture() is Proxy: {}", (_personPicture instanceof HibernateProxy) ? "YES" : "NO"); //YES
log.info("_person.getPersonPicture() in Initialized {}", Hibernate.isInitialized( _personPicture)); //true

log.info("_PersonPicture1: {}", _personPicture);
}

At the output the queries generated by hibernate on this test.

Hibernate: 
    select
        nextval ('public.person_seq')
Hibernate: 
    select
        nextval ('public.person_picture_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.Person
        */ insert 
        into
            public.person
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.PersonPicture
        */ insert 
        into
            public.person_picture
            (data, person_id, id) 
        values
            (?, ?, ?)
Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.name as name2_0_0_,
        personpict1_.id as id1_1_1_,
        personpict1_.data as data2_1_1_,
        personpict1_.person_id as person_i3_1_1_ 
    from
        public.person person0_ 
    left outer join
        public.person_picture personpict1_ 
            on person0_.id=personpict1_.person_id 
    where
        person0_.id=?
2022-06-21 17:01:58.435  INFO 39296 --- [           main] SpringdatajpaentityOneOneBidiApplication : _person: Person{id=1, name='Jose Alberto', personPicture=picture of Person ...}
2022-06-21 17:01:58.439  INFO 39296 --- [           main] SpringdatajpaentityOneOneBidiApplication : _person.getPersonPicture() is Proxy: NO
2022-06-21 17:01:58.439  INFO 39296 --- [           main] SpringdatajpaentityOneOneBidiApplication : _person.getPersonPicture() in Initialized true
2022-06-21 17:01:58.439  INFO 39296 --- [           main] SpringdatajpaentityOneOneBidiApplication : _PersonPicture1: PersonPicture{id=1, data='picture of Person ...', person=1 Jose Alberto}


@Transactional
public void createPictureAddPerson_checkBidirection(){
createPictureAndPerson();

PersonPicture _personPicture = personPictureRepository.findById(1L).get();
log.info("_personPicture", _personPicture);

Person _person = _personPicture.getPerson();
log.info("_personPicture.getPerson() is Proxy: {}", (_person instanceof HibernateProxy) ? "YES" : "NO");
log.info("_personPicture.getPerson() is Initialized {}", Hibernate.isInitialized( _person));

log.info("_person: {}", _person);
}

At the output the queries generated by hibernate on this test.

Hibernate: 
    select
        nextval ('public.person_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.Person
        */ insert 
        into
            public.person
            (name, id) 
        values
            (?, ?)
Hibernate: 
    select
        nextval ('public.person_picture_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.PersonPicture
        */ insert 
        into
            public.person_picture
            (data, person_id, id) 
        values
            (?, ?, ?)
Hibernate: 
    select
        personpict0_.id as id1_1_0_,
        personpict0_.data as data2_1_0_,
        personpict0_.person_id as person_i3_1_0_,
        person1_.id as id1_0_1_,
        person1_.name as name2_0_1_ 
    from
        public.person_picture personpict0_ 
    left outer join
        public.person person1_ 
            on personpict0_.person_id=person1_.id 
    where
        personpict0_.id=?
2022-06-21 17:04:08.476  INFO 36456 --- [           main] SpringdatajpaentityOneOneBidiApplication : _personPicture
2022-06-21 17:04:08.476  INFO 36456 --- [           main] SpringdatajpaentityOneOneBidiApplication : _personPicture.getPerson() is Proxy: NO
2022-06-21 17:04:08.476  INFO 36456 --- [           main] SpringdatajpaentityOneOneBidiApplication : _personPicture.getPerson() is Initialized true
2022-06-21 17:04:08.476  INFO 36456 --- [           main] SpringdatajpaentityOneOneBidiApplication : _person: Person{id=1, name='Jose Alberto', personPicture=picture of Person :)}


@Transactional
public void getPerson_checkPicture(){
createPersonAndPicture();

Person _person = personRepository.findById(1L).get();

PersonPicture personPicture = _person.getPersonPicture();

log.info("Person: {}", _person);
log.info("PersonPicture: {}", personPicture);
}

At the output the queries generated by hibernate on this test.

Hibernate: 
    select
        nextval ('public.person_seq')
Hibernate: 
    select
        nextval ('public.person_picture_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.Person
        */ insert 
        into
            public.person
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.PersonPicture
        */ insert 
        into
            public.person_picture
            (data, person_id, id) 
        values
            (?, ?, ?)
Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.name as name2_0_0_,
        personpict1_.id as id1_1_1_,
        personpict1_.data as data2_1_1_,
        personpict1_.person_id as person_i3_1_1_ 
    from
        public.person person0_ 
    left outer join
        public.person_picture personpict1_ 
            on person0_.id=personpict1_.person_id 
    where
        person0_.id=?
2022-06-21 17:06:35.632  INFO 44788 --- [           main] SpringdatajpaentityOneOneBidiApplication : Person: Person{id=1, name='Jose Alberto', personPicture=picture of Person ...}
2022-06-21 17:06:35.635  INFO 44788 --- [           main] SpringdatajpaentityOneOneBidiApplication : PersonPicture: PersonPicture{id=1, data='picture of Person ...', person=1 Jose Alberto}


@Transactional
public void getPicture_checkPerson(){
createPictureAndPerson();

PersonPicture _personPicture = personPictureRepository.findById(1L).get();

Person _person = _personPicture.getPerson();

log.info("PersonPicture: {}", _personPicture);
log.info("Person: {}", _person);
}

At the output the queries generated by hibernate on this test.

Hibernate: 
    select
        nextval ('public.person_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.Person
        */ insert 
        into
            public.person
            (name, id) 
        values
            (?, ?)
Hibernate: 
    select
        nextval ('public.person_picture_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.PersonPicture
        */ insert 
        into
            public.person_picture
            (data, person_id, id) 
        values
            (?, ?, ?)
Hibernate: 
    select
        personpict0_.id as id1_1_0_,
        personpict0_.data as data2_1_0_,
        personpict0_.person_id as person_i3_1_0_,
        person1_.id as id1_0_1_,
        person1_.name as name2_0_1_ 
    from
        public.person_picture personpict0_ 
    left outer join
        public.person person1_ 
            on personpict0_.person_id=person1_.id 
    where
        personpict0_.id=?
2022-06-21 17:14:37.057  INFO 24564 --- [           main] SpringdatajpaentityOneOneBidiApplication : PersonPicture: PersonPicture{id=1, data='picture of Person :)', person=1 Jose Alberto}
2022-06-21 17:14:37.060  INFO 24564 --- [           main] SpringdatajpaentityOneOneBidiApplication : Person: Person{id=1, name='Jose Alberto', personPicture=picture of Person :)}


@Transactional
public void deletePerson_checkPersonPictureAlsoDeleted(){
createPersonAndPicture();

personRepository.deleteById(1L);

log.info("person exist: {}",personRepository.existsById(1L)); // false
log.info("personPicture exist: {}", personPictureRepository.existsById(1L)); // false
}

The output to check the queries

Hibernate: 
    select
        nextval ('public.person_seq')
Hibernate: 
    select
        nextval ('public.person_picture_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.Person
        */ insert 
        into
            public.person
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.PersonPicture
        */ insert 
        into
            public.person_picture
            (data, person_id, id) 
        values
            (?, ?, ?)
Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.name as name2_0_0_,
        personpict1_.id as id1_1_1_,
        personpict1_.data as data2_1_1_,
        personpict1_.person_id as person_i3_1_1_ 
    from
        public.person person0_ 
    left outer join
        public.person_picture personpict1_ 
            on person0_.id=personpict1_.person_id 
    where
        person0_.id=?
Hibernate: 
    /* delete com.bext.onetoonebidirection.entity.PersonPicture */ delete 
        from
            public.person_picture 
        where
            id=?
Hibernate: 
    /* delete com.bext.onetoonebidirection.entity.Person */ delete 
        from
            public.person 
        where
            id=?
Hibernate: 
    /* select
        count(*) 
    from
        Person x 
    WHERE
        x.id = :id */ select
            count(*) as col_0_0_ 
        from
            public.person person0_ 
        where
            person0_.id=?
2022-06-21 17:22:07.341  INFO 39636 --- [           main] SpringdatajpaentityOneOneBidiApplication : person exist: false
Hibernate: 
    /* select
        count(*) 
    from
        PersonPicture x 
    WHERE
        x.id = :id */ select
            count(*) as col_0_0_ 
        from
            public.person_picture personpict0_ 
        where
            personpict0_.id=?
2022-06-21 17:22:07.344  INFO 39636 --- [           main] SpringdatajpaentityOneOneBidiApplication : personPicture exist: false


@Transactional
public void deletePersonPicture_checkPersonAlsoDeleted(){
createPictureAndPerson();
List<PersonPicture> all = personPictureRepository.findAll();
all.forEach( pp -> log.info("finadAll personPictures: {}",pp) );

//personRepository.deleteById(1L); // This delete Person and PersonPicture
personPictureRepository.deleteById(1L); // This don´t Delete PersonPicture

log.info("personPicture exist: {}", personPictureRepository.existsById(1L)); // true
log.info("person: {}", personRepository.existsById(1L)); // true
}
The output of queries generated

Hibernate: 
    select
        nextval ('public.person_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.Person
        */ insert 
        into
            public.person
            (name, id) 
        values
            (?, ?)
Hibernate: 
    select
        nextval ('public.person_picture_seq')
Hibernate: 
    /* insert com.bext.onetoonebidirection.entity.PersonPicture
        */ insert 
        into
            public.person_picture
            (data, person_id, id) 
        values
            (?, ?, ?)
Hibernate: 
    /* select
        generatedAlias0 
    from
        PersonPicture as generatedAlias0 */ select
            personpict0_.id as id1_1_,
            personpict0_.data as data2_1_,
            personpict0_.person_id as person_i3_1_ 
        from
            public.person_picture personpict0_
Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.name as name2_0_0_,
        personpict1_.id as id1_1_1_,
        personpict1_.data as data2_1_1_,
        personpict1_.person_id as person_i3_1_1_ 
    from
        public.person person0_ 
    left outer join
        public.person_picture personpict1_ 
            on person0_.id=personpict1_.person_id 
    where
        person0_.id=?
Hibernate: 
    /* load com.bext.onetoonebidirection.entity.PersonPicture */ select
        personpict0_.id as id1_1_1_,
        personpict0_.data as data2_1_1_,
        personpict0_.person_id as person_i3_1_1_,
        person1_.id as id1_0_0_,
        person1_.name as name2_0_0_ 
    from
        public.person_picture personpict0_ 
    left outer join
        public.person person1_ 
            on personpict0_.person_id=person1_.id 
    where
        personpict0_.person_id=?
2022-06-21 17:25:05.295  INFO 36468 --- [           main] SpringdatajpaentityOneOneBidiApplication : finadAll personPictures: PersonPicture{id=1, data='picture of Person :)', person=1 Jose Alberto}
Hibernate: 
    select
        personpict0_.id as id1_1_0_,
        personpict0_.data as data2_1_0_,
        personpict0_.person_id as person_i3_1_0_,
        person1_.id as id1_0_1_,
        person1_.name as name2_0_1_ 
    from
        public.person_picture personpict0_ 
    left outer join
        public.person person1_ 
            on personpict0_.person_id=person1_.id 
    where
        personpict0_.id=?
Hibernate: 
    /* select
        count(*) 
    from
        PersonPicture x 
    WHERE
        x.id = :id */ select
            count(*) as col_0_0_ 
        from
            public.person_picture personpict0_ 
        where
            personpict0_.id=?
2022-06-21 17:25:05.313  INFO 36468 --- [           main] SpringdatajpaentityOneOneBidiApplication : personPicture exist: true
Hibernate: 
    /* select
        count(*) 
    from
        Person x 
    WHERE
        x.id = :id */ select
            count(*) as col_0_0_ 
        from
            public.person person0_ 
        where
            person0_.id=?
2022-06-21 17:25:05.315  INFO 36468 --- [           main] SpringdatajpaentityOneOneBidiApplication : person: true



============================================================

eot

No hay comentarios:

Publicar un comentario