洋葱架构 - 服务层责任

时间:2013-07-03 07:42:57

标签: asp.net-mvc design-patterns repository-pattern onion-architecture

我正在学习Jeffrey Palermo的Onion Architecture两周多了。我按照this tutorial创建了一个测试项目。在学习期间,我遇到了this问题。根据接受的答案,一个人nwang建议像GetProductsByCategoryId这样的方法不应该在Repository中而另一方面Dennis Traub 表明它是存储库的责任。我在做的是:

我在Domain.Interface中有一个通用存储库,其中我有一个方法Find

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

然后我在BaseRepository中创建了Infrastucture.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();
     }
}

我在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?
         }
    }

3 个答案:

答案 0 :(得分:6)

您设计应用程序的方式是可以的......但只有当您的服务处理其他事情而不仅仅是整理存储库方法时!

始终牢记YAGNI principle说:

  

在您真正需要它们时始终实施,而不是在您预见到需要它们时

假设您有一个用户故事,说每当您的数据库中找不到产品描述时,您应该从其他地方(调用外部服务或其他东西)进行检索。然后很明显你的ProductService必须有一个

private readonly IProductRepository _productRepository;

但也是

private readonly IProductDescriptionService _productDescriptionService;

在这种情况下,在存储库顶部添加服务层确实很有意义。

答案 1 :(得分:5)

我发现,有时事情可能会因为它而被抽象,并没有提供真正的价值。我会说你的例子中的结构很好,并且正确地遵循了模式。正确地说,您的服务层用于满足客户端UI的需求,它与数据层松散耦合,并包含操作数据所需的任何业务逻辑。

我一直认为开始简单构建你的结构比过度抽象,过于复杂和过度膨胀项目更有成效。业务或技术案例通常会推动项目,并决定是否需要。

答案 2 :(得分:4)

虽然在这种情况下,似乎稍后服务只是一个包装器,但有时您可能需要添加一些业务逻辑或调用两个存储库。假设您有一个名为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服务等。