3

我現在正在學習由Jeffrey Palermo開發的Onion Architecture超過2周。我已按照this tutorial創建了一個測試項目。在學習期間,我遇到了關於SO的this問題。根據接受的答案,一個人nwang建議像GetProductsByCategoryId這樣的方法不應該在存儲庫中,另一方面Dennis Traub 表明它是存儲庫的責任。我做的是:洋蔥體系結構 - 服務層責任

我有一個通用存儲庫中Domain.Interface中,我有一個方法Find

public interface IRepository<TEntity> where TEntity : class 
{ 
    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> filter = null); 
    ....... 
    ....... 
    ....... 
} 

然後,我創建了一個BaseRepositoryInfrastucture.Data

public class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class 
{ 
    internal readonly DbSet<TEntity> dbSet; 
    public virtual IEnumerable<TEntity> Find(
      Expression<Func<TEntity, bool>> filter = null) 
    { 
      IQueryable<TEntity> query = dbSet; 

      if (filter != null) 
      { 
       query = query.Where(filter); 
      } 
      return query.ToList(); 
    } 
} 

而且我有a 混凝土存儲庫 in Infrastructure.Data

public class ProductRepository : RepositoryBase<Product>, IProductRepository 
{ 
     public ProductRepository(MyDBContext context) 
      : base(context) 
     {   

     } 
} 

現在我在服務層正在做的是將服務注入到服務中,並調用Repository.Find來處理類似GetProductsByCategoryId的方法。像:

public class ProductService : IProductService 
{ 
    private readonly IUnitOfWork _unitOfWork; 
    private readonly IProductRepository _productRepository; 

    public ProductService(IUnitOfWork unitOfWork, IProductRepository productRepository) 
    { 
      _unitOfWork = unitOfWork; 
      _productRepository = productRepository; 
    } 

    public IList<Product> GetProductsByCategoryId(int CategoryId) 
    { 
      // At the moment, My code is like this: 
      return _productRepository.Find(e => e.CategoryId == CategoryId).ToList(); 

      // My confusion is here. Am I doing it right or I need to take this code to 
      // ProductRepository and call _productRepositoy.GetProductsByCategoryId(CategoryId) here instead. 
      // If I do this, then Service Layer will become more of a wrapper around repository. Isn't it? 
      // My question is : What exactly will be the responsibility of the Service Layer in Onion Architecture? 
     } 
    } 
+2

有些東西似乎有點過。 UnitOfWork應該包裝所有的倉庫。所以你調用存儲庫應該看起來像'_unitOfWork.ProductRepository.Find(e => e.CategoryId == CategoryId).ToList();' – sunil

+2

是的,我在很多例子中看到了這種方法,但是你的工作單元將成爲存儲庫容器與所有存儲庫緊密耦合到工作單元。 –

+0

存儲庫與工作單元的一個美麗的例子是在這裏:http://www.codeproject.com/Articles/543810/Dependency-Injection-and-Unit-Of-Work-using-Castle –

回答

5

您設計應用程序的方式沒問題......但前提是您的服務將處理其他事情,而不僅僅是整理存儲庫方法!

始終牢記YAGNI principle,上面寫着:

始終貫徹的事情,當你真正需要它們,從來沒有當你只是預見到你需要他們

假設你有一個用戶故事說,只要在數據庫中找不到產品說明,就應該從其他地方(調用外部服務或其他地方)取回產品說明。然後,它似乎很明顯,你ProductService必須有一個

private readonly IProductRepository _productRepository; 

也是一個

private readonly IProductDescriptionService _productDescriptionService; 

在這種情況下真的很有意義在您的倉庫的頂部添加一個服務層。

+0

這太棒了。其實我現在沒有在做一個真正的項目。我正在嘗試學習洋蔥建築。這就是爲什麼我想知道處理複雜場景的正確方法。 –

+2

好的。我在SO上做了一堆[洋蔥相關答案](http://stackoverflow.com/search?q=user:1660523+ [onion-architecture])。你可能會發現其中一些有趣的。 – MaxSC

4

我發現,有時候事情可能會變得過度抽象爲它的緣故,並沒有提供真正的價值。我會說在你的例子中的結構是好的,並正確地遵循模式。您的服務層正確地服務於客戶端UI的需求,它與數據層鬆散耦合,幷包含操作數據所需的任何業務邏輯。

我總是認爲,從簡單和建立在結構上開始,而不是過度抽象,過度複雜和過度膨脹項目會更有成效。商業或技術案例通常會推動項目,並決定是否需要。

+0

這是一個美好的建議,開始簡單並感謝您的讚賞。實際上,我的具體存儲庫即「ProductRepository」中沒有任何內容,這讓我擔心和懷疑項目中存在具體存儲庫。 –

+0

如果你遵循這個方法,你可以使用Repository 作爲具體的類。這是一個通用的存儲庫模式 – Igorek

3

雖然在這種情況下,服務似乎只是一個包裝,但有時您可能需要添加一些業務邏輯或調用兩個存儲庫。假設你有一個名爲CartService的服務,並且你有一個名爲AddToCart的方法,你需要先獲得產品,做一些計算,然後調用插入到下面的另一個倉庫。

public class CartService : ICartService 
{ 
    private readonly IUnitOfWork _unitOfWork; 

    public CartService(IUnitOfWork unitOfWork) 
    { 
     _unitOfWork = unitOfWork; 
    } 

    public void AddToCart (int productId, int quantity) 
    { 
    var product = _unitOfWork.ProductRepository 
           .Find(p => p.ProductId == productId).Single(); 

    var cartItem = new CartItem { 
        ProductId = productId, 
        Desc = product.Desc, 
        Quantity = quantiry 
        }; 

    _unitOfWork.CartRepository.Add(cartItem); 
    } 
} 

更多,複雜的場景包括調用第三方Web服務等