我正在学习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?
}
}
答案 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服务等。