lunes, 20 de junio de 2022

Spring Data Jpa Entity RelationShip Mappings @OneToOne Unidirection Inverse

Spring Data Jpa Entity RelationShip Mappings @OneToOne Unidirection Inverse



Java Entities

Capital Entity

@Entity
@NoArgsConstructor
@Table(name = "capital", schema = "public")
public class Capital {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "public.capital_seq")
private Long id;
private String name;

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name="country_id_fk", referencedColumnName = "id") // this could be omitted
private Country country;


Country Entity


@Entity
@NoArgsConstructor
@Table(name = "country", schema = "public")
public class Country {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "public.country_seq")
private Long id;
private String name;
@OneToOne(mappedBy = "country", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Capital capital;

Hibernate creates automatically the tables the next way

Tables

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

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

Hibernate: 
    
    alter table if exists public.capital 
       add constraint FK2qo7jvd6fd696h28g4xium9en 
       foreign key (country_id_fk
       references public.country


Test the behaviour

// Create country - capital relation and save by country
Country country = new Country();
country.setName("Mexico");
Capital capital = new Capital();
capital.setName("CDMX");

country.setCapital(capital);
capital.setCountry(country);

Country savedCountry = countryRepository.save(country);

log.info("savedCountry {} {} {}", savedCountry.getId(), savedCountry.getName(), savedCountry.getCapital().getName());

// At this moment capital has not been explicity saved, so when CountryRecovered tries to getCapital.name will fail
// IF Country-capital field OneToOne is fetch.LAZY, with fetch.EAGER saves capital immediately when country is saved.
Country countryRecovered = countryRepository.findById(savedCountry.getCapital().getId()).get();
log.info("countryRecovered: {} {} {}", countryRecovered.getId(), countryRecovered.getName(), countryRecovered.getCapital().getName());

// Saving item for sure can recover Customer indepently of fetch.LAZY
Capital savedCapital = capitalRepository.save(capital);
log.info("savedCapital: {}", savedCapital);

// Create new Customer - Item relation and save by item.
Country countryB = new Country("France");

Capital capitalB = new Capital("Paris");
capitalB.setCountry(countryB);
//capitalB.setCountry(savedCountry);
//capitalB.setCountry(country); // This will generate error: detached entity passed to persist because OneToOne violated
Capital capitalBsaved = capitalRepository.save(capitalB);
log.info("savedCapital {}", capitalBsaved);

On the output the queries generated by hibernate on the test.

Creation of tables

Hibernate: 
    
    create table public.capital (
       id int8 not null,
        name varchar(255),
        country_id_fk int8,
        primary key (id)
    )
Hibernate: 
    
    create table public.country (
       id int8 not null,
        name varchar(255),
        primary key (id)
    )
Hibernate: 
    
    alter table if exists public.capital 
       add constraint FK2qo7jvd6fd696h28g4xium9en 
       foreign key (country_id_fk) 
       references public.country

Queries executed by test

Hibernate: 
    select
        nextval ('public.country_seq')
Hibernate: 
    select
        nextval ('public.capital_seq')
Hibernate: 
    /* insert com.bext.onetooneunidirectionInverse.entity.Country
        */ insert 
        into
            public.country
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert com.bext.onetooneunidirectionInverse.entity.Capital
        */ insert 
        into
            public.capital
            (country_id_fk, name, id) 
        values
            (?, ?, ?)
2022-06-20 20:27:41.206  INFO 28404 --- [           main] .o.SpringdatajpaentitymappingApplication : savedCountry 1 Mexico CDMX
Hibernate: 
    select
        country0_.id as id1_1_0_,
        country0_.name as name2_1_0_ 
    from
        public.country country0_ 
    where
        country0_.id=?
Hibernate: 
    /* load com.bext.onetooneunidirectionInverse.entity.Capital */ select
        capital0_.id as id1_0_0_,
        capital0_.country_id_fk as country_3_0_0_,
        capital0_.name as name2_0_0_ 
    from
        public.capital capital0_ 
    where
        capital0_.country_id_fk=?
2022-06-20 20:27:41.219  INFO 28404 --- [           main] .o.SpringdatajpaentitymappingApplication : countryRecovered: 1 Mexico CDMX
Hibernate: 
    /* load com.bext.onetooneunidirectionInverse.entity.Capital */ select
        capital0_.id as id1_0_1_,
        capital0_.country_id_fk as country_3_0_1_,
        capital0_.name as name2_0_1_,
        country1_.id as id1_1_0_,
        country1_.name as name2_1_0_ 
    from
        public.capital capital0_ 
    left outer join
        public.country country1_ 
            on capital0_.country_id_fk=country1_.id 
    where
        capital0_.id=?
Hibernate: 
    /* load com.bext.onetooneunidirectionInverse.entity.Capital */ select
        capital0_.id as id1_0_0_,
        capital0_.country_id_fk as country_3_0_0_,
        capital0_.name as name2_0_0_ 
    from
        public.capital capital0_ 
    where
        capital0_.country_id_fk=?
2022-06-20 20:27:41.225  INFO 28404 --- [           main] .o.SpringdatajpaentitymappingApplication : savedCapital: Capital{id=1, name='CDMX', coutnry.name=Mexico}
Hibernate: 
    select
        nextval ('public.capital_seq')
Hibernate: 
    select
        nextval ('public.country_seq')
Hibernate: 
    /* insert com.bext.onetooneunidirectionInverse.entity.Country
        */ insert 
        into
            public.country
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert com.bext.onetooneunidirectionInverse.entity.Capital
        */ insert 
        into
            public.capital
            (country_id_fk, name, id) 
        values
            (?, ?, ?)
2022-06-20 20:27:41.232  INFO 28404 --- [           main] .o.SpringdatajpaentitymappingApplication : savedCapital Capital{id=2, name='Paris', coutnry.name=France}

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

eot

No hay comentarios:

Publicar un comentario