Etki Alanı Nesnesi'nde havuzu kullanmalı mıyım veya Etki Alanı Nesnesini Hizmet Katmanına geri mi aktarmalıyım?


10

Bir işlem komut dosyası dünyasından geldim ve DDD'ye bir göz atmaya başladım. Bir DDD tasarım veritabanı kalıcılığı ile entegre doğru yolu emin değilim. Sahip olduğum şey bu:

Arayüzü Organizasyon etki alanı nesnelerinin örneklerini alma ve kaydetme yöntemleri içeren OrganisationService adlı bir hizmet sınıfı. Kuruluş, toplu bir köküdür ve bununla ilgili başka verileri de vardır: Üyeler ve Lisanslar. EF6 veritabanı önce DBContext, OrganisationService içinde OrganisationDB varlıklarını ve ilgili MemberDB ve LicenseDB varlıklarını almak için kullanılır. OrganisationService tarafından alındığında ve Organization etki alanı nesnesine yüklendiğinde bunların tümü etki alanı nesne sınıfı eşdeğerlerine dönüştürülür. Bu nesne şöyle görünür:

public class Organisation
{
    public IList<Member> Members { get; set; }
    public IList<License> Licenses { get; set; }
}

OrganisationService'te Depo desenini kullanmıyorum ... EF6'nın artık depoyu artık gereksiz hale getirdiği anlaşıldığı için EF'i Depo olarak kullanıyorum.

Tasarımın bu noktasında Organizasyon etki alanı nesnesi anemiktir: EF POCO Organizasyon sınıfına benzer. OrganisationService sınıfı bir Havuz'a çok benziyor!

Şimdi mantık eklemeye başlamalıyım. Bu mantık bir Kuruluş Lisanslarının ve Üyelerinin yönetimini içerir. Şimdi işlem komut dosyası günlerinde OrganisationService'e bu işlemleri yürütmek ve DB ile etkileşim kurmak için bir Depoya çağrı yapmak için yöntemler ekleyeceğim, ancak DDD ile bu mantığın Organization etki alanı nesnesinin içinde kapsüllenmesi gerektiğine inanıyorum ...

Burada ne yapmam gerektiğinden emin değilim: Bu verileri veritabanına geri mantığın bir parçası olarak sürdürmem gerekecek. Bu, bunu yapmak için Organization etki alanı nesnesi içinde DbContext kullanmanız gerektiği anlamına mı geliyor? Etki alanı nesnesinde depo / EF kullanmak kötü bir uygulama mı? Eğer öyleyse, bu kalıcılık nereye aittir?

public class Organisation
{
    public IList<Member> Members { get; set; }
    public IList<License> Licenses { get; set; }

    public void AddLicensesToOrganisation(IList<License> licensesToAdd)
    {
        // Do validation/other stuff/

        // And now Save to the DB???
        using(var context = new EFContext())
        {
            context.Licenses.Add(...
        }

        // Add to the Licenses collection in Memory
        Licenses.AddRange(licensesToAdd);
    }
}

Bunun yerine, yalnızca bellekte Organizasyon etki alanı nesnesini mutasyona uğratmalı ve daha sonra kalıcılık için OrganisationService'e geri itmeli miyim? O zaman nesne üzerinde gerçekte ne değiştiğini takip etmeliyim (EF'in kendi POCO'larına yaptığı şey budur! EF'in sadece bir depo değiştirme değil, aynı zamanda etki alanı katmanı olabileceğini de hissetmeye başlıyorum!)

Buradaki herhangi bir rehberlik takdir edilmektedir.

Yanıtlar:


2

Her iki yaklaşımı da alabilir ve iyi çalışmasını sağlayabilirsiniz - elbette artıları ve eksileri vardır.

Entity Framework kesinlikle etki alanı varlıklarınızı tüketmek için tasarlanmıştır . Etki alanı varlıklarınız ve veri varlıklarınız aynı sınıflar olduğunda iyi çalışır. Değişiklikleri sizin için takip etmek için EF'e güvenebiliyorsanız ve context.SaveChanges()işleminizi bitirdiğinizde arayın . Ayrıca, doğrulama özelliklerinizin bir kez alan modellerinizde ve bir kez de kalıcı varlıklarınızda iki kez ayarlanması gerekmediği anlamına gelir - iş mantığınızdaki gibi [Required]veya [StringLength(x)]kontrol edilebilir , DB işlemi yapın veEntityValidationException. Son olarak, kodlamak hızlıdır - bir eşleme katmanı veya depo yazmanız gerekmez, bunun yerine doğrudan EF bağlamıyla çalışabilirsiniz. Zaten bir depo ve bir iş birimi, bu yüzden ekstra soyutlama katmanları hiçbir şey başaramıyor.

Alan adınızı ve kalıcı varlıkları birleştirmenin bir dezavantajı [NotMapped], mülklerinize dağılmış bir grup özellikle sonuçlanmanızdır . Genellikle, kalıcı verilerde yalnızca get filtreleri olan veya daha sonra iş mantığınızda ayarlanan ve veritabanınıza geri dönmeyen etki alanına özgü özellikler istersiniz. Bazı durumlarda, alan modellerinizdeki verilerinizi bir veritabanıyla iyi çalışmayan bir şekilde ifade etmek istersiniz - örneğin, numaralandırmalar kullanırken, Entity bunları bir intsütuna eşler - ancak belki de eşlemek istersiniz bunları insan tarafından okunabilir hale getirir string, böylece veritabanını incelerken bir aramaya başvurmanız gerekmez. Sonra stringeşlenen bir mülk ile sonuçlanırsınız,enumözelliği olmayan (ancak dize ve enum ile eşleşir) ve her ikisini de gösteren bir API! Benzer şekilde, karmaşık türleri (tabloları) bağlamlar arasında birleştirmek istiyorsanız , sınıfınızda herkese açık olarak gösterilen bir mappedOtherTableId ve eşlenmemiş bir ComplexTypeözellik ile dolabilirsiniz . Bu, projeye aşina olmayan ve alan modellerinizi gereksiz yere şişiren biri için kafa karıştırıcı olabilir.

İş mantığım / alanım ne kadar karmaşıksa, alan adımı ve kalıcı varlıkları birleştirmeyi daha kısıtlayıcı veya hantal buluyorum. Kısa süreleri olan veya karmaşık bir iş katmanı ifade etmeyen projeler için, EF varlıklarını her iki amaç için kullanmanın uygun olduğunu ve alan adınızı kalıcılığınızdan soyutlamaya gerek olmadığını hissediyorum. Maksimum genişleme kolaylığı gerektiren veya çok karmaşık mantığı ifade etmesi gereken projeler için, ikisini ayırmaktan ve ekstra kalıcılık karmaşıklığıyla uğraşmaktan daha iyi olduğunuzu düşünüyorum.

Varlık değişikliklerinizi manuel olarak izleme sorununu önlemenin bir yolu, ilgili kalıcı varlık kimliğini alan modelinizde saklamaktır. Bu eşleme katmanınız tarafından otomatik olarak doldurulabilir. Ardından, EF'de bir değişikliğe devam etmeniz gerektiğinde, herhangi bir eşleme yapmadan önce ilgili kalıcı varlığı alın . Ardından değişiklikleri eşlediğinizde EF bunları otomatik olarak algılar ve context.SaveChanges()bunları elle izlemek zorunda kalmadan arayabilirsiniz .

public class OrganisationService
{
    public void PersistLicenses(IList<DomainLicenses> licenses) 
    {
        using (var context = new EFContext()) 
        {
            foreach (DomainLicense license in licenses) 
            {
                var persistedLicense = context.Licenses.Find(pl => pl.Id == license.PersistedId);
                MappingService.Map(persistedLicense, license); //Right-left mapping
                context.Update(persistedLicense);
            }
            context.SaveChanges();
        }
    }
}

Farklı yaklaşımları farklı veri karmaşıklığıyla birleştirirken herhangi bir sorun var mı? DB ile iyi eşleşen bir şey varsa, doğrudan EF kullanın. Eğer yapmadığınız bir şey varsa, EF kullanmadan önce bir eşleme / soyutlama uygulayın.
Euphoric

@ Etki alanı ve db'nin farklılıkları eşlemede ele alınabilir. Etki alanını iki kez eklemenin (kalıcı olmayan ve kalıcı olmayan) ve değişiklik izlemeyi elle işlemenin özel durumlar için eşlemeler eklemekten daha az iş olduğu bir kullanım durumunu düşünemiyorum. Beni birine yönlendirebilir misin? (NHibernate kullandığımı varsayalım, belki EF daha sınırlı mı?)
Firo

Çok yararlı, pratik ve bilgilendirici cevap. Cevap olarak işaretleme. Teşekkürler!
MrLane

3

EF6 bilmiyorum ama diğer ORM açıkça bu bağlamda lisans bağlamına eklemek zorunda kalmazsınız, değişiklikleri kaydederken onları algılar. Böylece yöntem

public void AddLicenses(IEnumerable<License> licensesToAdd)
{
    // Do validation/other stuff/
    // Add to the Licenses collection in Memory
    Licenses.AddRange(licensesToAdd);
}

ve etrafındaki kod

var someOrg = Load(orgId);

someOrg.AddLicenses(someLicences);

SaveChanges();

Etki alanı nesnelerim Objeler değil, bu yüzden bunları yalnızca bir Liste olan Lisanslar koleksiyonuna eklemek onu kesmeyecek. Asıl mesele, asıl kalıcılığın olduğu yerde olduğu gibi EF ile ilgili değildir. EF'deki tüm kalıcılık bir bağlam kapsamında olmalıdır. Soru bu nereye ait?
MrLane

2
etki alanı varlıkları ve kalıcı varlıklar aynı olabilir / olmalıdır, aksi takdirde zamanın% 99'unun hiçbir değer katmadığı ve değişiklik izlemenin kaybolacağı başka bir soyutlama katmanı tanıtırsınız.
Firo
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.