Secara umum, apakah dianggap praktik yang buruk untuk mengizinkan bidang yang dibuat pengguna dalam database untuk aplikasi web?
Sebagai contoh, saya membuat webapp inventaris rumah untuk istri saya, dan dia akan ingin mendefinisikan bidangnya sendiri untuk item yang berbeda. Saya berencana untuk mengizinkannya membuat kategori item, dan menambahkan "fitur" ke kategori tersebut. Fitur hanya akan menjadi kunci / nilai yang disimpan sebagai string. Dengan begitu jika dia memiliki kategori yang disebut "Audio CD" misalnya, dia bisa menambahkan fitur untuk hal-hal seperti "artis", "trek", dll. Tetapi dalam kategori lain seperti "furnitur", dia bisa menambahkan fitur untuk barang-barang seperti "bahan" "(kayu, plastik, dll). Maka item apa pun bisa menjadi milik satu (atau banyak) kategori, menambahkan fitur-fitur itu ke item.
Saya dapat melihat masalah di mana mencari dengan fitur-fitur ini membutuhkan perbandingan string, tidak ada validasi data, dll. Mengikuti metodologi tangkas, mungkin akan lebih baik jika dia datang dengan kategori dan atribut baru dan saya hanya harus membuat tabel baru saat kita pergi. Dalam contoh saya, ini adalah basis pengguna kecil (2 dari kami) dan jumlah catatan yang dibuat akan kecil, jadi tidak terlalu buruk.
Namun secara umum, bagaimana orang menangani hal seperti ini dalam "kehidupan nyata"?
Jawaban:
Ketika Anda mulai mendapatkan "bidang yang ditentukan pengguna" seperti yang sering ditemukan di pelacak bug, manajemen sumber daya pelanggan, dan alat bisnis serupa adalah bahwa mereka tidak didukung dengan tabel dengan bidang bajillion (jika ya, maka kemungkinan masalah itu sendiri).
Alih-alih apa yang Anda temukan adalah desain tabel Nilai Atribut Entitas dan alat administrasi terkait untuk mengelola atribut yang valid.
Pertimbangkan tabel berikut:
Ini setelah Anda menambahkan beberapa atribut. Alih-alih
attr1
berpura - pura membacaartist
atautracks
ataugenre
atribut apa pun yang dimiliki benda itu. Dan bukannya 5, bagaimana jika itu 50. Jelas itu tidak bisa diatur. Ini juga memerlukan pembaruan model dan pemindahan aplikasi untuk menangani bidang baru. Tidak idealSekarang perhatikan struktur tabel berikut:
Anda mendapatkan barang Anda dengan bidang dasarnya. Anda memiliki dua tabel lagi. Satu dengan atribut. Setiap bidang adalah baris dalam
attr
tabel. Dan kemudian adathing_attr
dengan sepasang kunci asing yang berkaitan kembali kething
meja danattr
meja. Dan ini kemudian memiliki bidang nilai tempat Anda menyimpan nilai bidang apa pun untuk entitas itu nantinya.Dan sekarang Anda punya struktur di mana tabel attr dapat diperbarui saat runtime dan bidang baru dapat ditambahkan (atau dihapus) dengan cepat tanpa dampak signifikan pada keseluruhan aplikasi.
Pertanyaannya sedikit lebih kompleks dan validasi menjadi lebih kompleks juga (baik prosedur tersimpan yang funky atau semua sisi klien). Ini adalah trade off dalam desain.
Pertimbangkan juga situasi di mana suatu hari Anda perlu melakukan migrasi dan Anda kembali ke aplikasi untuk menemukan bahwa sekarang ada setengah lusin atribut atau lebih dari skema yang Anda bagikan pada awalnya. Ini membuat migrasi dan pemutakhiran yang buruk di mana tabel Nilai Atribut Entitas, bila digunakan dengan benar, bisa lebih bersih. (Tidak selalu, tetapi bisa.)
Jika Anda bekerja dengan citarasa yang sesuai dari database nosql, Anda mungkin bisa melakukan ini (perhatikan bahwa citarasa yang tepat dari nosql untuk ini mungkin akan menjadi toko nilai kunci yang, yah, tabel EAV untuk yang berhubungan seperti dijelaskan di atas) tanpa terlalu banyak kesulitan. Namun ia datang dengan semua kompromi untuk nosql yang dijelaskan di tempat lain dengan sangat rinci.
Jika Anda bekerja pada basis data relasional - Anda harus memiliki skema. Menambahkan kolom secara dinamis berarti beberapa bagian dari hal-hal berikut ini benar:
select *
dan kemudian melakukan beberapa kode kompleks untuk mengetahui apa sebenarnya data tersebut (lihat ResultSetMetaData Java ) dan kemudian menyimpannya di peta ( atau tipe data lain - tetapi bidang yang tidak bagus dalam kode). Ini kemudian membuang sedikit jenis dan keamanan kesalahan ketik yang Anda miliki dengan pendekatan tradisional.hasdate
bidang untuk menyimpan stempel waktu telah didefinisikan sebagaihasdate
boolean untuk kecocokan yang berhasil ... dan pemutakhiran Anda rusak.varchar2
vstext
dan sejenisnya. Kode Anda untuk menambahkan kolom akan berfungsi pada MySQL tetapi tidak pada Postgres atau Oracle atau SQL Server.delete * from students
, tetapi Anda tidak dapat mengacaukan database dengan cara yang buruk). Jumlah hal yang bisa salah dengan akses skema baik dari kecelakaan atau meroketnya aktivitas jahat.Ini benar-benar bermuara pada "jangan lakukan itu." Jika Anda benar-benar menginginkan ini, lakukan dengan pola struktur tabel EAV yang diketahui atau database yang sepenuhnya didedikasikan untuk struktur ini. Jangan biarkan orang membuat bidang sembarang dalam tabel. Sakit kepala tidak layak.
sumber
Melakukan ini dengan baik sulit.
Untuk aplikasi satu kali seperti yang Anda rencanakan, Anda tentu saja dapat menambahkan kolom untuk setiap bidang, dan menyediakan UI yang membuat definisi bidang oleh pengguna yang tidak terlatih lebih aman daripada memberi mereka baris perintah SQL. Atau Anda dapat mengikuti pola Entity-Attribute-Value yang ditakuti , yang merupakan respons klasik, jika agak menakutkan, terhadap masalah semacam ini. Membangun UI untuk mendefinisikan bidang EAV biasanya jauh lebih kompleks daripada untuk kolom basis data, dan kueri bisa menjadi sangat berbulu, tetapi untuk sejumlah besar bidang ( yaitu , skema matriks sangat jarang), itu mungkin satu-satunya cara untuk mendapatkan pekerjaan selesai.
sumber
Saya datang salib beberapa hal serupa baru-baru ini.
Saya membuat 2 tabel.
Dia adalah semua objekmu. U mengatur nama itu.
Dan jenis objek ini: - bagi saya jenis yang tersedia adalah inventaris, inventory_item, kantor.
Dan setup yang biasa adalah n item adalah child atau inventory yang juga child of office dan saya menggunakan tabel join untuk menggabungkan objek satu sama lain
Tabel pengaturan berisi setiap nama bidang untuk jenis objek tertentu, dan nilai nilainya.
Contoh properti kantor
Lokasi, telepon, jam kerja
Dan untuk barang-barang
Dll, semua properti ini diberlakukan oleh model Anda dan disimpan dalam tabel pengaturan sebagai baris terpisah (namun gunakan ganti tidak disisipkan untuk menghindari beberapa baris untuk bidang yang sama)
Jadi kapan pun saya ingin kantor saya memuatnya dengan mudah dengan semua relasi dan pengaturannya di mana pengaturan object_I'd masuk (objek yang diminta)
Setelah itu saya memutar semua baris dari pengaturan dan hanya itu.
Dan jika saya ingin pengaturan menjadi spesifik untuk item dalam inventaris (bukan global) saya atur object_I'd = Saya akan dari tabel hubungan object_objects dan saya atur setting.type = relation_setting
Saya harap Anda mengerti apa yang saya maksud, saya akan mencoba memformat ulang jawaban ketika saya mendapatkan laptop
sumber
Tidak, ini bukan praktik buruk. Ini cukup umum. Dalam istilah OO ini disebut pewarisan. Anda memiliki inventaris item kelas dasar dan dua kelas bawaan AudioCD dan furnitur.
Anda harus memutuskan bagaimana inventaris barang, AudioCD, dan furnitur disimpan dalam basis data.
Jika easy-query paling penting bagi Anda dan db-space / normalisasi tidak masalah Anda akan mengimplementasikan skema "table-per-hierarchy".
Jika ruang / normalisasi paling penting bagi Anda dan pertanyaan yang lebih rumit tidak masalah bagi Anda untuk mengimplementasikan Skema "table-per-type".
Untuk lebih jelasnya lihat dotnet table-per-type-vs-table-per-hierarchy-inheritance atau java hibernate inheritance .
sumber