Apa cara terbaik untuk menyimpan enum ke dalam database?
Saya tahu Java menyediakan name()
dan valueOf()
metode untuk mengubah nilai enum menjadi String dan kembali. Tetapi apakah ada opsi (fleksibel) lain untuk menyimpan nilai-nilai ini?
Adakah cara cerdas untuk membuat enum menjadi angka unik ( ordinal()
tidak aman digunakan)?
Memperbarui:
Terima kasih untuk semua jawaban yang luar biasa dan cepat! Seperti yang saya duga.
Namun catatan untuk 'toolkit'; Itu salah satu cara. Masalahnya adalah saya harus menambahkan metode yang sama untuk setiap jenis Enum yang saya buat. Itu banyak kode duplikat dan, saat ini, Java tidak mendukung solusi apa pun untuk ini (enum Java tidak dapat memperluas kelas lain).
Jawaban:
Kami tidak pernah lagi menyimpan enumerasi sebagai nilai ordinal numerik; itu membuat proses debug dan dukungan menjadi terlalu sulit. Kami menyimpan nilai pencacahan aktual yang dikonversi ke string:
dan kemudian baca kembali dengan:
Masalahnya adalah di masa lalu saat menatap Manajer Perusahaan dan mencoba menguraikan:
ayat-ayat
yang terakhir jauh lebih mudah. Yang pertama membutuhkan kode sumber dan menemukan nilai-nilai numerik yang diberikan kepada anggota pencacahan.
Ya, ini membutuhkan lebih banyak ruang, tetapi nama anggota pencacahan pendek, dan hard drive murah, dan jauh lebih berharga untuk membantu saat Anda mengalami masalah.
Selain itu, jika Anda menggunakan nilai numerik, Anda terikat padanya. Anda tidak dapat memasukkan atau mengatur ulang anggota dengan baik tanpa harus memaksakan nilai numerik lama. Misalnya, mengubah pencacahan Suit menjadi:
harus menjadi:
untuk mempertahankan nilai numerik warisan yang disimpan dalam database.
Bagaimana mengurutkannya di database
Muncul pertanyaan: katakanlah saya ingin memesan nilai. Beberapa orang mungkin ingin mengurutkannya berdasarkan nilai ordinal enum. Tentu saja, memesan kartu dengan nilai numerik dari pencacahan tidak ada artinya:
Itu bukan urutan yang kami inginkan - kami menginginkannya dalam urutan pencacahan:
Pekerjaan yang sama yang diperlukan jika Anda menyimpan nilai integer diperlukan jika Anda menyimpan string:
Tapi itu bukan urutan yang kami inginkan - kami ingin mereka dalam urutan pencacahan:
Pendapat saya adalah bahwa peringkat semacam ini termasuk dalam antarmuka pengguna. Jika Anda menyortir item berdasarkan nilai pencacahannya: Anda melakukan kesalahan.
Tetapi jika Anda benar-benar ingin melakukannya, saya akan membuat
Suits
tabel dimensi:Dengan cara ini, ketika Anda ingin mengubah kartu Anda untuk menggunakan Kissing Kings New Deck Order, Anda dapat mengubahnya untuk tujuan tampilan tanpa membuang semua data Anda:
Sekarang kami memisahkan detail pemrograman internal (nama enumerasi, nilai enumerasi) dengan pengaturan tampilan yang ditujukan untuk pengguna:
sumber
12.37 ms
alih-alih mengambil12.3702 ms
. Itulah yang saya maksud dengan "dalam kebisingan" . Anda menjalankan kueri lagi dan itu membutuhkan13.29 ms
, atau11.36 ms
. Dengan kata lain, keacakan penjadwal utas akan secara drastis membanjiri pengoptimalan mikro yang secara teoritis Anda miliki yang sama sekali tidak terlihat oleh siapa pun dengan cara apa pun.Kecuali Anda memiliki alasan kinerja tertentu untuk menghindarinya, saya akan merekomendasikan menggunakan tabel terpisah untuk pencacahan. Gunakan integritas kunci asing kecuali pencarian ekstra benar-benar membunuh Anda.
Meja setelan:
Meja pemain
suit_id
) tidak bergantung pada nilai enumerasi Anda, yang membantu Anda mengerjakan data dari bahasa lain juga.sumber
public enum foo {bar}
danCREATE TABLE foo (name varchar);
dapat dengan mudah keluar dari sinkronisasi.Saya berpendapat bahwa satu-satunya mekanisme yang aman di sini adalah menggunakan nilai String
name()
. Saat menulis ke DB, Anda dapat menggunakan sproc untuk memasukkan nilai dan saat membaca, gunakan View. Dengan cara ini, jika enum berubah, ada tingkat tipuan di sproc / view untuk dapat menyajikan data sebagai nilai enum tanpa "memaksakan" ini pada DB.sumber
Seperti yang Anda katakan, ordinal agak berisiko. Pertimbangkan misalnya:
Jika Anda menyimpannya sebagai ordinal, Anda mungkin memiliki baris seperti:
Tetapi apa yang terjadi jika Anda memperbarui Boolean?
Ini berarti semua kebohongan Anda akan disalahartikan sebagai 'file-not-found'
Lebih baik hanya menggunakan representasi string
sumber
Untuk database yang besar, saya enggan kehilangan keunggulan ukuran dan kecepatan representasi numerik. Saya sering berakhir dengan tabel database yang mewakili Enum.
Anda dapat menerapkan konsistensi database dengan mendeklarasikan kunci asing - meskipun dalam beberapa kasus mungkin lebih baik untuk tidak mendeklarasikannya sebagai batasan kunci asing, yang membebankan biaya pada setiap transaksi. Anda dapat memastikan konsistensi dengan melakukan pemeriksaan secara berkala, pada waktu yang Anda pilih, dengan:
Bagian lain dari solusi ini adalah menulis beberapa kode pengujian yang memeriksa bahwa enum Java dan tabel enum database memiliki konten yang sama. Itu tersisa sebagai latihan untuk pembaca.
sumber
enumID
adalah empat byte, jadi Anda memiliki tiga byte tambahan per baris dengan menggunakan nama. 3 byte x 1 juta baris adalah 3MB.enumId
pasti cocok dengan dua byte (enum yang lebih panjang tidak dimungkinkan di Java) dan kebanyakan dari mereka muat dalam satu byte (yang didukung oleh beberapa DB). Ruang yang disimpan dapat diabaikan, tetapi perbandingan yang lebih cepat dan panjang yang tetap akan membantu.Kami hanya menyimpan nama enum itu sendiri - ini lebih mudah dibaca.
Kami bermain-main dengan menyimpan nilai spesifik untuk enum di mana ada sekumpulan nilai terbatas, misalnya, enum ini yang memiliki sekumpulan status terbatas yang kami gunakan untuk mewakili char (lebih bermakna daripada nilai numerik):
dan ketika Anda memiliki banyak nilai, Anda perlu memiliki Peta di dalam enum Anda untuk menjaga metode getFromXYZ tetap kecil.
sumber
Jika menyimpan enum sebagai string dalam database, Anda dapat membuat metode utilitas untuk (de) membuat serialisasi enum apa pun:
sumber
Semua pengalaman saya memberi tahu saya bahwa cara teraman untuk mempertahankan enum di mana saja adalah dengan menggunakan nilai kode tambahan atau id (semacam evolusi dari jawaban @jeebee). Ini bisa menjadi contoh ide yang bagus:
Sekarang Anda dapat menggunakan ketekunan apa pun yang mereferensikan konstanta enum Anda dengan kodenya. Bahkan jika Anda akan memutuskan untuk mengubah beberapa nama konstan, Anda selalu dapat menyimpan nilai kode (misalnya
DWARF("dwarf")
keGNOME("dwarf")
)Oke, selami lebih dalam dengan konsep ini. Berikut adalah beberapa metode utilitas, yang membantu Anda menemukan nilai enum apa pun, tetapi pertama-tama mari kita perluas pendekatan kita.
Dan biarkan enum kita mengimplementasikannya:
Ini adalah waktu untuk metode pencarian ajaib:
Dan gunakan seperti pesona:
Race race = resolveByCode(Race.class, "elf")
sumber
Saya telah menghadapi masalah yang sama di mana tujuan saya adalah untuk mempertahankan nilai Enum String ke dalam database, bukan nilai Ordinal.
Untuk mengatasi masalah ini, saya telah menggunakan
@Enumerated(EnumType.STRING)
dan tujuan saya terselesaikan.Misalnya, Anda memiliki
Enum
Kelas:Di kelas entitas, tentukan
@Enumerated(EnumType.STRING)
:Saat Anda mencoba menyetel nilai Anda ke Database, nilai String akan disimpan ke dalam Database sebagai "
APPLE
", "ORANGE
" atau "LEMON
".sumber
Beberapa nilai dengan relasi OR untuk satu, kolom enum. Konsep untuk .NET dengan menyimpan jenis enum dalam database seperti byte atau int dan menggunakan FlagsAttribute dalam kode Anda.
http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx
sumber
Anda dapat menggunakan nilai tambahan dalam konstanta enum yang dapat bertahan dari perubahan nama dan penggunaan enum:
Untuk mendapatkan id dari enum:
Untuk mendapatkan enum dari id:
Saya menyarankan menggunakan nilai tanpa arti untuk menghindari kebingungan jika nama enum harus diubah.
Dalam contoh di atas, saya telah menggunakan beberapa varian dari "Penomoran baris dasar" meninggalkan spasi sehingga angka tersebut kemungkinan akan tetap dalam urutan yang sama seperti enum.
Versi ini lebih cepat daripada menggunakan tabel sekunder, tetapi membuat sistem lebih bergantung pada kode dan pengetahuan kode sumber.
Untuk mengatasinya, Anda juga dapat menyiapkan tabel dengan id enum di database. Atau pergi ke arah lain dan pilih id untuk enum dari tabel saat Anda menambahkan baris ke dalamnya.
Catatan kecil : Selalu verifikasi bahwa Anda tidak mendesain sesuatu yang harus disimpan dalam tabel database dan dipertahankan sebagai objek biasa. Jika Anda dapat membayangkan bahwa Anda harus menambahkan konstanta baru ke enum pada saat ini, saat Anda menyiapkannya, itu adalah indikasi Anda mungkin lebih baik membuat objek biasa dan tabel sebagai gantinya.
sumber