具有实体框架的有界上下文和通用存储库,并与简单注入器IoC连接

本文关键字:注入器 连接 IoC 存储 简单 框架 实体 上下文 | 更新日期: 2023-09-27 17:59:38

我在StackOverflow上读了很多书,找不到任何与此完全相似的问题/答案。尽量短一点。

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

public class CustomerRepository : Repository<Customer>

但现在我想跳过这些自定义查询,转而将查询处理程序用于自定义查询,如"GetCustomerbyOrderNumber…",并让存储库只负责处理一个实体,在本例中为Customer。

但是,当使用Bounded Context时,我以前也这样做过,我通常会用我的IoC(使用Castle、AutoMapper和现在的Simple Injector)为每个Bounded上下文注册每个实体框架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;
    }

我不知道如何管理SimpleInjector来理解要使用什么Dbcontext。场景可能是将ICommandHandler注入MVC控制器。Implementation AddCustomerCommandHandler将在构造函数中注入IRepository。但问题来了。实现存储库将IQuerableUnitOfWork作为依赖项(所有有界上下文都继承自BaseContext,该BaseContext继承自接口IQuerableUnitOfWork。因此,所有DBContext都是IQuerableUnitOfWork)。

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

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

1) 创建一个工厂并在SI中注册。将该工厂注入CommandHandlers并让它们获得适当的Repository。

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

还有什么我没有想到的又好又顺利的方法吗?

你真的用简单的注射器做过上面的任何解决方案吗?结果如何?

具有实体框架的有界上下文和通用存储库,并与简单注入器IoC连接

您不使用通用存储库,句号!最多使用通用存储库接口,其中T是域实体,而不是EF实体。您不公开EF或其部分,它违背了Repository的目的(将Domain与持久性细节解耦)。

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

我很难理解你的实际情况,因为代码看起来很乱,但以下是我的想法:

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

你的问题是关于如何使用Di Container,但这就像在问:什么品牌的链锯更适合切割我站在上面的树枝。没有,目标一开始就错了。

无意冒犯,但我感觉你使用的是一个非常有缺陷的DDD版本,即你没有进行正确的DDD,因此,你的代码非常复杂,而且似乎可维护性很低。

这里是同一个工作单元类中的两个上下文。试试这个,我希望它能帮助你。

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