【问题标题】:Store References to Generic Repositories in UnitOfWork在 UnitOfWork 中存储对通用存储库的引用
【发布时间】:2012-04-18 00:47:17
【问题描述】:

我正在使用以下 UnitOfWork 类,以便通过使用泛型获取我的实体的存储库。

public class UnitOfWork : IUnitOfWork
{
  private readonly EfDbContext _context;

  public UnitOfWork()
  {
    _context = new EfDbContext();
  }

  public IRepository<T> RepositoryFor<T>() where T : Entity
  {
    return new Repository<T>(_context);
  }

  public void Save()
  {
    _context.SaveChanges();
  }
}

但是,我遇到了一些问题,我有两个单独的类为单个实体独立实例化 UnitOfWork,这意味着为该实体创建了两个存储库。当我尝试保存实体时,这会导致实体框架引发“IEntityChangeTracker 的多个实例无法引用实体对象”错误。

我认为我需要更严格地遵循此 post by Tom Dykstra 中“创建工作单元类”部分中描述的 UOW 模式,其中存储库存储在私有字段中如果存在则重用,如果为空则创建。我遇到的问题是我希望我的 UOW 继续使用泛型 - Repository&lt;T&gt; - 而不必为我在代码中拥有的所有实体类型声明私有存储库字段。

我如何能够存储给定类型的存储库已被实例化的事实并重新使用它而不是创建它的新实例?

--- 编辑:这里是修复---

使用 Ninject,我调整了我的绑定,通过指定 InRequestScope 仅实例化存储库和 UOW 的单个实例

kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
//kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); // Removed based on comment below
kernel.Bind(typeof(EfDbContext)).ToSelf().InRequestScope();

【问题讨论】:

  • Singleton,或工厂,如果已创建,则保留对存储库的引用,并提供引用或副本或该存储库
  • 假设有时您想使用 Include() 进行特定查询,那么通用存储库将不够用。您可能需要有一个用于继承通用存储库的特定实体类型的存储库。
  • 为了完美,您不应该在 IoC 容器中注册 Repository&lt;&gt;。它是工作单元的一部分,不应允许它以某种方式获取它,除非从 UoW 实例中获取。此外,您显式地实例化它而不是从容器中解析。所以,在容器中注册是没有意义的。
  • 这是有道理的。我删除了存储库的绑定。谢谢!

标签: c# entity-framework unit-of-work


【解决方案1】:

问题不在于多个存储库,而在于多个DbContext 实例。 EF 告诉您不能一次将同一个实体实例添加到多个上下文中。因此共享存储库无济于事。此外,拥有多个 UoW 共享单例存储库是通往地狱的道路。处理并发(EF 不是线程安全的)、状态等将非常困难。

要解决此问题,您应该执行以下任一操作:

  1. 共享工作单元,以便您在单个业务操作中使用相同的 UoW 实例(和 DbContext
  2. 在将实体实例添加到另一个 UoW 之前创建它们的副本。

选择取决于您的具体情况。

【讨论】:

  • 谢谢帕维尔...您的评论为我指明了正确的方向。我发现了这个问题。使用 Ninject,我添加了 InRequestScope 并解决了问题。我已经用有效的解决方案更新了我的问题。感谢您为我指明正确的方向。
  • 这种方法通常效果很好。但是,有一些限制。例如,您最终可能需要在单个服务器方法中使用不同的 UoW(不同的事务)。在这种情况下,请考虑使用参数化而不是请求范围来精确控制 UoW 共享。
【解决方案2】:

你觉得这个解决方案怎么样?

public class UnitOfWork
    {
        private IRepository<Animal> _animalRepository;
        public IRepository<Animal> Animals => _animalRepository ??= new Repository<Animal>();

        public IRepository<T> Repository<T>()
        {
            var result = GetType()
                .GetProperties()
                .FirstOrDefault(r => typeof(IRepository<T>) == r.PropertyType)?
                .GetValue(this, null);

            return (IRepository<T>)result;
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-02
    相关资源
    最近更新 更多