我使用Ninject.Extensions.Factory来控制存储库层的生命周期。我希望有一个单一的参照点,从中我可以获得对所有存储库的引用,并让它们懒惰地可用。Ninject Factory方法似乎是一个很好的解决方案,但我对我的解决方案不太确定:
public class PublicUow : IPublicUow
{
private readonly IPublicRepositoriesFactory _publicRepositoriesFactory;
public PublicUow(IPublicRepositoriesFactory publicRepositoriesFactory)
{
_publicRepositoriesFactory = publicRepositoriesFactory;
}
public IContentRepository ContentRepository { get { return _publicRepositoriesFactory.ContentRepository; } }
public ICategoryRepository CategoryRepository { get { return publicRepositoriesFactory.CategoryRepository; } }
}问题在于PublicRepositories类。
public class PublicRepositoriesFactory : IPublicRepositoriesFactory
{
private readonly IContentRepositoryFactory _contentRepositoryFactory;
private readonly ICategoryRepositoryFactory _categoryRepositoryFactory;
public PublicRepositoriesFactory(IContentRepositoryFactory contentRepositoryFactory, ICategoryRepositoryFactory categoryRepositoryFactory)
{
_contentRepositoryFactory = contentRepositoryFactory;
_categoryRepositoryFactory = categoryRepositoryFactory;
}
public IContentRepository ContentRepository { get { return _contentRepositoryFactory.CreateContentRepository(); } }
public ICategoryRepository CategoryRepository { get { return _categoryRepositoryFactory.CreateCategoryRepository(); } }
}我担心,随着存储库数量的增加,这将变得很难管理,这个类在某个时候可能需要在当前实现中使用20-30个构造函数参数。有没有一种方法可以减少ctr参数的数量,比如传递一个接口的数组/字典或类似的东西?
我已经考虑过在这个场景中使用属性注入,但大多数文章建议在一般情况下避免使用属性注入。
是否有一种更普遍的模式可以使这更容易管理?
一般来说,这是一个好办法吗?
发布于 2014-10-15 05:14:49
使用类似这样的存储库接口已成为相当普遍的做法
public interface IRepository
{
T LoadById<T>(Guid id);
void Save<T>(T entity);
....
}而不是像IContentRepository、ICategoryRepository这样的大量特定存储库。
只有在实体类型和操作具有特定逻辑的情况下,特定的存储库才会有用,例如,验证它是否有效。但是这样的操作是一个“方面”,或者是一个直接的关注点,你应该这样做。对保存进行管理/执行验证不应该实现x次,而应该只执行一次。唯一需要具体实现的是确切的验证规则(干的)。但是,这些应该在单独的类中实现,并由组合使用,而不是继承。
此外,对于“基于用例”检索实体或多个实体的内容,您应该使用特定的查询类,而不是将方法放在存储库接口(SRP,SOC)上。GetProductsByOrder(Guid orderId)就是一个例子。这既不应该出现在产品上,也不应该出现在上,而应该放在单独的类中。
更进一步,使用工厂延迟创建所有存储库似乎不是一个好主意。为什么?
查询示例
我对EntityFramework不太熟悉。我更了解NHibernate,所以你看。
public class GetParentCategoriesQuery : IGetParentCategoriesQuery
{
private readonly EntityFrameworkContext context;
public GetParentCategories(EntityFrameworkContext context)
{
this.context = context;
}
public IEnumerable<Category> GetParents(Category child)
{
return this.context.Categories.Where(x => x.Children.Contains(child));
}
}因此,基本上唯一的改变是将GetParentCategoriesQuery提取到它自己的类中。DbContext实例必须与其他查询和存储库实例共享。对于web项目,这是通过绑定DbContext .InRequestScope()来完成的。对于其他应用程序,您可能需要使用另一种机制。
查询的使用非常简单:
public class CategoryController
{
private readonly IRepository repository;
private readonly IGetParentCategoriesQuery getParentCategoriesQuery;
public CategoryController(
IRepository repository,
IGetParentCategoriesQuery getParentCategoriesQuery)
{
this.repository = repository;
this.getParentCategoriesQuery = getParentCategoriesQuery;
}
public void Process(Guid categoryId)
{
Category category = this.repository.LoadById(categoryId);
IEnumerable<Category> parentCategories =
this.getParentCategoriesQuery(category);
// so some stuff...
}
}范围划分的一个替代方法是让存储库实例化查询类型并将DbContext传递给查询实例(这可以使用工厂扩展来完成):
public TQuery CreateQuery<TQuery>()
{
return this.queryFactory.Create<TQuery>(this.context);
}可用于如下用途:
IEnumerable<Category> parents = repository
.CreateQuery<GetParentCategoriesQuery>()
.GetParents(someCategory);但请注意,此替代方案将再次延迟创建查询,从而导致测试性降低(绑定问题可能会在更长时间内未被检测到)。
GetParentCategoriesQuery是存储库层的一部分,但不是存储库类的一部分。
https://stackoverflow.com/questions/26366871
复制相似问题