2014-10-26 23 views
8

Günlerdir bununla başımı çarptım ve hala doğru yaklaşımın hangisi olduğuna karar veremiyorum.
Bu soru, özellikle bir web uygulamasının aksine WPF'u hedeflemektedir, birçok yayın ve makale çevrimiçi olarak numaralı (context) yaklaşımı için geçerlidir ve için context değil.
Entity-Framework DB first modelini kullanan bir WPF MVVM uygulamasına sahibim.WPF MVVM uygulamasında DbContext'i yönetme

public partial class User 
{ 
    public User() 
    { 
     this.Role = new HashSet<Role>(); 
    } 

    public string ID { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<Role> Role { get; set; } 
} 

public class Role 
{ 
    public Role() 
    { 
     this.User = new HashSet<User>(); 
    } 

    public int ID { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<User> User { get; set; } 
} 

aşağıdaki bu nasıl ele alınacağı üzerinde seçeneklerimi daralmış ettik:

1)
burada (EF Designer tarafından oluşturulan) Uygulamamda kullanılan iki modelin bir örnektir

public class Dal 
{ 
    public User GetUserById(object userId) 
    { 
     using (var db = new DbEntities()) 
     { 
      return db.User.Find(userId); 
      db.SaveChanges(); 
     } 
    } 

    public void RemoveUser(User userToRemove) 
    { 
     using (var db = new DbEntities()) 
     { 
      db.User.Remove(userToRemove); 
      db.SaveChanges(); 
     } 
    } 
} 

benim 01 kullanabilirsiniz: oluşturur ve her yöntem çağrısı DbContext uzaklaştıran DataAccess sınıf oluşturuluyorşöyle:

Benzer
public class UserManagerViewModel : ObservableObject 
{ 
    private readonly Dal dal = new Dal(); 

    // models... 
    //commands... 
} 

2) 1 yaklaşır, ancak Using ifadeleri olmadan:

public class Dal : IDisposable 
{ 
    private readonly DbEntities db = new DbEntities(); 
    public User GetUserById(object userId) 
    { 
     return db.User.Find(userId); 
     db.SaveChanges(); 

    } 

    public void RemoveUser(User userToRemove) 
    { 
     db.User.Remove(userToRemove); 
     db.SaveChanges(); 
    } 

    public void Dispose() 
    { 
     db.SaveChanges(); 
    } 
} 

kullanım ViewModel

3) içindeki aynıdır Oluştur Her entity için repository. Yukarıdaki seçeneklerle aynı şekilde gözükür (ayrıca using ikilemiyle birlikte veya yok), ancak her depo yalnızca entity ile ilgili yöntemleri içerir.
Afaik kullanımı, yukarıdaki ViewModel benimki ile aynıdır. aşağıdaki gibi

public class UnitOfWork : IDisposable 
{ 
    private DbEntities db = new DbEntities(); 

    private IUserRepository userRepository; 
    public IUserRepository UserRepository 
    { 
     get 
     { 
      return userRepository ?? new UsersRepository(db); 
     } 
    } 

    public void Save() 
    { 
     db.SaveChanges(); 
    } 

    public void Dispose() 
    { 
     db.Dispose(); 
    } 
} 

ve benim ViewModel içinde kullanmak:

4) talep üzerine uygun Repository geçecek bir Unit-Of-Work sınıf oluşturun

public class UserManagerViewModel : ObservableObject 
{ 
    private readonly UnitOfWork unit = new UnitOfWork(); 

    // models... 
    //commands... 
} 

yukarıdaki yaklaşımın hangisi (eğer varsa) eşzamanlılık, daha iyi soyutlama ve katmanlama ve genel performans açısından tercih edilir mi?
DÜZENLEME -this article. aşağıdaki paragraf Bulunan:

Windows Presentation Foundation (WPF) veya Windows Forms ile çalışan, form başına bir bağlam örneğini kullanın. Bu, içeriğin sağladığı değişiklik izleme işlevini kullanmanıza olanak tanır.

Ancak, benim view-model bir DbContext nesne oluşturmak gerekip gerekmediği sorusunu gündeme getiriyor ya da daha iyisini benim DAL sınıf olarak böyle bir yardımcı sınıf var ve onu referans etmektir.

+3

EF, mükemmel bir UoW ​​(içerik) + deposuna (DbSet) sahiptir. Neden kendiniz yaratıyorsunuz? Bu ekstra katmanlar neredeyse hiç işe yaramıyor. EF modeline yakın servislerde kullanım durumlarını kapsayan iş merkezli uygulamaların aksine iş mantığını müşteriye çeken veri merkezli uygulamalara yönelme eğilimindedirler. Veriyi soyutlama ve soyutlama görevleri (soyutlamanın kalıcılığın uygulanmasını gizlediği anlamına gelir). –

+0

Cevabınız için bu http://mehdi.me/ambient-dbcontext-in-ef6/ – ErikEJ

+0

@GertArnold'a bakın. Özellikle 'WPF MVVM' hakkında soru sorduğumdan beri, uzun ömürlü bir 'DbContext' kullanılmalı mıyım (' görünüm 'modeli başına bir' içerik ') veya' bağlamımın ömrünü sınırlandırmalı mıyım? ' seçenek 1 ('kullanarak' kullanarak) :) – Yoav

cevap

2

Bu, bağımlılık enjeksiyon çerçevelerinin çözülmesi için tasarlandığı şeydir. Evet, projenize eklemek için başka bir teknolojidir, ancak DI kullanmaya başladığınızda asla geriye bakmazsınız.

Buradaki asıl sorun, kontrolün tersine çevrilmesi ve kararın daha üst sıralarda yer alması gerektiğinde, bu kararı kendi görüş modellerinde yapmaya çalıştığınızdır. Bir WPF/MVVM uygulaması, bağlam başına bir bağlam isteyecektir, böylece değişiklikler sadece bir kullanıcı düzenleme işlemini tamamladıktan sonra gönderilir ve ayrıca kullanıcıya değişiklikleri iptal etme fırsatı verir. Bunu bir web uygulamasında kullanmadığınızı biliyorum, ancak iyi tasarlanmış bir mimariye göre, bu durumda, istek başına bir bağlam isteyeceksiniz. Veritabanını statik verilerle dolduran bir konsol uygulaması yardımcı programı yazmak isteyebilirsiniz, bu durumda performans ve kullanım kolaylığı için global/singleton içerik isteyebilirsiniz. Son olarak, ünite testlerinizin, muhtemelen test başına dayandığında, bağlamla dalga geçmesi gerekir. Bu vakaların dördü enjeksiyon çerçevenizde kurulmalı ve görüş modelleriniz bunların hiçbirini bilmemeli veya önemsememelidir.

İşte bir örnek. Kişisel olarak .NET için tasarlanmış olan Ninject'i kullanıyorum. Aynı zamanda, ORM'nin seçiminin burada alakasız olmasına rağmen, NHibernate'i tercih ediyorum. Farklı kapsam gereksinimleri vardır oturumu nesneleri var ve bu benim ORM sınıfları başlatır bir Ninject modülünde kurmak alır: Bu bağlam sınıfından NHibernate'in eşdeğer olan bir ISession için kapsam belirleme kurar

var sessionBinding = Bind<ISession>().ToMethod(ctx => 
{ 
    var session = ctx.Kernel.Get<INHibernateSessionFactoryBuilder>() 
     .GetSessionFactory() 
     .OpenSession(); 
    return session; 
}); 

if (this.SingleSession) 
    sessionBinding.InSingletonScope(); 
else if (this.WebSession) 
    sessionBinding.InRequestScope(); 
else 
    sessionBinding.InScope(ScreenScope); 

. otomatik ben kurdum kapsam kuralları kullanarak bu alanı doldurmak için [enjekte] özelliğinin Ninject söyler

public class RepositoryManager : IRepositoryManager 
{ 
    [Inject] 
    public ISession Session { get; set; } 

    ... etc... 
{ 

: bellekteki veritabanı nesnelerini yönetmek Benim depo sınıfları, onlar ile ilişkili oturumda bir başvuru içerir yukarı. Şimdiye kadar bu benim alan sınıflarımda gerçekleşiyor, ama benim görünüm model katmanına da uzanıyor. Kapsam belirleme kurallarında "ScreenScope" adı verilen bir nesneyi iletirim ve buraya girmeyeceğim, temelde ScreenViewModel'deki bir oturum nesnesini veya üye olarak sahip olduğu görünüm modellerini istediğim zaman anlamına gelir. Kendi çocukları da dahil olmak üzere, aynı İşlevi nesnesi otomatik olarak oluşturulur ve hepsine iletilir. DI kapsam belirleme kullanarak Hatta sadece [enjekte] özniteliği ile üyelerini beyan, bunu düşünmek gerekmez ve anı:

public class ScreenViewModel 
{ 
    [Inject] public CustomerService CustomerService { get; set; } 
    [Inject] public SalesService SalesService { get; set; } 
    [Inject] public BillService BillService { get; set; } 
    ...etc... 
} 

Bu servis sınıfları tüm enjekte edilmiş bir RepositoryManager içerir ve Hepsi ScreenViewModel'de olduğu için ISession nesnesi en azından WPF yapmamda aynı olacaktır. MVC derlememe geçersem, belirli bir istek için oluşturulan tüm görünüm modelleri için aynı olurlar ve bir konsol yapısına geçersem, tüm programdaki her şey için aynı İşlevi kullanır.

TL; DR: Bağımlılık enjeksiyonunu kullanın ve içeriklerinizi bir form başına bir kapsam.

+0

UI topoick'de DI üzerinde araştırma yapıyorum ve olay/komut başına içerik yapmak istiyorum (WPF durumunda). Ne yazık ki, bunun nasıl uygulanacağına dair hiçbir fikrim yok: (Gördüğüm tek çözüm, metod argümanları olarak enjeksiyonları geçmek, ama bu oldukça berbat –