首页 > 解决方案 > 使用依赖注入时使用存储库模式的多个 DB 上下文与 UnitofWork

问题描述

我正在开发具有多个模块的应用程序。我为同一数据库中不同架构下的不同模块创建了表,并在默认架构中创建了所有与用户相关的表。在阅读了有关 dbcontext、工作单元和存储库模式的更多信息后,我感到更加困惑。我开始创建一个 dbcontext 并意识到登录用户需要很少数量的表,但是通过调用构造函数,它将所有内容都带入内存。后来我想创建多个 dbcontexts,但我必须在所有 dbcontexts 中包含用户相关的表。

作为第三种选择,我开始使用 unitofwork 和 repository 模式。许多文章都说它只是 EF 之上的另一个抽象,带有 DBContext 和 DBSet。我仍然继续工作,并意识到我将拥有数百个存储库,一旦我将它们全部添加到 unitofwork 并调用构造函数,所有内容都会再次加载到内存中。我完全不知道哪种方法最适合我的需要。每个控制器只需要特定的表存储库和用户表存储库来进行 CRUD 操作,但是通过执行上述步骤,是否会导致性能问题?

我的工作单元如下

using DemoApp.Core;
using DemoApp.Core.Repositories;
using DemoApp.Persistence.Repositories;

namespace DemoApp.Persistence
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly DemoAppContext _context;
        public UnitOfWork(DemoAppContext context)
        {
            _context = context;
            Ones = new OneRepository(_context);
            Twos = new TwoRepository(_context);
        }
        public IOneRepository Ones { get; private set; }
        public ITwoRepository Twos { get; private set; }

        public int Complete()
        {
            return _context.SaveChanges();
        }
        public void Dispose()
        {
            _context.Dispose();
        }
    }
}

和控制器

using DemoApp.Core;
using DemoApp.Core.Domain;
using DemoApp.Persistence;
using System;
using System.Linq;
using System.Web.Mvc;

namespace DemoApp.Controllers
{
    public class HomeController : Controller
    {
        private readonly IUnitOfWork _unitOfWork;
        public HomeController(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }
        public ActionResult Index()
        {
            var result = _unitOfWork.Ones.GetAll();
            return View(result);
        }
    }
}

标签: entity-frameworkrepository-patterndbcontextunit-of-work

解决方案


拥有单个大型上下文不会在构造时将实体加载到内存中,但它会解析实体映射,这在非常大的上下文中首次加载可能需要几秒钟。有界上下文适合非常大的系统,您可以在其中分离相关实体,或将“重”或时间敏感实体与主要使用上下文分开。

我使用有界上下文的模式,该模式使用输入到相关上下文的属性来标记哪些实体类型配置适用于哪些上下文。这适用于使用较小的只读实体定义。不过,我真的只推荐这个用于非常大的实体集。通过利用延迟执行和 .Select() 表达式在需要时仅提取所需的数据,通常不需要使用多个有界实体声明。

使用工作单元和存储库模式的论据主要围绕启用单元测试。我不建议使用通用存储库(每个实体的存储库),而是像使用控制器模式一样使用存储库模式。每个存储库为应用程序的一个区域提供检索、创建和删除与该区域相关的实体的方法。将存储库绑定到单个实体会导致大量样板代码或不适用于所有实体的通用操作。它使您的代码不那么灵活,最终更难阅读。在大多数情况下,您应该利用实体之间映射的关系,因此,单个存储库可以管理对特定屏幕的所有相关实体的检索和操作,而不是在许多不同的存储库之间切换以尝试加载相关数据。我使用 Mehdime 的 DbContextScope UoW 模式,因为它促进了跨存储库/帮助程序的读/写和只读范围,并且不需要将 dbcontext/UoW 包装器注入到存储库中。这使得在请求中拥有多个 UoW 范围与将 DbContext/UoW 实例范围限定为请求或手动处理生命周期范围(如果您的容器支持)。在任何情况下,作为一种选择都值得一看。Mehdime 的实现适用于 EF 6.x,而 EF Core 有可用的分支。我使用 Mehdime 的 DbContextScope UoW 模式,因为它促进了跨存储库/帮助程序的读/写和只读范围,并且不需要将 dbcontext/UoW 包装器注入到存储库中。这使得在请求中拥有多个 UoW 范围与将 DbContext/UoW 实例范围限定为请求或手动处理生命周期范围(如果您的容器支持)。在任何情况下,作为一种选择都值得一看。Mehdime 的实现适用于 EF 6.x,而 EF Core 有可用的分支。我使用 Mehdime 的 DbContextScope UoW 模式,因为它促进了跨存储库/帮助程序的读/写和只读范围,并且不需要将 dbcontext/UoW 包装器注入到存储库中。这使得在请求中拥有多个 UoW 范围与将 DbContext/UoW 实例范围限定为请求或手动处理生命周期范围(如果您的容器支持)。在任何情况下,作为一种选择都值得一看。Mehdime 的实现适用于 EF 6.x,而 EF Core 有可用的分支。如果您的容器支持,则将 DbContext/UoW 实例限定为请求或手动处理生命周期范围。在任何情况下,作为一种选择都值得一看。Mehdime 的实现适用于 EF 6.x,而 EF Core 有可用的分支。如果您的容器支持,则将 DbContext/UoW 实例限定为请求或手动处理生命周期范围。在任何情况下,作为一种选择都值得一看。Mehdime 的实现适用于 EF 6.x,而 EF Core 有可用的分支。


推荐阅读