2012-03-09 40 views
5

編輯ASP.NET MVC設計模式:DI,倉庫,服務層

我應該把服務層和庫層進入一個項目,所以web項目能夠參考的DbContext對象?現在我的Web(控制器)無法引用dbcontext對象。什麼是正確的方式?

// service and repository are together 
(View <- Controller) -> (Service -> Repository -> EF DbContext) -> (DB) 
// separate service and repository layer 
(View <- Controller) -> (Service) -> (Repository -> EF DbContext) -> (DB) 

下面是原來的問題

我就知道這麼是一個很好的社區張貼我對MVC設計模式的問題。請給我你的建議,我會感謝你的幫助。謝謝!

我們正在計劃一個新項目,我們的重點是開發一個可擴展和鬆散耦合的應用程序。

我是軟件開發新手;我做了一些關於MVC Music Store Tutorial的閱讀,後面跟着一本書叫Pro ASP.NET MVC 3 Framework by Steven Sanderson (Apress)。從這本書中,我瞭解了DDD(域驅動設計)和其他一些概念,如存儲庫和依賴注入。我跟着這本書建立了SportsStore網站,並對DI有了一些基本的瞭解。但是我個人認爲這個例子並沒有將業務邏輯層分開,所以我對此做了一個研究,我找到了一個叫做Service Layer Pattern的模式,並且從我的理解中,它分離出了業務邏輯層。基於此,我爲我的新項目推出了一個結構(下面的示例項目)。

我需要實現IDisposable接口嗎?如果是的話,在哪裏和爲什麼? 這個結構對於一個相對較大規模的項目是否可行?

示例數據庫設計:產品(一個)----(多)ProductCategoryRs(許多)----(一個)範疇

該解決方案包含3個項目:資源庫,服務,網絡

存儲庫:

定義IRepository接口,基本的CRUD操作

這些簽名是否足夠?我應該添加TEntity GetById(object id);

public interface IRepository<TEntity> 
{ 
    IQueryable<TEntity> All { get; } 
    void Create(TEntity item); 
    void Update(TEntity item); 
    void Delete(TEntity item); 
    void SaveChanges(); 
} 

實現通用庫類

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class 
{ 
    STOREEntities context; 
    public Repository() 
    { 
     context = new STOREEntities(); 
    } 
    public IQueryable<TEntity> All 
    { 
     get 
     { 
      return context.Set<TEntity>(); 
     } 
    } 
    public void Create(TEntity item) 
    { 
     context.Set<TEntity>().Add(item); 
    } 
    public void Update(TEntity item) 
    { 
     context.Entry<TEntity>(item).State = System.Data.EntityState.Modified; 
    } 
    public void Delete(TEntity item) 
    { 
     context.Set<TEntity>().Remove(item); 
    } 
    public void SaveChanges() 
    { 
     context.SaveChanges(); 
    } 
} 

服務: 定義IProductService界面,在這裏擴展業務邏輯。

public interface IProductService 
{ 
    IEnumerable<Product> Products { get; } 
    IEnumerable<Product> Get(Expression<Func<Product, Boolean>> filter); 
    Product GetByProductId(int productId); 
    void AddProduct(Product product); 
    void EditProduct(Product product); 
    void RemoveProduct(Product product); 
    void SaveChanges(); 
} 

實施產品服務

public class ProductService : IProductService 
{ 
    IRepository<Product> repository; //Inject 
    public ProductService(IRepository<Product> repo) 
    { 
     repository = repo; 
    } 
    public IEnumerable<Product> Products 
    { 
     get { return repository.All; } 
    } 
    public IEnumerable<Product> Get(Expression<Func<Product, bool>> filter) 
    { 
     return repository.All.Where(filter); 
    } 
    public Product GetByProductId(int productId) 
    { 
     return repository.All.SingleOrDefault(p => p.ProductID == productId); 
    } 
    public void AddProduct(Product product) 
    { 
     repository.Create(product); 
    } 
    public void EditProduct(Product product) 
    { 
     repository.Update(product); 
    } 
    public void RemoveProduct(Product product) 
    { 
     repository.Delete(product); 
    } 
    public void SaveChanges() 
    { 
     repository.SaveChanges(); 
    } 
} 

Web項目,檢索服務數據,並轉換爲視圖模型和顯示。 ProductController的代碼

public class ProductController : Controller 
{ 
    IProductService productService; //inject 
    public ProductController(IProductService service) 
    { 
     productService = service; 
    } 
    public ActionResult Index() 
    { 
     var products = productService.Products; //retrieve from service layer 
     return View(products); 
    } 
} 

回答

2

我相信你真的應該添加TEntity GetById(int id)IRepository<TEntity>通用接口。

爲什麼?因爲如果你不這樣做,如果你想你的業務層上取一個記錄,你只有兩個選擇(倉庫,數據訪問層):

  1. 返回一個完整的,「unlazy」收集,這意味着您將返回100,000條記錄以便使用單個記錄。
  2. 返回像IQueryable<TEntity>這樣的懶惰集合,它可以讓您從數據庫中獲取單條記錄,但可能會導致很多nasty side-effects

第一個選項顯然是錯誤的。第二個是有爭議的,但是(除非你的項目讓你成爲一個單一的開發人員,並且你真的真的知道你在做什麼),這可能是漏洞和不安全的。所以,如果你確實需要一個記錄(有時你肯定會這麼做),那麼就應該公開一個方法。

話雖如此,你也應該而不是公開IQueryable<TEntity> All { get; },出於完全相同的原因。改爲使用IEnumerable<TEntity> All { get; },並通過調用context.Set<TEntity>().ToList()來使具體的通用存儲庫類返回實際的集合。

編輯

關於IDisposable接口:

只有兩個(相關的)原因實現IDisposable接口,我能想到的:

  1. 處置非託管資源
  2. 一很酷的方式implementing the RAII pattern

對於您的情況,您可能需要將它用於您的存儲庫實現。請查看this SO question瞭解更多信息。

+0

@null:我會編輯我的答案,請看看它。 – rsenna 2012-03-15 12:42:24

+0

-1,雖然你對GetById有很好的理解,但它不是OP任何問題的答案。 – Levitikon 2013-05-23 12:57:55

+1

@Levitikon:他問了'IDisposable',我回答了。這是1個答案(至少這是我學會計數的方式,不知道你是什麼:P) – rsenna 2013-05-23 14:08:40