Varlık nesnelerini veri aktarımı nesneleri olarak kullanmak iyi bir uygulama mıdır?


29

Merak ediyorum çünkü öyleyse neden Entity Framework, katmanları arasında veri aktarmak için aynı özelliklere sahip yeni bir nesne oluşturmak için mantık sunmuyor?

Varlık çerçevesini kullanarak ürettiğim varlık nesnelerini kullanırım.


3
Bence bu iyi bir soru ama gerçekten söyleyemem çünkü onu okumak çok zor çünkü nasıl düzelteceğime emin değilim. Lütfen sorunuzu düzenleyin.
candied_orange

1
@CandiedOrange +1, ve bu kadar çok artıracak kadar korkutucu kılar.
guillaume31

Yanıtlar:


23

Sana bağlı.

Çoğu insan size bunun iyi bir uygulama olmadığını söyler, ancak bazı durumlarda bu durumdan kurtulabilirsiniz.

EF, DDD ile hiçbir zaman birçok nedenden ötürü iyi oynamadı, ancak iki öne çıkıyor: varlıklarınızda parametreleştirilmiş yapıcılar olamaz ve koleksiyonları kapatamazsınız. DDD buna bağlıdır, çünkü etki alanı modeli hem veri hem de davranış içermelidir.

Bir şekilde, EF sizi anemik bir etki alanı modeline zorlar ve bu durumda varlıkları DTO'lar olarak kullanabilirsiniz. Navigasyon özelliklerini kullanıyorsanız bazı sorunlarla karşılaşabilirsiniz ancak bu varlıkları seri hale getirip tel üzerinden gönderebilirsiniz. Yine de pratik olmayabilir. Göndermeniz gerekmeyen özelliklere sahip olan her varlık için serileştirmeyi kontrol etmeniz gerekecektir. En kolay yol, basitçe veri aktarımı için uyarlanmış ayrı sınıflar tasarlamaktır. AutoMapper gibi kütüphaneler bu amaç için oluşturulmuştur.

Örneğin: PersonAşağıdaki tanımla adlandırılan bir sınıfınız olduğunu varsayalım :

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
}

Eğer bir yere çalışanların listesini görüntülemek istediğiniz varsayarsak, sadece göndermeye pratik olabilir Id, FirstNameve LastName. Ancak diğer tüm ilgisiz mülkleri göndermeniz gerekir. Cevabın büyüklüğünü umursamıyorsanız, mesele o kadar da büyük değil, ancak genel fikir yalnızca ilgili verileri göndermek. Öte yandan, bir kişi listesi döndüren bir API tasarlayabilir ve bu durumda tüm özellikleri göndermeniz gerekebilir, böylece varlıkları seri hale getirmek ve göndermek mantıklı olabilir. Bu durumda, bir DTO sınıfı oluşturmak tartışılabilir. Bazıları varlıkları ve DTO'ları karıştırmayı sever, bazıları değildir.

Güncellenen sorunuzu yanıtlamak için EF bir ORM'dir. Görevi, veritabanı kayıtlarını nesnelere eşlemektir ve bunun tersi de geçerlidir. EF'den geçmeden önce ve sonra bu nesnelerle yaptıklarınız endişelerinin bir parçası değildir. Olmamalı.


1
Kısaca özetlendi. DTO'lar ve POCO'lar arasındaki farklar nelerdir? Sadece veri tutmuyorlar mı?
Laiv,

1
@ guillaume31 Sürekliliği dikkate almadan gerçek bir etki alanı modeline sahip olamazsınız. Topluluğumu geçerli bir duruma yüklemek için yansıma kullanmaya zorlanırsam (ortak mülkümün farklı bir adla desteklenmiş olması şartıyla başka türden saldırılardan bahsetmemeye gerek yok) genel bir arayüz ne işe yarar? Eğer EF bana genel arayüzleri kullanarak topluluğumu gizlemek için bir altyapı sunmuyorsa, o zaman iş mantığımı başka bir yerde tutmaktan ve etki alanımı veritabanına yüklemek için ek bir kazan plakası yazmak yerine anemik hale getirmekten daha iyi olurum.
devnull

1
Yani, tüm etki alanı modelinizi genel koleksiyonunuzun özel alanla aynı şekilde topladığı ismini vermek yerine anemik yapmak mı istiyorsunuz? (yapıcı problemini bir kenara koyalım, çünkü genellikle nesnenin tüm alanlarını alan bir
guillaume31

1
@Konrad buradan : 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.Uygulamalarımın işletmelerime enjekte edilmesini çok seviyorum.
devnull

1
@Konrad Etki alanı varlıklarımı DTO'lar olarak kullanmayı keserdim (eğer bu şekilde kullanırsam). DTO'lar, EF'in servis enjeksiyonu desteğinden bağımsız olarak faydalıdır.
devnull

8

Hayır öyle değil.

İdeal olarak, DTO'lar kalıcılık depolarınızla eşleşecektir (diğer bir deyişle veritabanı tablolarınız).

Ancak işletme sınıflarınız mutlaka bir eşleşme değildir. Veritabanınızdakilerle ilgili ek sınıflara veya ayrı veya birleştirilmiş sınıflara ihtiyacınız olabilir. Uygulamanız küçükse, bu tür sorunları gerçekten göremeyebilirsiniz, ancak orta ila büyük uygulamalarda bu çok sık olur.

Bir başka şey de, DTO'ların ısrarla uğraşma konusundaki alanın bir parçası olduğu ve İşletme Katmanınız hakkında hiçbir şey bilmemesi gerektiğidir.


Bir Komut nesnesi, iş katmanının hakkında bir şeyler bilmesi gereken bir DTO'dur.
devnull

İş katmanının muhtemelen komut nesnesini bir arabirim aracılığıyla dolaylı olarak arayacağını düşünüyorum. Ve DTO'ları, veri taşıyan basit nesnelerde olduğu gibi, hiç işlevselliği olmayan anlamına gelir. Bir komut nesnesinin DTO olup olmadığından emin değilim ( martinfowler.com/eaaCatalog/dataTransferObject.html ).
Juan Carlos Eduardo Romaina Ac

1
Genellikle, komutlar gerçek komuta ve işleyiciye ayrılır. Komut verileri, işleyici davranışı içerir. Bu şekilde kullanıldığında, komut kısmı yalnızca istemciden alınan verileri içerir ve istemci ile iş katmanı arasında DTO görevi görür.
devnull

DTO, sebattan etki alanına akmaz, ayrıca gelen verilerde olduğu gibi dışarıdan da gelebilir (REST API'lerinde düşünün). Devnull'ın belirttiği gibi, komutlar ve olaylar bir miktar DTO'lar ve iş katmanına aktarılıyor. İşleyicilerin iş katmanı olup olmaması tasarıma bağlıdır.
Laiv

4

Bu aslında çok kötü bir fikir. Martin Fowler'ın Yerel DTO'lar hakkında bir makalesi var .

Uzun lafın kısası, DTOPattern, işlemin dışında, örneğin aynı işlemin içindeki katmanlar arasında değil, örneğin kablo üzerinden veri aktarmak için kullanıldı.


Tüm programlama yaklaşımlarında olduğu gibi, tek bedene uygun bir beden yoktur, aksi takdirde yaptığımız her uygulamada farklı desen ve yaklaşımları tartışmaz ve tartışmazdık, her zaman aynı şeyleri kullanırdık. DTO'lar aslında sadece bir niyeti göstermek için adlandırılmış olan POPO'lardır. Örneğin servis, kontrolör ve görünüm arasında "veri aktarmak" için DTO kullanmanın hiçbir anlamı yoktur. Sınıfların adında veya yapısında, verilerin nerede ve nerede transfer edildiğini belirten veya sınırlayan hiçbir şey yoktur
James

4

Hayır, bu kötü bir uygulama.

Bazı nedenler:

  1. Yeni varlık alanları varsayılan olarak Dto'da olacaktır . Varlığı kullanmak, her bilginin varsayılan olarak tüketilebileceği anlamına gelir. Bu, mantıklı bilgiler açığa çıkarmanıza veya en azından, API'yi tüketen için kullanılmayan pek çok bilgiyle API sözleşmenizi şişirmenize neden olabilir. Elbette, bazı açıklamaları ( @JsonIgnoreJava dünyasında olduğu gibi) kullanarak alanları yok sayabilirsiniz , ancak bu bir sonraki soruna yol açar ...
  2. Varlık üzerinde çok fazla açıklama / koşul / kontrol bulunmaktadır . Dto'da ne göndermek istediğinizi kontrol etmeniz gerekir, bazı nitelik isimleri değiştiğinde (bu sözleşmeyi kıracak), varlıktan olmayan bir özellik, özelliklerin sırasını vb. Ekleyin. Çok fazla ek açıklama içeren, fazladan alanlar ve her seferinde olanları anlamak zor olacaktır.
  3. Daha az esneklik . Bir Dto ile bilgileri daha fazla sınıfta bölmekte, nitelik isimlerini değiştirmekte, yeni nitelikler eklemektedir, vb. Serbest bırakabilirsiniz. Bunu Dto kadar kolay bir şekilde yapamazsınız.
  4. Optimize edilmedi . Varlığınız her zaman basit bir Dto'dan daha büyük olacaktır. Böylece her zaman yok sayılacak / serileştirilecek daha fazla bilgiye ve muhtemelen daha fazla gereksiz bilginin iletilmesine sahip olacaksınız.
  5. Tembel problemler . Bazı çerçevelerin varlığını kullanarak (Hazırda Bekletme gibi), daha önce bir veritabanı işlemine tembel yüklenmemiş olan bazı bilgileri almaya çalışırsanız, ORM proxy işlemi işleme eklenmez ve bir tür "tembel istisna" alırsınız. sadece getişletmenin bir yöntemini çağırmak için .

Bu nedenle, varlık alanlarını Dto ile eşleyerek bu işte size yardımcı olmak için bir tür eşleme aracı kullanmak daha kolay ve güvenlidir.


1

@Dherik’in söylediklerini tamamlamak için, varlık nesnelerini veri aktarma nesneleri olarak kullanmanın temel sorunları şunlardır:

  1. Bir işlemde, bir DTO olarak kullandığınız için varlığınızda yapılan değişiklikleri yapma riskini alırsınız (bir işlemi oturumun varlığından ayırabilseniz bile, çoğu zaman önce bu durumu kontrol etmeniz gerekir) Varlık DTO'nuzdaki herhangi bir değişiklik ve bir işlemde olmadığınızı veya değişikliklerin devam etmesini istemiyorsanız oturumun kapatıldığından emin olun).

  2. İstemci ile sunucu arasında paylaştığınız verilerin boyutu: bazen, isteğin yanıtının boyutunu en aza indirmek için varlığın tüm içeriğini müşteriye göndermek istemezsiniz. DTO'yu varlıktan ayırmak, bazı kullanım durumlarında göndermek istediğiniz verileri özelleştirmek için daha esnektir.

  3. Görünürlük ve bakım: Kurumunuzun alanlarındaki jpa / hazırda bekletme ek açıklamalarınızı yönetmeli ve aynı yerde json'da serileştirmek için jackson ek açıklamalarını korumanız gerekir (bunları kurum tarafından devralınan arabirime yerleştirmek için bunları varlık uygulamasından ayırabilirseniz bile) varlıktır). Ardından, DTO içeriğinizi yeni bir alan ekleyerek değiştirirseniz, başka bir kişi muhtemelen kuruluşun bir alanı olduğunu düşünebilir, bu nedenle veritabanınızla ilgili tablonun bir alanı olabilir ( @Transienttüm DTO alanlarınızda ek açıklama kullanabilseniz bile) Dava için ..!).

Bence, varlığı okuduğunuzda ses çıkarıyor ama benim görüşüm kesinlikle öznel.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.