带有实体框架的有界上下文和通用存储库以及使用简单注入器IoC的连接

时间:2014-04-23 08:35:30

标签: c# generics repository-pattern entity-framework-6 simple-injector

在StackOverflow上阅读了很多内容,但无法找到与此相似的任何问题/答案。尽量保持简短。

我的关键问题是当你有几个有界的上下文时如何设计一个通用的存储库。我之前一直在使用Generic存储库但是我通常会将它们关闭,例如

public class CustomerRepository : Repository<Customer>

但是现在我想跳过这些自定义查询,而不是将查询处理程序用于自定义查询,例如&#34; GetCustomerbyOrderNumber ....&#34;并让Repositories负责只使用一个实体,在本例中为Customer。

但是当我使用Bounded Context时,我通常使用我的IoC(使用Castle,AutoMapper和现在的Simple Injector)为每个Bounded Context注册每个Entity Framework DBContext。但是当试图采用纯粹的开放通用存储库方法时......

 public class Repository<TEntity> : IRepository<TEntity>
    where TEntity : Entity, IAggregateRoot
{
    #region Members

    private readonly IQueryableUnitOfWork _unitOfWork;

    #endregion

    #region Constructor

    /// <summary>
    ///     Create a new instance of repository
    /// </summary>
    /// <param name="unitOfWork">Associated Unit Of Work</param>
    protected Repository(IQueryableUnitOfWork unitOfWork)
    {
        if (unitOfWork == null)
            throw new ArgumentNullException("unitOfWork");

        _unitOfWork = unitOfWork;
    }

我不知道如何管理Simple Injector以了解要使用的Dbcontext。该场景可能会将ICommandHandler注入MVC​​控制器。实现AddCustomerCommandHandler将IRepository注入构造函数。但问题出在这里。实现Repository将IQuerableUnitOfWork视为依赖(所有有界上下文都继承自继承自IQuerableUnitOfWork接口的BaseContext。因此所有DBContexts都是IQuerableUnitOfWork。)

不知何故,当需要在同一个Bounded上下文中使用命令处理程序(位于另一个程序集中)时,我需要告诉Simple注入器将ANiceBoundedContexOne(只是一个示例上下文)注入到Repository中。 然后在为有限上下文使用命令处理程序时使用ANiceBoundedContexTwo注入到Repository中。

我做过一些研究和阅读,并不完全确定Simple Injector的功能,但我可以看到一些解决方案路径:

1)建立工厂并在SI中注册。将该工厂注入CommandHandlers并让它们获得适当的存储库。

2)制作更多特定于上下文的界面。 IContextOneRepository,如果我参考上面的例子。这意味着,如果我有三个有界上下文基础设施组件,他们都可以拥有他们的IContextOneRepository,IContextTwoRepository和IContextThreeRepository(名称很糟糕,但它只是一个例子)。 Repository实现位于Shared Kernel类库中。简单注入器将为该实现注册三个接口,但将不同的DBContext注入到Repository构造函数中。

还有其他一些我没有想过的美好而顺畅的方式吗?

您是否真的使用简单的进样器完成了上述任何解决方案?这是如何实现的?

2 个答案:

答案 0 :(得分:2)

您不使用通用存储库,期间!最多使用通用存储库接口,其中T是域实体,而不是EF实体。你不公开EF或它的一些部分,它会破坏Repository的目的(将域与持久性细节分离)。

存储库使用聚合根(AR),它只在特定的有界上下文(BC)中有效。 BC由域定义,它不关心持久性或其他实现细节。因为 BC是一个抽象的DDD概念,而不是实际的类。在你的BC中你有相同的AR吗?如果是这样,您可能会得到错误的模型或某些BC可以合并。如果您使用CQRS也很重要,因为您只关心更改模型(命令)而不关心查询。

我很难理解你的实际情况,因为代码似乎很乱,但这些是我的想法:

您定义了一个或多个AR。每个AR都有一个相应的存储库,在DAL中实现,存储库使用EF。该应用程序仅从这些存储库获取/保存AR(看不到EF)。针对特定AR的Repo并不关心其他AR(至少从接口的角度来看,如果您想对所有AR使用相同的实现,那就没问题)。

你的问题是关于如何使用Di Container,但它就像问:什么电锯品牌更好地切割我正站在树枝上。没有,开始的目标是错误的。

没有冒犯,但我觉得你使用的是一个非常有缺陷的DDD版本,即你没有做正确的DDD,结果你的代码非常复杂,而且可维护性很低。

答案 1 :(得分:-1)

这里有两个相同单元类的上下文。试试这个我希望这会对你有帮助。

    public class UnitOfWorks : IUnitOfWorks
                {
                     ///Context one        
                    private readonly TodosContexts todoContext = new TodosContexts();

                     ///Context Second
                    private readonly CustomerContext customerContext = new CustomerContext(); 

                    /// <summary>
                    /// Flag to show disposed of not.
                    /// </summary>
                    private bool disposed = false;

                    /// First context
                    private IItemRepository itemRepository;

                    /// Second context       
                private ICustomerRepository customerRepository;

                    public IItemRepository ItemRepository
                    {
                        get { return this.itemRepository ?? (this.itemRepository = new  ItemRepository(this.context)); }
                    }



                    public ICustomerRepository CustomerRepository
                    {
                        get { return this.customerRepository ?? (this.customerRepository = new                     CustomerRepository(this.customerContext)); }
                    }
                }

                public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
                {
                    /// <summary>
                    /// Gets or sets CoreDBContext information.
                    /// </summary>
                    public DbContext Context { get; set; }

                    /// <summary>
                    /// Gets or sets Database Entity set information.
                    /// </summary>
                    public DbSet<TEntity> DBSet { get; set; }

                    /// <summary>
                    /// Initialises a new instance of the  <see cref="GenericRepository {TEntity}" /> class.
                    /// </summary>
                    /// <param name="contextValue">Context information.</param>
                    public GenericRepository(DbContext contextValue)
                    {
                        this.Context = contextValue;
                        this.DBSet = this.Context.Set<TEntity>();
                    }
               }


public class CustomerRepository : GenericRepository<Customer>, ICustomerRepository
    {
        /// <summary>
        /// Initialises a new instance of the <see cref="CommentRepository" /> class.
        /// </summary>
        /// <param name="contextValue">The context value.</param>
        public CustomerRepository(CustomerContext contextValue)
            : base(contextValue)
        {
            if (this.Context == null)
            {
                throw new ArgumentException("Context is null.");
            }
        }
    }