Apakah praktik yang baik untuk menggunakan objek entitas sebagai objek transfer data?

29

Saya bertanya-tanya karena jika demikian, mengapa Entity Framework tidak menawarkan logika untuk membuat objek baru dengan properti yang sama untuk mentransfer data antar lapisan?

Saya menggunakan objek entitas yang saya hasilkan dengan kerangka kerja entitas.

pengguna2484998
sumber
3
Saya pikir ini adalah pertanyaan yang bagus tapi saya tidak bisa mengatakannya karena sulit dibaca. Saya tidak yakin bagaimana cara memperbaikinya. Harap edit pertanyaan Anda.
candied_orange
1
@CandiedOrange +1, dan itu membuatnya semakin menakutkan karena ini mendapatkan begitu banyak upvotes.
guillaume31

Jawaban:

23

Ini terserah kamu.

Sebagian besar orang akan memberi tahu Anda bahwa itu bukan praktik yang baik tetapi dalam beberapa kasus Anda bisa melakukannya.

EF tidak pernah bermain bagus dengan DDD karena berbagai alasan, tetapi ada dua yang menonjol: Anda tidak dapat memiliki konstruktor berparameter pada entitas Anda dan Anda tidak dapat merangkum koleksi. DDD mengandalkan itu, karena model domain harus mencakup data dan perilaku.

Di satu sisi, EF memaksa Anda untuk memiliki model domain anemia dan dalam hal ini Anda dapat menggunakan entitas sebagai DTO. Anda dapat mengalami beberapa masalah jika Anda menggunakan properti navigasi tetapi Anda bisa membuat serial entitas tersebut dan mengirimkannya melalui kabel. Ini mungkin tidak praktis. Anda harus mengontrol serialisasi untuk setiap entitas yang memiliki properti yang tidak perlu Anda kirim. Cara yang lebih mudah adalah dengan mendesain kelas terpisah yang dirancang khusus untuk transfer data. Perpustakaan seperti AutoMapper dibuat untuk tujuan ini.

Sebagai contoh: Misalkan Anda memiliki kelas yang dipanggil Persondengan definisi berikut:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; get; }

    // plus a bunch of other properties relevant about a person
}

Dengan asumsi Anda ingin menampilkan daftar karyawan di suatu tempat, mungkin praktis untuk mengirim saja Id, FirstNamedan LastName. Tetapi Anda harus mengirim semua properti yang tidak relevan lainnya. Ini bukan masalah besar jika Anda tidak peduli tentang ukuran respons tetapi ide umumnya adalah hanya mengirim data yang relevan. Di sisi lain, Anda dapat merancang API yang mengembalikan daftar orang dan dalam hal itu mengirim semua properti mungkin diperlukan, sehingga masuk akal untuk membuat cerita bersambung dan mengirim entitas. Dalam hal ini, membuat kelas DTO masih bisa diperdebatkan. Beberapa orang suka mencampuradukkan entitas dan DTO, beberapa orang tidak.

Untuk menjawab pertanyaan Anda yang diperbarui, EF adalah ORM. Tugasnya adalah memetakan catatan basis data ke objek dan sebaliknya. Apa yang Anda lakukan dengan benda-benda itu sebelum dan sesudah melewati EF bukan bagian dari keprihatinannya. Seharusnya juga tidak.

devnull
sumber
1
Diringkas secara singkat. Apa perbedaan antara DTO dan POCO? Bukankah mereka hanya menyimpan data?
Laiv
1
@ guillaume31 Anda tidak dapat memiliki model domain sejati tanpa mempertimbangkan kegigihan. Apa gunanya antarmuka publik jika saya dipaksa untuk menggunakan refleksi (belum lagi jenis peretasan lainnya, asalkan properti publik saya didukung oleh bidang pribadi yang bernama berbeda) untuk memuat agregat saya dalam keadaan yang valid? Jika EF tidak memberikan saya infrastruktur untuk menyembunyikan agregat saya dengan menggunakan antarmuka publik mereka maka saya lebih baik menyimpan logika bisnis saya di tempat lain dan membuat domain saya anemia daripada menulis plat boiler tambahan untuk memuatnya dari database.
devnull
1
Jadi, Anda lebih suka membuat seluruh model domain Anda anemia daripada memberi nama pengambil koleksi publik Anda dengan cara yang sama dengan bidang pribadi? (mari kita kesampingkan masalah konstruktor, karena ini paling sering melawan domain di tempat pertama untuk mengekspos konstruktor mengambil semua bidang objek ...)
guillaume31
1
@Konrad dari sini : As of EF Core 2.1, only services known by EF Core can be injected. Support for injecting application services is being considered for a future release.Saya sangat suka memiliki layanan aplikasi yang disuntikkan ke entitas saya.
devnull
1
@Konrad saya akan berhenti menggunakan entitas domain saya sebagai DTO (jika saya menggunakannya dengan cara ini). DTO berguna terlepas dari dukungan EF untuk injeksi layanan.
devnull
8

Tidak, bukan.

Idealnya, DTO akan cocok dengan repositori kegigihan Anda (alias, tabel database Anda).

Tetapi kelas bisnis Anda belum tentu cocok. Anda mungkin perlu kelas tambahan, atau dipisahkan, atau bergabung dengan kelas untuk apa yang Anda miliki dalam database. Jika aplikasi Anda kecil, Anda mungkin tidak benar-benar melihat masalah seperti ini, tetapi dalam aplikasi menengah hingga besar, ini akan sering terjadi.

Hal lain adalah bahwa DTO adalah bagian dari domain apa pun yang berhubungan dengan kegigihan, sementara Layer Bisnis Anda seharusnya tidak tahu apa-apa tentang mereka.

Juan Carlos Eduardo Romaina Ac
sumber
Sebuah Command objek adalah DTO bahwa lapisan bisnis harus tahu sesuatu tentang.
devnull
Saya pikir lapisan bisnis mungkin akan memanggil objek perintah secara tidak langsung, melalui antarmuka. Dan maksud saya DTO seperti pada objek sederhana yang membawa data, tanpa fungsi sama sekali. Saya tidak yakin apakah objek perintah adalah DTO ( martinfowler.com/eaaCatalog/dataTransferObject.html ).
Juan Carlos Eduardo Romaina Ac
1
Biasanya, perintah dipisahkan ke dalam perintah aktual dan penangannya. Perintah berisi data, pawang berisi perilaku. Ketika digunakan seperti ini, bagian perintah hanya berisi data yang diterima dari klien dan bertindak sebagai DTO antara klien dan lapisan bisnis.
devnull
DTO tidak mengalir dari kegigihan ke domain, mereka juga bisa datang dari luar seperti pada data yang datang (pikirkan dalam REST APIs). Seperti yang ditunjukkan oleh devnull, perintah dan acara agak DTO dan mereka ditransfer ke lapisan bisnis. Apakah penangan lapisan bisnis atau tidak tergantung pada desain.
Laiv
4

Ini sebenarnya ide yang sangat buruk. Martin Fowler memiliki artikel tentang DTO Lokal .

Singkat cerita, DTOPola digunakan untuk mentransfer data di luar proses, misalnya melalui kabel dan bukan di antara lapisan dalam proses yang sama.

Constantin Galbenu
sumber
Seperti semua pendekatan pemrograman, tidak ada satu ukuran yang cocok untuk semua, jika tidak kita tidak akan berdebat dan mendiskusikan berbagai pola dan pendekatan dalam setiap aplikasi yang kita bangun, kita hanya akan selalu menggunakan hal yang sama. DTO pada dasarnya hanyalah POPO yang baru saja mereka namai untuk menunjukkan niat. Tidak ada yang menggunakan DTO untuk "mentransfer data" antara misalnya layanan, pengontrol, dan tampilan. Tidak ada apa pun dalam nama atau struktur kelas yang menunjukkan atau membatasi dari mana dan ke data ditransfer
James
4

Tidak, ini praktik yang buruk.

Beberapa alasan:

  1. Bidang entitas baru akan berada di Dto, secara default . Gunakan entitas berarti setiap informasi akan tersedia untuk dikonsumsi secara default. Ini dapat mengarahkan Anda untuk mengekspos informasi yang masuk akal atau, setidaknya, membuat kontrak API Anda meningkat, dengan banyak informasi yang tidak digunakan untuk siapa yang mengkonsumsi API. Tentu saja, Anda dapat mengabaikan bidang menggunakan beberapa penjelasan (seperti @JsonIgnoredari dunia Java), tetapi ini mengarah ke masalah berikutnya ...
  2. Banyak anotasi / ketentuan / kontrol pada entitas . Anda perlu mengontrol apa yang ingin Anda kirim pada Dto, ketika beberapa nama atribut berubah (ini akan memutus kontrak), tambahkan beberapa atribut yang bukan dari entitas, urutan atribut, dll. Segera Anda akan melihat simpel Anda entitas dengan banyak anotasi, bidang tambahan dan setiap kali akan lebih sulit untuk memahami apa yang terjadi.
  3. Kurang fleksibel . Dengan Dto Anda bebas memecah informasi di lebih banyak kelas, mengubah nama atribut, menambahkan atribut baru, dll. Anda tidak dapat melakukan ini dengan mudah dengan entitas sebagai Dto.
  4. Tidak dioptimalkan . Entitas Anda akan selalu lebih besar dari Dto sederhana. Jadi, Anda akan selalu memiliki lebih banyak informasi untuk diabaikan / diserialisasi dan mungkin lebih banyak informasi yang tidak perlu dikirim.
  5. Masalah malas . Menggunakan entitas beberapa kerangka kerja (seperti Hibernate), jika Anda mencoba mengambil beberapa informasi yang tidak dimuat malas di dalam transaksi basis data sebelumnya, proksi ORM tidak akan dilampirkan ke transaksi dan Anda akan menerima semacam "pengecualian malas" hanya untuk memanggil getmetode entitas.

Jadi, lebih mudah dan aman menggunakan semacam alat mapper untuk membantu Anda dalam pekerjaan ini, memetakan bidang entitas ke Dto.

Dherik
sumber
1

Untuk menyelesaikan apa yang dikatakan @Dikerik, masalah utama menggunakan objek entitas sebagai objek transfer data adalah:

  1. Dalam suatu transaksi, Anda mengambil risiko untuk melakukan perubahan yang dilakukan pada entitas Anda karena Anda menggunakannya sebagai DTO (bahkan jika Anda dapat melepaskan entitas sesi dalam transaksi, sebagian besar waktu Anda perlu memeriksa keadaan ini sebelum modifikasi pada entitas Anda-DTO dan pastikan bahwa Anda tidak dalam transaksi atau bahwa sesi telah ditutup jika Anda tidak ingin modifikasi tetap ada).

  2. Ukuran data yang Anda bagikan antara klien dan server: kadang-kadang Anda tidak ingin mengirim semua konten entitas ke klien untuk meminimalkan ukuran respons permintaan. Memisahkan DTO dari entitas lebih fleksibel, sehingga untuk mengkhususkan data yang ingin Anda kirim dalam kasus penggunaan tertentu.

  3. Visibilitas dan pemeliharaan: Anda harus mengelola jpa / hibernasi anotasi pada bidang entitas Anda dan mempertahankan anotasi jackson untuk diserialisasi dalam json di tempat yang sama (bahkan jika Anda dapat memisahkannya dari implementasi entitas dalam menempatkannya di antarmuka yang diwarisi oleh kesatuan). Kemudian, jika Anda mengubah konten DTO Anda dalam menambahkan bidang baru, orang lain mungkin bisa berpikir bahwa itu adalah bidang entitas, oleh karena itu bidang tabel yang bersangkutan dalam database Anda (bahkan jika Anda dapat menggunakan @Transientanotasi pada semua bidang DTO Anda untuk kasus ini ..!).

Menurut pendapat saya, itu menciptakan kebisingan ketika Anda membaca entitas, tetapi pendapat saya pasti subjektif.

Charles Vuillecard
sumber