29 Temmuz 2020 Çarşamba

JPA @OneToMany Ilişki - Unidirectional

Giriş
Unidirectional OneToMany ilişki iyi bir şey değil ve mümkünse kaçınılmalı. Unidirectional ilişki, join tablosu ile veya join tablosu olmadan kurulabilir. Açıklaması şöyle.
By default, a unidirectional @OneToMany relationship will use a join table....

1. Join Tablosu Olmadan - Unidirectional İse Bu Tercih Edilir
 Eğer join tablosu olmasın istiyorsak parent tarafında OneToMany +  JoinColumn birlikte kullanılır.
@JoinColumn ile child nesnenin tablosundaki bir alan belirtilir.

Performansı OneToMany - Bidirectional kadar iyi olmasa bile ikinci seçeneğe göre daha iyi.

Örnek
Şöyle yaparız. article_id Vote tablosundadır
class Article extends BaseActivity{
  @OneToMany
  @JoinColumn(name = "article_id")
  private List<Vote> votes = new ArrayList<>();
}
Örnek
Açıklaması şöyle.
Although it seems less likely to be used, we can also have the one-to-many association on one side. In this case, the mappedBy element used above would not work because Book no longer has an association to Author. Instead, we use a @JoinColumn to tell Hibernate which column to use in order to fetch Book instances when given an author id:
Elimizde şöyle bir kod olsun.
@Entity
public class Author {
  @OneToMany
  @JoinColumn(name = "AUTHOR_ID")
  protected List<Book> books = new ArrayList<>();
  ...
}
Author tablosu şöyledir. Buraya kadar her şey normal. Klasik bir primary key kulllanan tablo oluşturuldu
create table Author (
    id bigint not null,
    birthDay date,
    country varchar(30) not null,
    name varchar(255) not null,
    primary key (id)
)
Book tablosu şöyledir. Author tablosuna foreign key olarak bağlandı.
create table Book (
    id bigint not null,
    publishingDate date,
    title varchar(255) not null,
    volumes integer not null,
    PUBLISHER_ID bigint not null,
    AUTHOR_ID bigint,
    primary key (id)
)

alter table Book
    add constraint FKe3rppuv3qa0j4ewpn52qfljn6
    foreign key (AUTHOR_ID)
    references Author
2. Join Tablosu İle - Tercih Edilmez
Eğer join tablosu olsun istiyorsak sadece OneToMany kodunu yazmak yeterli. @JoinTable anotasyonunu kullanmaya gerek yok. Bu durumda join tablosu otomatik olarak oluşturulur. Yani A tablosu, B tablosu ve A_B join tablosu vardır. Ancak bu kullanım şeklinde fazladan bir sürü sql çalıştığı için performans kaybı oluyor. Sebebi ise
- A için bir insert statement,
- B için bir insert statement ve
- A_B için bir insert statemen çalıştırılması
Eğer mevcut bir join tablosunu kullanmak istersek @JoinTable ile birlikte kullanırız.

EntityManager.persist() ve EntityManager.merge() Farkı
EntityManager.persist(parent) şeklinde kullanmak gerekir. Açıklaması şöyle. Ben de EntityManager.merge() ile denediğimde, child entity nesnelere id atanmadıklarını yani persist edilmediklerini gördüm.
Merge should be used for "re-attaching entities that got detached and not for taking arbitrary transient objects"
Örnek
Şöyle yaparız.
@Entity
public class Employee {
  @Id
  @Column(name="EMP_ID")
  private long id;
  ...
  @OneToMany (cascade = CascadeType.ALL)
  @JoinTable(name="EMP_PHONE",
    joinColumns={ @JoinColumn(name="EMP_ID", referencedColumnName="EMP_ID") },
    inverseJoinColumns={ @JoinColumn(name="PHONE_ID", referencedColumnName="ID",
                                     unique=true) }
  )

  private List<Phone> phones;
  ...
}
Empoloyee nesnesini Phone nesneleri ekleyerek kaydedersek, CascadeType.ALL kuıllandığımız için Employee ve Phone nesnelerinin birlikte kaydedildiklerini görürüz.

SQL olarak şöyle bir şey görürüz. Toplam 4 nesne yazmak için daha fazla SQL çalıştırmak gerekti. İşte bu yüzden Unidirectional OneToMany tercih edilmez.
insert into employee ...

insert into phone ...
insert into phone ...
insert into phone ...

insert into emp_phone ...
insert into emp_phone ...
insert into emp_phone ...

Hiç yorum yok:

Yorum Gönder