Herhangi bir ORM çözümünün nesne model üzerinden çalışmayı sağlayabilmesi için öncelikle uygulamanın nesne modeli ile veri modeli arasında eşleştirme yapılması gerekir. Bu aşamada;
- sınıflar ile tablolar
- property’ler ile sütunlar
- sınıflar arası ilişkiler ile foreign key’ler
- java tipleri ile SQL veri tipleri
arasında eşleştirmeler yapılır.
Bu yazı dizimizde spesifik olarak JPA ve Hibernate’in sınıflar arası ilişkiler ile foreign key’ler arasında eşleştirme yapmamızı sağlayan yapılarını kategorik biçimde incelemeye çalışacağız. Sınıflar arası ilişkiler genel olarak aşağıdaki gibi gruplanarak incelenebilir;
- Multiplicity: yani ilişkinin çokluluğu, iki sınıf arasındaki ilişkinin multiplicity’si 1:1,1:M,M:1 veya M:N şeklinde olabilir.
- İlişkinin yönü: Sınıflar arası ilişkiler tek yönlü (uni-directional) veya çift yönlü (bi-directional) olabilir.
- Source ve target sınıfların türü: İlişkiye giren sınıflar, Entity – Entity veya Entity – Component (Embeddable) şeklinde olabilir.
Bu gruplandırmaya ilave olarak 1:M veya M:N ilişkiler kendi içerisinde target sınıftan nesnelerin tutulduğu Java Collections API’sindeki tipe göre de gruplanabilir.
- Collection türü: List, Set, Map veya Bag (Collection) şeklinde olabilir.
Öncelikle entity-entity türündeki sınıflar arasındaki ilişkileri inceleyelim. En basit ilişki türü tek yönlü 1:1 ilişki olacaktır. Source entity sınıfındaki property üzerinde @OneToOne annotasyonu ile belirtilir. M:N ilişkiler haricinde diğer ilişkilerin bilgisi bir “join column” veya “join table” üzerinden yönetilebilir. Bunun için @JoinColumn veya @JoinTable annotasyonları kullanılır. İlişkiyi çift yönlü yapmak istersek bu durumda @OneToOne annotasyonu ilişkinin diğer tarafına da konmalıdır. Bu durumda Hibernate’in iki entity arasındaki ilişkiyi kurmak veya kaldırmak için uygulama kodu içerisinde hangi taraftaki property üzerinde yapılan değişiklikleri dikkate alması gerektiğini söylememiz gerekir. Bunun için @OneToOne annotasyonundaki mappedBy attribute’u kullanılır. MappedBy attribute’u @ManyToOne annotasyonu hariç diğer multiplicity belirten annotasyonların hepsinde mevcuttur. Çift yönlü ilişkilerde ayrıca @JoinTable veya @JoinColumn annotasyonları da ilişkiyi yöneten taraf üzerinden tanımlanmak zorundadır. Aksi takdirde JPA/Hibernate hata verecektir.
1:1 ilişkiyi sütun üzerinden yönettiğimiz takdirde, ilişkiyi “foreign key join column” veya “primary key join column” üzerinden yönetmek mümkündür. Genel olarak 1:1 ilişkileri foreign key üzerinden yönetmek daha pratiktir. Primary key join column yönteminde bir sınıfın primary key’i diğer sınıfın primary key’ine referans veren foreign key olmak zorundadır. Bu tür bir ilişkiyi kurmak için @PrimaryKeyJoinColumn annotasyonu kullanılır.
JPA ve Hibernate’in ilişkileri eager veya lazy yükleme özelliği vardır. Ancak Hibernate’in proxy yaklaşımından dolayı opsiyonel 1:1 ilişkilerde lazy yükleme yapmak mümkün olmayabilir.
Entity-component sınıfları arasında 1:1 ilişkiler ise @Embedded veya @Embeddable annotasyonları ile gerçekleştirilir. Normalde bir entity sınıf içerisindeki ilişki @Embedded/@Embeddable annotasyonları ile tanımlandığı takdirde target sınıfın property’lerine karşılık gelen sütunlar source sınıfın tablosunun içerisinde yer alır. Başka bir ifade ile nesne model üzerinde iki farklı sınıfa dağılmış bilgi, veritabanı düzeyinde ise tek tablo içerisinde toplanır. Veritabanı düzeyinde tek tablo içerisinde yönetilen bu ilişki nesne düzeyinde ise iki sınıfın 1:1 ilişkisine karşılık gelmektedir. Eğer tek tablo içerisinde tutulan bu bilgiyi iki ayrı tabloya dağıtmak istersek @SecondaryTable annotasyonundan yararlanabiliriz. Embeddable bileşene ait sütunlar burada ikincil tabloda yer alacaklardır.
Bir sonraki yazımızda M:1 ilişkilerin yönetimi ile devam edeceğiz.