Setelah beberapa jawaban yang berguna tentang apakah saya harus menggunakan objek domain atau id unik sebagai parameter metode / fungsi di sini. Identifier vs objek domain sebagai parameter metode , saya memiliki pertanyaan serupa: anggota (diskusi pertanyaan sebelumnya tidak berhasil tutup ini). Apa pro dan kontra menggunakan ID unik sebagai anggota vs objek sebagai anggota. Saya meminta referensi bahasa yang sangat diketik, seperti Scala / C # / Java. Haruskah saya (1)
User( id: Int, CurrentlyReadingBooksId: List[Int])
Book( id: Int, LoanedToId: Int )
atau (2), lebih disukai daripada (1) Setelah melalui: Haruskah kita mendefinisikan tipe untuk semuanya?
User( id: UserId, CurrentlyReadingBooksId: List[ BookId] )
Book( id: BookId, LoanedToId: UserId )
atau (3)
User( id: Int, CurrentlyReadingBooks: List[Book])
Book( id: Int, LoanedTo: User)
Meskipun saya tidak dapat memikirkan manfaat memiliki objek (3), satu manfaat memiliki ID (2) & (1) adalah ketika saya membuat objek Pengguna dari DB, saya tidak harus membuat objek Buku, yang pada gilirannya mungkin bergantung pada objek Pengguna itu sendiri, menciptakan rantai tanpa akhir. Apakah ada solusi umum untuk masalah ini untuk RDBMS dan No-SQL (jika mereka berbeda)?
Berdasarkan beberapa jawaban sejauh ini, ulangi pertanyaan saya: (dengan menggunakan ID yang seharusnya dalam tipe terbungkus) 1) Selalu menggunakan ID? 2) Selalu menggunakan Objek? 3) Gunakan ID ketika ada risiko rekursi dalam serialisasi dan deserialisasi, tetapi menggunakan objek sebaliknya? 4) Ada lagi?
EDIT: Jika Anda menjawab bahwa Objek harus selalu digunakan atau untuk beberapa kasus, pastikan untuk menjawab kekhawatiran terbesar yang telah diposting penjawab lain => Cara mendapatkan data dari DB
sumber
Jawaban:
Objek Domain sebagai id membuat beberapa masalah kompleks / halus:
Serialisasi / Deserialisasi
Jika Anda menyimpan objek sebagai kunci, itu akan membuat serialisasi objek grafik menjadi sangat rumit. Anda akan mendapatkan
stackoverflow
kesalahan saat melakukan serialisasi naif ke JSON atau XML karena rekursi. Anda kemudian harus menulis serializer khusus yang mengubah objek aktual untuk menggunakan id mereka alih-alih membuat serialisasi objek contoh dan membuat rekursi.Lewati objek untuk keamanan tipe tetapi hanya menyimpan id, maka Anda dapat memiliki metode pengakses yang malas memuat entitas terkait ketika dipanggil. Caching tingkat kedua akan menangani panggilan berikutnya.
Kebocoran referensi halus:
Jika Anda menggunakan objek domain dalam konstruktor seperti yang Anda miliki di sana, Anda akan membuat referensi melingkar yang akan sangat sulit untuk memungkinkan memori direklamasi untuk objek yang tidak digunakan secara aktif.
Situasi yang ideal:
Id buram vs int / panjang:
Seorang
id
harus merupakan pengidentifikasi yang sepenuhnya buram yang tidak membawa informasi tentang apa yang diidentifikasi. Tetapi harus menawarkan beberapa verifikasi bahwa itu adalah pengidentifikasi yang valid dalam sistemnya.Jenis mentah mematahkan ini:
int
,long
danString
merupakan jenis mentah yang paling umum digunakan untuk pengidentifikasi dalam sistem RDBMS. Ada sejarah panjang alasan praktis yang berasal dari dekade dan mereka semua adalah kompromi yang cocok dengan tabunganspace
atau tabungantime
atau keduanya.Id berurutan adalah pelanggar terburuk:
Saat Anda menggunakan id berurutan, Anda mengemas informasi semantik temporal ke dalam id secara default. Yang tidak buruk sampai digunakan. Ketika orang mulai menulis logika bisnis yang menyortir atau memfilter pada kualitas semantik id, maka mereka membuat dunia kesakitan bagi para pengelola masa depan.
String
bidang yang bermasalah karena desainer naif akan mengemas informasi ke dalam konten, biasanya semantik temporal juga.Ini membuat tidak mungkin untuk menciptakan sebuah sistem data terdistribusi juga, karena
12437379123
ini tidak unik global. Peluang bahwa node lain dalam sistem terdistribusi akan membuat catatan dengan nomor yang sama dijamin cukup banyak ketika Anda mendapatkan cukup data dalam suatu sistem.Kemudian retas mulai bekerja di sekitarnya dan semuanya berubah menjadi tumpukan kekacauan mengepul.
Mengabaikan sistem terdistribusi besar ( cluster ) itu menjadi mimpi buruk lengkap ketika Anda mulai mencoba untuk berbagi data dengan sistem lain juga. Terutama ketika sistem lain tidak di bawah kendali Anda.
Anda berakhir dengan masalah yang sama persis, bagaimana membuat id Anda unik secara global.
UUID dibuat dan distandarisasi karena suatu alasan:
UUID
dapat mengalami semua masalah yang tercantum di atas tergantung pada yangVersion
Anda gunakan.Version 1
menggunakan alamat MAC dan waktu untuk membuat id unik. Ini buruk karena membawa informasi semantik tentang lokasi dan waktu. Itu sendiri bukan masalah, itu adalah ketika pengembang naif mulai mengandalkan informasi itu untuk logika bisnis. Ini juga membocorkan informasi yang dapat dieksploitasi dalam setiap upaya intrusi.Version 2
menggunakan penggunaUID
atauGID
dan domianUID
atauGUI
sebagai pengganti waktu dariVersion 1
ini sama buruknya denganVersion 1
kebocoran data dan mempertaruhkan informasi ini untuk digunakan dalam logika bisnis.Version 3
serupa tetapi menggantikan alamat MAC dan waktu denganMD5
hash dari beberapa arraybyte[]
dari sesuatu yang pasti memiliki makna semantik. Tidak ada kebocoran data yang perlu dikhawatirkan,byte[]
tidak dapat dipulihkan dariUUID
. Ini memberi Anda cara yang baik untuk secara deterministik membuatUUID
bentuk instance dan kunci eksternal semacam itu.Version 4
didasarkan hanya pada angka acak yang merupakan solusi yang baik, sama sekali tidak membawa informasi semantik, tetapi tidak secara deterministik dapat diciptakan kembali.Version 5
hanya sukaVersion 4
tetapi menggunakansha1
bukanmd5
.Kunci Domain dan Kunci Data Transaksional
Preferensi saya untuk id objek domain, adalah menggunakan
Version 5
atauVersion 3
jika dibatasi menggunakanVersion 5
karena beberapa alasan teknis.Version 3
sangat bagus untuk data transaksi yang mungkin tersebar di banyak mesin.Kecuali jika Anda dibatasi oleh ruang, gunakan UUID:
Mereka dijamin unik, membuang data dari satu database dan memuat ulang ke yang lain Anda tidak perlu khawatir tentang duplikat id yang sebenarnya referensi data domain yang berbeda.
Version 3,4,5
benar-benar buram dan begitulah seharusnya.Anda dapat memiliki satu kolom sebagai kunci utama dengan
UUID
dan kemudian Anda dapat memiliki indeks unik gabungan untuk apa yang seharusnya menjadi kunci primer komposit alami.Penyimpanan juga tidak harus
CHAR(36)
. Anda dapat menyimpanUUID
dalam byte asli / bit / angka bidang untuk database yang diberikan selama masih dapat diindeks.Warisan
Jika Anda memiliki tipe mentah dan tidak bisa mengubahnya, Anda masih bisa mengabstraksikannya dalam kode Anda.
Menggunakan salah satu
Version 3/5
dariUUID
Anda dapat lulus dalamClass.getName()
+String.valueOf(int)
sebagaibyte[]
dan memiliki kunci referensi buram yang dapat dipulihkan dan ditentukan.sumber
C-> A -> B -> A
danB
dimasukkan ke dalam masaCollection
ituA
dan semua anak-anaknya masih dapat dijangkau, hal-hal ini tidak sepenuhnya jelas dan dapat menyebabkan kebocoran halus .GC
adalah yang paling sedikit dari masalah, serialisasi dan deserialisasi grafik adalah mimpi buruk kompleksitas.Ya, ada manfaatnya, dan ada juga kompromi.
List<int>
:User
Users
tabelList<Book>
:Jika Anda tidak memiliki masalah memori atau CPU yang akan saya ikuti
List<Book>
, kode yang menggunakanUser
instance akan lebih bersih.Kompromi:
Saat menggunakan Linq2SQL, kode yang dihasilkan untuk entitas Pengguna akan memiliki
EntitySet<Book>
yang dimuat malas ketika Anda mengaksesnya. Ini harus menjaga kode Anda tetap bersih dan instance Pengguna kecil (jejak memori bijaksana).sumber
Aturan praktis yang singkat dan sederhana:
ID digunakan dalam DTO s.
Referensi objek biasanya digunakan dalam Logika Domain / Logika Bisnis dan objek lapisan UI.
Itulah arsitektur umum dalam proyek-proyek yang lebih besar dan cukup kuat. Anda akan memiliki pemetaan yang menerjemahkan ke sana ke mari dari dua jenis objek ini.
sumber
BookRepository
danUserRepository
. Anda akan selalu memanggilmyRepository.GetById(...)
atau serupa, dan repositori akan membuat objek dan memuat nilainya dari penyimpanan data, atau mendapatkannya dari cache. Juga, objek anak-anak sebagian besar malas dimuat, yang juga mencegah harus berurusan dengan referensi melingkar langsung pada waktu konstruksi.