【问题标题】:Onion Architecture - Service Layer Responsibility洋葱架构——服务层职责
【发布时间】:2013-06-30 19:27:54
【问题描述】:

我正在学习 Jeffrey Palermo 的 Onion Architecture 已经两个多星期了。我按照this tutorial 创建了一个测试项目。在学习时,我遇到了关于 SO 的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);
     .......
     .......
     .......
}

然后我在Infrastucture.Data 中创建了一个BaseRepository:

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

【问题讨论】:

  • 好像有点不对劲。 UnitOfWork 应该包装您的所有存储库。因此,您对获取存储库的调用应类似于 _unitOfWork.ProductRepository.Find(e =&gt; e.CategoryId == CategoryId).ToList();
  • 是的,我在许多示例中都看到了这种方法,但是您的工作单元将成为一个存储库容器,所有存储库都与工作单元紧密耦合。
  • 一个带有工作单元的存储库的漂亮示例在这里:codeproject.com/Articles/543810/…

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


【解决方案1】:

您设计应用程序的方式还可以...但前提是您的服务将处理其他事情,而不仅仅是包装存储库方法!

始终牢记YAGNI principle 上面写着:

总是在你真正需要的时候实施,绝不是在你预见到你需要它们的时候

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

private readonly IProductRepository _productRepository;

也是一个

private readonly IProductDescriptionService _productDescriptionService;

在这种情况下,在您的存储库之上添加一个服务层确实很有意义。

【讨论】:

  • 太好了。实际上我目前没有在做一个真正的项目。我正在尝试学习洋葱架构。这就是为什么我想知道处理复杂场景的正确方法。
  • 好的。我在 SO 上制作了一堆 Onion related answers。您可能会发现其中一些很有趣。
【解决方案2】:

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

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

【讨论】:

  • 这是一个从简单开始的好建议,感谢您的赞赏。实际上我的具体存储库,即“ProductRepository”里面没有任何东西,这让我担心和怀疑我的项目中是否存在具体的存储库。
  • 如果您遵循这种方法,您可以将 Repository 用作具体类。这是一个通用的存储库模式
【解决方案3】:

虽然在这种情况下,稍后的服务似乎只是一个包装器,但有时您可能需要添加一些业务逻辑或调用两个存储库。假设您有一个名为 CartService 的服务,并且您有一个名为 AddToCart 的方法,您需要在其中首先获取产品,进行一些计算,然后调用 insert 到另一个存储库,如下所示。

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);  
  }
}

更复杂的场景包括调用第三方网络服务等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 2015-03-17
    • 2011-10-09
    • 2012-09-01
    • 2019-04-17
    • 1970-01-01
    • 2021-08-29
    • 2014-10-15
    相关资源
    最近更新 更多