SORU
14 Mayıs 2012, PAZARTESİ


Web isteği başına bir DbContext... neden?

Varlık Çerçevesi kurmak için nasıl açıklayan tek oluşturulan DbContext. bir sürü makale okuyorum ve başına HTTP web request çeşitli Dİ çerçeveler kullanılmış.

Neden bu ilk etapta iyi bir fikir mi? Avantajları bu yaklaşım kullanarak elinize ne geçer? Bu iyi bir fikir bazı durumlarda var? DbContexts başına depo yöntemi çağrısı başlatmasını yapamazsın bu tekniği kullanarak yapabileceğiniz şeyler var mı?

CEVAP
14 Mayıs 2012, PAZARTESİ


NOT: Bu yanıt, Varlık Çerçevesi hakkında konuşuyor DbContext ama Çalışmaları uygulama Birimi, gibi herhangi bir tür için geçerlidir SQL bu SERİ DataContext ve ISession Arabiriminin.

Ian tekrarlayarak başlayalım: tüm uygulama için DbContext Bir tek Olması Kötü bir Fikir. Bu mantıklı başka bir durum tek iş parçacıklı bir uygulama, sadece tek bir uygulama örneği tarafından kullanılan bir veritabanı varsa. DbContext iş parçacığı için güvenli değil Ve ve DbContext verileri önbelleğe alır beri, bayat yakında alır. Bu uygulamalar/çoklu kullanıcıların veritabanı üzerinde aynı anda tabii ki çok yaygın olan) çalışırken sorun her türlü olur. Ama sen bunu zaten biliyor ve sadece yeni bir örneği (geçici bir yaşam tarzı ile yani ihtiyacı olan herkes için içine DbContext enjekte etmek için değil nedenini öğrenmek istiyorum bekliyorum. (iplik - kötü, başına DbContext -hatta tek bir bağlam this answer okuma neden hakkında daha fazla bilgi için).

Beni geçici olarak DbContext bir kayıt işe yarayabilir söyleyerek başlamak istiyorum, ama genellikle belirli bir kapsam içinde iş söz konusu birim, tek bir örnek istiyorum. Web uygulaması, bir web isteği sınırları üzerinde böyle bir kapsam tanımlamak için pratik olabilir, böylece Başına bir Web İsteği yaşam tarzı. Bu nesnelerin bir bütün set aynı bağlam içinde çalışmasına izin verir. Diğer bir deyişle, aynı iş içinde hareket ediyorlar.

Eğer işlemleri aynı bağlam içinde faaliyet sahip olmanın bir amacı varsa, bu durumda geçici yaşam tarzı, güzel ama dikkat edilmesi gereken birkaç şey vardır:

  • Her nesne kendi kopyasını alır bu yana, Sistemin durumunu değiştiren her sınıf, _context.SaveChanges() (aksi halde değişiklikler kaybolmak istiyorum) araması gerekiyor. Bu kodunuzu karmaşık hale getirebilir, ve ekler kodu için ikinci bir sorumluluk kapsamında kontrol sorumluluğu) ve Single Responsibility Principle ihlalidir.
  • Varlıklar [DbContext tarafından yüklendi kurtardı] asla başka bir sınıfın bağlamında örnek olarak kullanılabilir. çünkü böyle bir sınıf kapsamı bırakın, emin olun. Bu, bu kuruluşlara gerektiğinde de performans sorunlarına neden olabilir onları kimliği ile yeniden yüklemek gerekir, çünkü kod çok karmaşık olabilir.
  • DbContext uygular beri ** 16 yaşında, muhtemelen hala tüm oluşturulan örneklerini Elden çıkarmak istiyorum. Eğer bunu yapmak istiyorsan, temelde iki seçenek var. İş mantığı dışarıdan geçti alır bir nesne sahiplenir, bu durumda context.SaveChanges(), çağrıldıktan sonra aynı yöntem doğru ama onları imha etmek gerekir. İkinci seçenek ise Elden yarattığı tüm örnekleri sınırının Http İsteği, ama bu durumda hala bir çeşit ölçüm için izin kabın biliyorum bu örnekleri çıkarmak lazım Elden.

Başka bir seçenek içindeğilDbContext tüm enjekte. Bunun yerine, mümkün olduğu DbContextFactory yeni bir örnek (geçmişte bu yaklaşımı kullanmak için kullanılır) oluşturmak için enjekte. Bu şekilde iş mantığı açıkça içeriği kontrol eder. Eğer bu gibi görünebilir:

public void SomeOperation()
{
    using (var context = this.contextFactory.CreateNew())
    {
        var entities = this.otherDependency.Operate(
            context, "some value");

        context.Entities.InsertOnSubmit(entities);

        context.SaveChanges();
    }
}

Bu artı yan DbContext açıkça hayatı yönetmek ve kolay ayarlamak için. Aynı zamanda kullanmanıza olanak sağlar tek bir bağlamda belli bir kapsamı olan net avantaj gibi çalışan kod tek bir iş işlem, ve mümkün geçmek varlıklar, çünkü köken aynı DbContext.

Olumsuz yöntem Enjeksiyon adlandırılır) DbContext yöntemi geçmek zorunda kalacak. Bir anlamda bu çözümün 'kapsamlı' bir yaklaşım, ama şimdi kapsam uygulama kodu (ve muhtemelen pek çok kez tekrar edilir. aynı olduğunu unutmayın Ve iş birimi oluşturmak yardımcı olduğu için sorumlu olan uygulamadır. Beri DbContext yarattıktan sonra bağımlılık grafiği oluşturulur, Yapıcı Enjeksiyon dışında resmi ve ihtiyacınız için erteleme Yöntemi Enjeksiyon yaparken ihtiyacınız aktarmak bağlamında bir sınıf için.

Enjeksiyon yöntemi değil, bu kötü, ama ne zaman iş mantığı alır daha karmaşık ve daha fazla sınıfları yer almak, sen-ecek var pas yöntem için yöntem ve sınıftan sınıfa, karmaşık kod (çok şey gördüm bu geçmişte). Basit bir uygulama için, bu yaklaşım iyi gelir.

Çünkü bu olumsuzlukları, bu fabrika yaklaşımı için daha büyük sistemler, başka bir yaklaşım yararlı olabilir ve bu senin izin bu konteyneri veya altyapı kodu / Composition Root yönetmek birimin çalışma. Bu soru hakkında tarzıdır.

İzin vererek konteyner ve/veya altyapı kolu bu uygulama kod değil kirli tarafından sahip oluşturmak için, (isteğe bağlı olarak) işlemek ve Elden bir Muğla örneği, tutar bu iş mantığı basit ve temiz (sadece bir Tek Sorumluluk). Bu yaklaşım ile bazı zorluklar vardır. Örneğin, Kaydedilmeye ve örnek Atmayın?

İş birimini elden web isteği sonunda yapılabilir. Ancak birçok kişi,yanlışbu da iş birimi Taahhüt yer olduğunu varsayalım. Ancak, uygulamada bu noktada, sadece iş birimi aslında kararlı olmak gerek orası kesin belirleyemez. Eğer iş katmanı kod çağrı yığını daha yüksek yakalanmış olduğunu bir istisna attı, kesinlikle tavsiye ediliryokİşlemek istiyorum.

Gerçek çözüm yine açıkça kapsam çeşit yönetmek için, ama bu sefer Kompozisyon Kök içinde yap. command / handler pattern arkasında tüm iş mantığı özetleme bunu yapmak için izin veren her komut işleyicisi sarılı bir dekoratör yazmak mümkün olacak. Örnek:

class TransactionalCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    readonly DbContext context;
    readonly ICommandHandler<TCommand> decorated;

    public TransactionCommandHandlerDecorator(
        DbContext context,
        ICommandHandler<TCommand> decorated)
    {
        this.context = context;
        this.decorated = decorated;
    }

    public void Handle(TCommand command)
    {
        this.decorated.Handle(command);

        context.SaveChanges();
    } 
}

Bu sadece bu altyapı kodu bir kere yazmak gerekiyor sağlar. Herhangi bir katı Dİ konteyner tutarlı bir şekilde ICommandHandler<T> tüm uygulamaları sarılı olmak böyle bir dekoratör yapılandırmanızı sağlar.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • DJPixcell

    DJPixcell

    20 NİSAN 2007
  • Michelle Phan

    Michelle Pha

    18 Temmuz 2006
  • Simon Hayter

    Simon Hayter

    20 HAZİRAN 2010