Panduan Mapping Collection


Artikel ini adalah lanjutan dari tulisan sebelumnya.

Pada tulisan sebelumnya, saya sempat mendefinisikan asosiasi antara Transaksi dan ItemTransaksi dalam bentuk relasi one-to-many.  Sebuah Transaksi dapat memiliki banyak ItemTransaksi yang disimpan dalam bentuk List.  Seperti yang diketahui, sebuah List adalah Collection yang memiliki urutan atau index berupa angka (mirip array).   Akan tetapi saat dibaca kembali dari database, urutan dalam List ini dapat saja berubah karena nilai index tidak disimpan.

Bagaimana bila seandainya saya ingin urutan dalam List tidak berubah dan selalu sama saat dibaca kembali dari database?  Saya perlu mengubah file Transaksi.groovy pada definisi listItemTransaksi menjadi seperti berikut ini (ini adalah versi unidirectional; Hibernate memiliki masalah bila memakai versi bidirectional dengan mappedBy):

@OneToMany @JoinColumn
@OrderColumn
List<ItemTransaksi> listItemTransaksi = []

Sekarang, akan ada sebuah field baru di tabel itemtransaksi, yaitu listItemTransaksi_ORDER.  Field ini akan menampung nilai index sesuai dengan yang ada di List, seperti yang terlihat pada contoh berikut ini:

mysql> select namaItem, listItemTransaksi_id, listItemTransaksi_ORDER from itemtransaksi;
+----------+----------------------+-------------------------+
| namaItem | listItemTransaksi_id | listItemTransaksi_ORDER |
+----------+----------------------+-------------------------+
| ITEM1    |                    1 |                       0 |
| ITEM2    |                    1 |                       1 |
+----------+----------------------+-------------------------+

Nilai yang disimpan ke dalam Collection tidaklah harus selalu berupa sebuah entitas lainnya.  Nilai juga bisa berupa sebuah tipe data native Java misalnya Integer, BigDecimal, atau String.  Sebagai contoh,  saya akan menambahkan daftar prestasi pada Pegawai.groovy sehingga isinya terlihat seperti berikut ini:

@DomainModel @Entity
@TupleConstructor @ToString(excludes = "pajak")
class Pegawai {

    @Size(min=10, max=10)
    String nomorPegawai

    @Size(min=3, max=100)
    String namaLengkap

    @Size(min=5, max=200)
    String alamat

    @OneToOne(cascade=CascadeType.ALL)
    @JoinColumn
    Pajak pajak

    @ElementCollection
    List<String> listPrestasi = []

}

Mapping di atas selain menghasilkan tabel pegawai dan tabel pajak, juga akan membuat sebuah tabel baru yaitu:

mysql> desc pegawai_listprestasi;
+--------------+--------------+------+-----+---------+-------+
| Field        | Type         | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| Pegawai_id   | bigint(20)   | NO   | MUL | NULL    |       |
| listPrestasi | varchar(255) | YES  |     | NULL    |       |
+--------------+--------------+------+-----+---------+-------+

Berikut ini adalah contoh kode program yang menyimpan sebuah Pegawai beserta daftar prestasinya:

Pegawai snake = new Pegawai("PP/01/05-1", "Solid Snake", "Small Ville")
snake.pajak = new Pajak(nomorPokokWajibPajak: "01.718.327.8-091.000", pegawai: snake)
snake.listPrestasi << "Menyelesaikan 1000 bug dalam sehari!"
snake.listPrestasi << "Tidak pernah lembur seharipun!"
snake.listPrestasi << "Tidak pernah membuka situs lain selain Stackoverflow.com selama jam kerja!"
persist(snake)

Setelah menjalankan kode program di atas, isi tabel pegawai_listprestasi akan terlihat seperti berikut ini:

mysql> select * from pegawai_listprestasi;
+------------+----------------------------------------------------------------------------+
| Pegawai_id | listPrestasi                                                               |
+------------+----------------------------------------------------------------------------+
|          1 | Menyelesaikan 1000 bug dalam sehari!                                       |
|          1 | Tidak pernah lembur seharipun!                                             |
|          1 | Tidak pernah membuka situs lain selain Stackoverflow.com selama jam kerja! |
+------------+----------------------------------------------------------------------------+

Collection tidak hanya List tapi juga Map.   Sebagai contoh, berikut ini adalah UML class diagram yang menyimpan harga dalam bentuk BigDecimal di Map:

Contoh Penggunaan Map

Contoh Penggunaan Map

Contoh mapping untuk UML class diagram di atas adalah:

@DomainModel @Entity
@TupleConstructor @ToString
class JenisPekerjaan {

    @Size(min=2, max=2)
    String kode

    @Size(min=3, max=50)
    String nama

    @ElementCollection
    Map<TipeMotor, BigDecimal> mapOngkos

}

@DomainModel @Entity
@TupleConstructor @ToString
class TipeMotor {

    @Size(min=2, max=2)
    String kode

    @Size(min=3, max=50)
    String nama
}

Domain class di atas akan menghasilkan tabel dengan struktur seperti berikut ini:

mysql> desc tipemotor;
+--------------+--------------+------+-----+---------+-------+
| Field        | Type         | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id           | bigint(20)   | NO   | PRI | NULL    |       |
| createdDate  | datetime     | YES  |     | NULL    |       |
| deleted      | varchar(255) | YES  |     | NULL    |       |
| kode         | varchar(5)   | YES  |     | NULL    |       |
| modifiedDate | datetime     | YES  |     | NULL    |       |
| nama         | varchar(50)  | YES  |     | NULL    |       |
+--------------+--------------+------+-----+---------+-------+

mysql> desc jenispekerjaan;
+--------------+--------------+------+-----+---------+-------+
| Field        | Type         | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id           | bigint(20)   | NO   | PRI | NULL    |       |
| createdDate  | datetime     | YES  |     | NULL    |       |
| deleted      | varchar(255) | YES  |     | NULL    |       |
| kode         | varchar(5)   | YES  |     | NULL    |       |
| modifiedDate | datetime     | YES  |     | NULL    |       |
| nama         | varchar(50)  | YES  |     | NULL    |       |
+--------------+--------------+------+-----+---------+-------+

mysql> desc jenispekerjaan_mapongkos;
+-------------------+---------------+------+-----+---------+-------+
| Field             | Type          | Null | Key | Default | Extra |
+-------------------+---------------+------+-----+---------+-------+
| JenisPekerjaan_id | bigint(20)    | NO   | PRI | NULL    |       |
| mapOngkos         | decimal(19,2) | YES  |     | NULL    |       |
| mapOngkos_KEY     | bigint(20)    | NO   | PRI | NULL    |       |
+-------------------+---------------+------+-----+---------+-------+

Contoh kode program yang menyimpan data akan terlihat seperti berikut ini:

TipeMotor supra = new TipeMotor("SA", "Supra 100")
TipeMotor tiger = new TipeMotor("TA", "Tiger")
TipeMotor cbr = new TipeMotor("CB", "CBR Old Type")
persist(supra)
persist(tiger)
persist(cbr)

JenisPekerjaan servisRingan = new JenisPekerjaan("PR", "Servis Ringan", [:])
servisRingan.mapOngkos[supra] = new BigDecimal("23000")
servisRingan.mapOngkos[tiger] = new BigDecimal("35000")
servisRingan.mapOngkos[cbr] = new BigDecimal("50000")
persist(servisRingan)

JenisPekerjaan servisLengkap = new JenisPekerjaan("PL", "Servis Lengkap", [:])
servisLengkap.mapOngkos[supra] = new BigDecimal("35000")
servisLengkap.mapOngkos[tiger] = new BigDecimal("50000")
servisLengkap.mapOngkos[cbr] = new BigDecimal("80000")
persist(servisLengkap)

Kode program di atas akan mengisi tabel sehingga terlihat seperti berikut ini:

mysql> select * from tipemotor;
+----+---------------------+---------+------+--------------+--------------+
| id | createdDate         | deleted | kode | modifiedDate | nama         |
+----+---------------------+---------+------+--------------+--------------+
|  1 | 2013-04-14 12:29:22 | N       | SA   | NULL         | Supra 100    |
|  2 | 2013-04-14 12:29:22 | N       | TA   | NULL         | Tiger        |
|  3 | 2013-04-14 12:29:22 | N       | CB   | NULL         | CBR Old Type |
+----+---------------------+---------+------+--------------+--------------+

mysql> select * from jenispekerjaan;
+----+---------------------+---------+------+--------------+----------------+
| id | createdDate         | deleted | kode | modifiedDate | nama           |
+----+---------------------+---------+------+--------------+----------------+
|  1 | 2013-04-14 12:29:22 | N       | PR   | NULL         | Servis Ringan  |
|  2 | 2013-04-14 12:29:22 | N       | PL   | NULL         | Servis Lengkap |
+----+---------------------+---------+------+--------------+----------------+

mysql> select * from jenispekerjaan_mapongkos;
+-------------------+-----------+---------------+
| JenisPekerjaan_id | mapOngkos | mapOngkos_KEY |
+-------------------+-----------+---------------+
|                 1 |  23000.00 |             1 |
|                 1 |  35000.00 |             2 |
|                 1 |  50000.00 |             3 |
|                 2 |  35000.00 |             1 |
|                 2 |  50000.00 |             2 |
|                 2 |  80000.00 |             3 |
+-------------------+-----------+---------------+

Contoh kode program yang mengakses data di atas adalah:

JenisPekerjaan pekerjaan = findJenisPekerjaanByKode("PR")[0]
println "Ongkos servis ringan untuk CBR adalah ${pekerjaan.mapOngkos[cbr]}"

Hasil dari kode program di atas adalah:

Ongkos servis ringan untuk CBR adalah 50000

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: