Memakai Named Entity Graph Di simple-jpa 0.7


Salah satu fitur baru pada simple-jpa 0.7 adalah dukungan named entity graph. Fasilitas named entity graph yang sudah ada sejak JPA 2.1 memungkinkan pengguna untuk menentukan apa saja atribut yang akan di-load sesuai dengan kebutuhan. Sebagai contoh, saya memiliki sebuah class Faktur yang memiliki relasi one-to-many dengan ItemFaktur, Bonus dan Pengiriman. Pada definisi class secara default, semua relasi tersebut akan di-fetch secara LAZY, seperti pada contoh berikut ini:

@DomainClass @Entity @Canonical
class Faktur {

   @NotBlank
   String nomor

   @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
   Set<ItemFaktur> daftarItemFaktur = new HashSet<>()

   @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
   Set<Bonus> daftarBonus = new HashSet<>()

   @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
   Set<Pengiriman> daftarPengiriman = new HashSet<>()

}

Bila saya memakai salah satu atribut di luar transaksi, seperti pada kode program berikut ini:

Faktur faktur = repo.findFakturByNomor("FA-001")
println faktur.daftarItemFaktur

Saya akan memperoleh pesan kesalahan org.hibernate.LazyInitializationException bila memakai provider Hibernate. Hal ini karena atribut yang di-fetch secara LAZY tidak ikut diambil melalui JOIN ke tabel bersangkutan di query SQL.

Salah satu penyelesaian yang mungkin adalah menambahkan FetchType.EAGER pada seluruh asosiasi yang ada. Akan tetapi ini akan menimbulkan masalah kinerja karena query yang diberikan akan melalukan join ke tiga tabel lain (masing-masing untuk ItemFaktur, Bonus dan Pengiriman).

Saya jarang sekali membutuhkan ketiganya secara bersamaan. Pada layar untuk pengiriman, saya hanya membutuhkan ItemFaktur dan Pengiriman. Pada layar untuk bonus, saya hanya membutuhkan ItemFaktur dan Bonus. Oleh sebab itu, saya bisa mendefinisikan dua entity graph, seperti pada contoh berikut ini:

@NamedEntityGraphs([
   @NamedEntityGraph(name="Faktur.Pengiriman", attributeNodes=[
      @NamedAttributeNode("daftarItemFaktur"),
      @NamedAttributeNode("daftarPengiriman")
   ]),
   @NamedEntityGraph(name="Faktur.Bonus", attributeNodes=[
      @NamedAttributeNode("daftarItemBonus"),
      @NamedAttrbiuteNode("daftarPengiriman")
   ])
])
@DomainClass @Entity @Canonical
class Faktur {
   ...
}

Pada deklarasi Faktur di atas, saya membuat dua entity graph yang bernama Faktur.Pengiriman dan Faktur.Bonus.

Saya dapat menambahkan FetchXXX pada dynamic finders simple-jpa untuk memakai salah satu entity graph yang ada. Sebagai contoh, untuk memakai entity graph Faktur.Pengiriman, saya dapat menggunakan kode program seperti:

Faktur faktur = repo.findFakturByNomorFetchPengiriman("FA-001")
println faktur.daftarItemFaktur
println faktur.daftarPengiriman
println faktur.daftarBonus // <-- ERROR: LazyInitializationException

Saya dapat mengakses daftarItemFaktur dan daftarPengiriman dengan baik. Walaupun demikian, tidak terjadi join ke seluruh tabel yang berelasi. Hal ini dapat dibuktikan karena saya tetap mendapatkan kesalahan bila mengakses daftarBonus karena atribut tersebut tidak didefinisikan pada entity graph Faktur.Pengiriman.

Untuk memakai entity graph Faktur.Bonus, saya dapat menggunakan kode program seperti:

Faktur faktur = repo.findFakturByNomorFetchBonus("FA-001")
println faktur.daftarItemFaktur
println faktur.daftarBonus
println faktur.daftarPengiriman // <-- ERROR: LazyInitializationException

Saya dapat mengakses daftarItemFaktur dan daftarBonus dengan baik. Tetapi, saya tidak boleh membaca daftarPengiriman karena atribut tersebut tidak terdaftar pada entity graph Faktur.Bonus.

Karena masih terbilang baru, implementasi named entity graph pada provider Hibernate masih memiliki sedikit masalah terutama bila berhubungan dengan inheritance. Terkadang saya menjumpai masalah seperti Hibernate menghasilkan query invalid yang memiliki klausa CROSS JOIN LEFT JOIN. Untuk mengatasi hal tersebut, sementara ini, saya memakai Hibernate yang telah dimodifikasi dengan mengubah baris yang memakai Hibernate JPA di BuildConfig.groovy menjadi seperti berikut ini:

griffon.project.dependency.resolution = {
   ...
   dependencies {
       runtime "jockihendry:hibernate-entitymanager:4.3.7-EXPERIMENT"
       ...
   }
   ...
}

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: