Yanıtlar:
Havuz Katmanı, veri erişimi üzerinde ek düzeyde soyutlama sağlar. Yazmak yerine
var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();
veritabanından tek bir öğe almak için depo arabirimini kullanırsınız
public interface IRepository<T>
{
IQueryable<T> List();
bool Create(T item);
bool Delete(int id);
T Get(int id);
bool SaveChanges();
}
ve arayın Get(id)
. Havuz katmanı temel CRUD işlemlerini ortaya koyar .
Hizmet katmanı, depo kullanan iş mantığını ortaya çıkarır. Örnek hizmet şöyle görünebilir:
public interface IUserService
{
User GetByUserName(string userName);
string GetUserNameByEmail(string email);
bool EditBasicUserData(User user);
User GetUserByID(int id);
bool DeleteUser(int id);
IQueryable<User> ListUsers();
bool ChangePassword(string userName, string newPassword);
bool SendPasswordReminder(string userName);
bool RegisterNewUser(RegisterNewUserModel model);
}
İken List()
tüm kullanıcılar, depo getiri yöntemi ListUsers()
IUserService sadece olanları geri dönebilirler, kullanıcı erişimi vardır.
ASP.NET MVC + EF + SQL SUNUCU, ben bu iletişim akışı var:
Görünümler <- Denetleyiciler -> Hizmet katmanı -> Depo katmanı -> EF -> SQL Server
Servis katmanı -> Depo katmanı -> EF Bu bölüm modellerde çalışır.
Görünümler <- Kontrolörler -> Servis katmanı Bu bölüm görünüm modellerinde çalışır.
DÜZENLE:
/ Orders / ByClient / 5 için akış örneği (belirli bir müşteri için siparişi görmek istiyoruz):
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService; // injected by IOC container
}
public ActionResult ByClient(int id)
{
var model = _orderService.GetByClient(id);
return View(model);
}
}
Bu sipariş servisi için arayüz:
public interface IOrderService
{
OrdersByClientViewModel GetByClient(int id);
}
Bu arayüz görünüm modelini döndürür:
public class OrdersByClientViewModel
{
CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
IEnumerable<OrderViewModel> Orders { get; set; }
}
Bu arayüz uygulamasıdır. Görünüm modeli oluşturmak için model sınıflarını ve havuzu kullanır:
public class OrderService : IOrderService
{
IRepository<Client> _clientRepository;
public OrderService(IRepository<Client> clientRepository)
{
_clientRepository = clientRepository; //injected
}
public OrdersByClientViewModel GetByClient(int id)
{
return _clientRepository.Get(id).Select(c =>
new OrdersByClientViewModel
{
Cient = new ClientViewModel { ...init with values from c...}
Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...}
}
);
}
}
IRepository<>
etmek GenericRepository<>
için IOC kütüphanede. Bu cevap çok eski. Bence en iyi çözüm, tüm depoları bir sınıfta birleştirmektir UnitOfWork
. Her türden depo ve denilen bir yöntem içermelidir SaveChanges
. Tüm depolar bir EF bağlamını paylaşmalıdır.
Carnotaurus'un dediği gibi, depo, verilerinizi depolama biçiminden iş nesnelerinize eşlemekten sorumludur. Depolama biriminden hem depolama alanına hem de veri okuma ve yazma (silme, güncelleme) işlemlerini gerçekleştirmelidir.
Hizmet katmanının amacı ise, kodun yeniden kullanımını ve endişelerin ayrılmasını teşvik etmek için iş mantığını tek bir yerde kapsüllemektir. Asp.net MVC siteleri inşa ederken bu benim için pratikte benim için ne anlama geliyor
[Denetleyici], [depoyu] arayan [Hizmetleri] çağırır
Yararlı bulduğum bir ilke, kontrolörlerde ve depolarda mantığı minimumda tutmaktır.
Kontrolörlerde beni KURU tutmaya yardımcı olduğu için. Aynı filtreyi veya mantığı başka bir yerde kullanmam çok yaygındır ve denetleyiciye yerleştirirsem yeniden kullanamam.
Depolarda, daha iyi bir şey ortaya çıktığında depolama alanımı (veya ORM) değiştirebilmek istiyorum. Havuzda mantığım varsa, depoyu değiştirdiğimde bu mantığı yeniden yazmam gerekiyor. Depom yalnızca IQueryable döndürürse ve hizmet filtrelemeyi diğer yandan yaparsa, yalnızca eşlemeleri değiştirmem gerekir.
Örneğin, kısa bir süre önce Linq-To-Sql depolarımın birkaçını EF4 ile değiştirdim ve bu ilkeye sadık kaldığım dakikalar birkaç dakika içinde değiştirilebilir. Biraz mantığım olduğunda bunun yerine saatler meselesiydi.
onBeforeBuildBrowseQuery
ve sorguyu değiştirmek için sorgu oluşturucu kullanabilirsiniz düşünüyorum.
Kabul edilen cevap (ve yüzlerce kez onaylanmış) büyük bir kusura sahiptir. Ben yorumda bu noktalamak istedim ama sadece orada 30 şey yorum kadar burada işaret gömülü alacak.
Bu şekilde oluşturulan bir kurumsal uygulamayı devraldım ve ilk tepkim WTH miydi? Servis katmanındaki ViewModels? Sözleşmeyi değiştirmek istemedim çünkü yıllar süren kalkınma süreci içine girmişti, bu yüzden ViewModels'e geri dönmeye devam ettim. Çocuk biz WPF kullanmaya başladığında bir kabusa dönüştü. Biz (devs takımı) hep şunu söylüyordu: Hangi ViewModel? Gerçek olan (WPF için yazdığımız) veya hizmetler mi? Bir web uygulaması için yazıldılar ve hatta kullanıcı arayüzünde düzenlemeyi devre dışı bırakmak için IsReadOnly bayrağı vardı . Büyük, büyük kusur ve hepsi tek bir kelime yüzünden: ViewModel !!
Aynı hatayı yapmadan önce, yukarıdaki hikayeme ek olarak başka nedenler de var:
Bir ViewModel'i hizmet katmanından döndürmek çok hayır. Bu demek oluyor ki:
Bu hizmetleri kullanmak istiyorsanız, MVVM kullanıyor olmanız daha iyi ve burada kullanmanız gereken ViewModel. Ah!
Hizmetler, bir yerde bir kullanıcı arayüzünde görüntüleneceklerini varsayıyorlar. Web hizmetleri veya windows hizmetleri gibi UI olmayan bir uygulama tarafından kullanılırsa ne olur?
Bu gerçek bir ViewModel bile değil. Gerçek bir ViewModel'de gözlemlenebilirlik, komutlar vb. Vardır. Bu sadece kötü bir ada sahip bir POCO'dur. (İsimlerin neden önemli olduğuna dair yukarıdaki hikayeme bakın.)
Tüketici uygulama daha iyi bir sunum katmanı (ViewModels bu katman tarafından kullanılır) ve C # daha iyi anlamak. Başka Ah!
Lütfen, yapma!
Genellikle varlıklarınızı doldurmak için iskele olarak bir havuz kullanılır - bir hizmet katmanı dışarı çıkar ve bir istek kaynağı oluşturur. Hizmet katmanınızın altına bir depo yerleştirmeniz olasıdır.
Veri havuzu katmanı veritabanına erişmek için uygulanır ve veritabanındaki CRUD işlemlerini genişletmeye yardımcı olur. Hizmet katmanı uygulamanın iş mantığından oluşur ve veri havuzu ile ilgili belirli mantığı uygulamak için depo katmanını kullanabilir. Bir uygulamada, ayrı bir havuz katmanına ve hizmet katmanına sahip olmak daha iyidir. Ayrı depo ve hizmet katmanlarına sahip olmak kodu daha modüler hale getirir ve veritabanını iş mantığından ayırır.