@OneToOne - relacja jedno i dwukierunkowa

Relacja @OneToOne jest to połączenie dwóch tabel za pomocą klucza głównego pierwszej tabeli i klucza obcego drugiej tabeli. Relacje dwukierunkową w Hibernejcie realizujemy na encjach, dzięki temu struktura tabel w bazie danych pozostaje niezmieniona.




✅ Stworzenie tabel w bazie danych 


CREATE DATABASE IF NOT EXISTS `bazatestowa2`;

USE `bazatestowa2`;

CREATE TABLE IF NOT EXISTS company_detail (

    company_detail_id INT AUTO_INCREMENT,

    created DATE, 

    country VARCHAR(40), 

    PRIMARY KEY (company_detail_id)

) ENGINE=InnoDB;


CREATE TABLE IF NOT EXISTS company (

    company_id INT AUTO_INCREMENT,

    company_name VARCHAR(40) DEFAULT NULL,

    PRIMARY KEY (company_id),

    company_detail_id INT,

    CONSTRAINT FK_COMPANY_COMPANYDETAIL FOREIGN KEY (company_detail_id) REFERENCES company_detail (company_detail_id)

) ENGINE=InnoDB;








 Stworzenie klas Entity w relacji jednokierunkowej


👉 Entity Company

package myhibernate.onedirection.entity;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name = "company")
public class Company {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="company_id")
private Integer companyId;
@Column(name="company_name")
private String companyName;

@OneToOne(cascade= CascadeType.ALL)
@JoinColumn(name="company_detail_id")
private CompanyDetail companyDetail;
public Integer getCompanyId() {
return companyId;
}

public void setCompanyId(Integer companyId) {
this.companyId = companyId;
}

public String getCompanyName() {
return companyName;
}

public void setCompanyName(String companyName) {
this.companyName = companyName;
}

public CompanyDetail getCompanyDetail() {
return companyDetail;
}

public void setCompanyDetail(CompanyDetail companyDetail) {
this.companyDetail = companyDetail;
}

@Override
public String toString() {
return "Company [companyId=" + companyId + ", companyName=" + companyName + "]";
}
}

👉 Entity CompanyDetail 

package myhibernate.onedirection.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = "company_detail")
public class CompanyDetail {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="company_detail_id")
private Integer companyDetailId;
@Temporal(value=TemporalType.TIMESTAMP)
@Column(name="created")
private Date created;
@Column(name="country")
private String country;

public Integer getCompanyDetailId() {
return companyDetailId;
}

public void setCompanyDetailId(Integer companyDetailId) {
this.companyDetailId = companyDetailId;
}

public Date getCreated() {
return created;
}

public void setCreated(Date created) {
this.created = created;
}

public String getCountry() {
return country;
}

public void setCountry(String country) {
this.country = country;
}

@Override
public String toString() {
return "CompanyDetail [companyDetailId=" + companyDetailId + ", created=" + created + ", country=" + country
+ "]";
}
}




 Stworzenie klas Entity w relacji dwukierunkowej


❗ Relacje dwukierunkową w hibernejcie realizujemy na encjach, dzięki temu struktura tabel w bazie danych pozostaje niezmieniona.

👉 Entity Company

package myhibernate.twodirection.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import javax.persistence.CascadeType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

@Entity
@Table(name = "company")
public class Company {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="company_id")
private Integer companyId;
@Column(name="company_name")
private String companyName;

@OneToOne(cascade= CascadeType.ALL)
@JoinColumn(name="company_detail_id")
private CompanyDetail companyDetail;
public Integer getCompanyId() {
return companyId;
}

public void setCompanyId(Integer companyId) {
this.companyId = companyId;
}

public String getCompanyName() {
return companyName;
}

public void setCompanyName(String companyName) {
this.companyName = companyName;
}

public CompanyDetail getCompanyDetail() {
return companyDetail;
}

public void setCompanyDetail(CompanyDetail companyDetail) {
this.companyDetail = companyDetail;
}

@Override
public String toString() {
return "Company [companyId=" + companyId + ", companyName=" + companyName + "]";
}
}

👉 Entity CompanyDetail 

package myhibernate.twodirection.entity;

import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = "company_detail")
public class CompanyDetail {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="company_detail_id")
private Integer companyDetailId;
@Temporal(value=TemporalType.TIMESTAMP)
@Column(name="created")
private Date created;
@Column(name="country")
private String country;
@OneToOne(mappedBy="companyDetail", cascade= CascadeType.ALL)
private Company company;

public Integer getCompanyDetailId() {
return companyDetailId;
}

public void setCompanyDetailId(Integer companyDetailId) {
this.companyDetailId = companyDetailId;
}

public Date getCreated() {
return created;
}

public void setCreated(Date created) {
this.created = created;
}

public String getCountry() {
return country;
}

public void setCountry(String country) {
this.country = country;
}

public Company getCompany() {
return company;
}

public void setCompany(Company company) {
this.company = company;
}

@Override public String toString() { return "CompanyDetail [companyDetailId=" + companyDetailId + ", created=" + created + ", country=" + country + "]"; }
}

w polu mappedBy podajemy nazwę pola z klasy, która na bazie ma w sobie klucz [Foreign Key]. W tym przypadku jest to pole companyDetail z klasy Company. 




 Klasa testująca dodawanie obiektu w relacji jednokierunkowej


package myhibernate.onedirection;


import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import myhibernate.onedirection.entity.Company;
import myhibernate.onedirection.entity.CompanyDetail;

public class RelationOneToOneApp {

public static void main(String[] args) {
Configuration conf = new Configuration();
conf.configure("hibernate.cfg.xml");
conf.addAnnotatedClass(Company.class);
conf.addAnnotatedClass(CompanyDetail.class);
SessionFactory factory = conf.buildSessionFactory();
Session session = factory.getCurrentSession();
session.beginTransaction();
//create company
Company company = new Company();
company.setCompanyName("BIG Company");
//create company detail
CompanyDetail companyDetail = new CompanyDetail();
companyDetail.setCountry("USA");
Date dateCreatedCompany = new Date();
companyDetail.setCreated(dateCreatedCompany);
//add ref
company.setCompanyDetail(companyDetail);
session.save(company);
session.getTransaction().commit();
factory.close();
}
}

❗ Wynik działania w konsoli: 



❗Wynik w bazie danych: 

1. tabela company


2. tabela company_detail







 Klasa testująca usuwanie obiektu w relacji jednokierunkowej


❗ Aktualy stan w bazie danych:

1. tabela company 


2. tabela company_detail



package myhibernate.onedirection;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import myhibernate.onedirection.entity.Company;
import myhibernate.onedirection.entity.CompanyDetail;

public class DeleteOneToOneApp {

public static void main(String[] args) {
Configuration conf = new Configuration();
conf.configure("hibernate.cfg.xml");
conf.addAnnotatedClass(Company.class);
conf.addAnnotatedClass(CompanyDetail.class);
SessionFactory factory = conf.buildSessionFactory();
Session session = factory.getCurrentSession();
session.beginTransaction();
String sql = "from Company c where c.companyName = :companyName ";
Query<Company> query = session.createQuery(sql);
query.setParameter("companyName", "BIG Company 1");
Company company = query.getSingleResult();
System.out.println("obiekt istnieje w baze:");
System.out.println(company);
session.delete(company);
System.out.println("obiekt skasowany.");
session.getTransaction().commit();
factory.close();

}

}

❗ Wynik działania w konsoli: 


❗ Wynik w bazie danych: 

1. tabela company


2. tabela company_detail






 Klasa testująca dodawanie obiektu w relacji dwukierunkowej 


👉 Klasa testująca

package myhibernate.twodirection;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import myhibernate.twodirection.entity.Company;
import myhibernate.twodirection.entity.CompanyDetail;

public class RelationOneToOneApp {

public static void main(String[] args) {
Configuration conf = new Configuration();
conf.configure("hibernate.cfg.xml");
conf.addAnnotatedClass(Company.class);
conf.addAnnotatedClass(CompanyDetail.class);
SessionFactory factory = conf.buildSessionFactory();
Session session = factory.getCurrentSession();
session.beginTransaction();
//create company
Company company = new Company();
company.setCompanyName("COMPANY 123");
//create company detail
CompanyDetail companyDetail = new CompanyDetail();
companyDetail.setCountry("POL");
Date dateCreatedCompany = new Date();
companyDetail.setCreated(dateCreatedCompany);
//add ref
company.setCompanyDetail(companyDetail);
session.save(company);
session.getTransaction().commit();
factory.close();
}
}

❗ Wynik działania w konsoli: 



❗Wynik w bazie danych: 

1. tabela company



2. tabela company_detail






 Klasa testująca usuwanie obiektu w relacji dwukierunkowej


Dzięki relacji dwukierunkowej, możemy w łatwy sposób dostać się z obiektu Company mając obiekt CompanyDetail

❗ Aktualy stan w bazie danych:

1. tabela company


2. tabela company_detail



👉 Klasa testująca

package myhibernate.twodirection;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import myhibernate.twodirection.entity.Company;
import myhibernate.twodirection.entity.CompanyDetail;

public class DeleteOneToOneApp {

public static void main(String[] args) {
Configuration conf = new Configuration();
conf.configure("hibernate.cfg.xml");
conf.addAnnotatedClass(Company.class);
conf.addAnnotatedClass(CompanyDetail.class);
SessionFactory factory = conf.buildSessionFactory();
Session session = factory.getCurrentSession();
session.beginTransaction();
String sql = "from CompanyDetail c where c.companyDetailId = :companyId ";
Query<CompanyDetail> query = session.createQuery(sql);
query.setParameter("companyId", 2);
CompanyDetail companyDetail = query.getSingleResult();
System.out.println("obiekt istnieje w baze:");
System.out.println(companyDetail);
session.delete(companyDetail); 
System.out.println("obiekt skasowany.");
session.getTransaction().commit();
factory.close();

}

}

❗ Wynik działania w konsoli: 


Jak widać w konsoli powstał tutaj problem N + 1 zapytań. Najpierw w  linii getSinleResult() wykonało się pierwsze zapytanie do wyciągnięcia informacji o obiekcie CompanyDetail

SELECT companydet0_.company_detail_id AS company_1_1_,
       companydet0_.country           AS country2_1_,
       companydet0_.created           AS created3_1_
FROM   company_detail companydet0_
WHERE  companydet0_.company_detail_id = ? 

a chwile później wykonało się drugie zapytanie doczytujące informacje o obiekcie Company

SELECT company0_.company_id           AS company_1_0_1_,
       company0_.company_detail_id    AS company_3_0_1_,
       company0_.company_name         AS company_2_0_1_,
       companydet1_.company_detail_id AS company_1_1_0_,
       companydet1_.country           AS country2_1_0_,
       companydet1_.created           AS created3_1_0_
FROM   company company0_
       LEFT OUTER JOIN company_detail companydet1_
                    ON company0_.company_detail_id =
                       companydet1_.company_detail_id
WHERE  company0_.company_detail_id = ? 

w celu ominięcia tego problemu należy w zapytaniu podać join fetch c.company czyli

String sql = "from CompanyDetail c join fetch c.company where c.companyDetailId = :companyId ";


w tej sytuacji Hibernate buduje jedno złączone zapytanie dla Company i CompanyDetail

SELECT companydet0_.company_detail_id AS company_1_1_0_,
       company1_.company_id           AS company_1_0_1_,
       companydet0_.country           AS country2_1_0_,
       companydet0_.created           AS created3_1_0_,
       company1_.company_detail_id    AS company_3_0_1_,
       company1_.company_name         AS company_2_0_1_
FROM   company_detail companydet0_
       INNER JOIN company company1_
               ON companydet0_.company_detail_id = company1_.company_detail_id
WHERE  companydet0_.company_detail_id = ? 

❗Wynik w bazie danych: 

1. tabela company



2. tabela company_detail





Brak komentarzy:

Prześlij komentarz