在使用 IdentityDbContext 的情况下,如何在 ASP.NET Core MVC 中使用存储库模式?

Posted

技术标签:

【中文标题】在使用 IdentityDbContext 的情况下,如何在 ASP.NET Core MVC 中使用存储库模式?【英文标题】:How to use repository pattern in ASP.NET Core MVC while IdentityDbContext has been used? 【发布时间】:2022-01-10 00:32:29 【问题描述】:

我在我的项目中使用了 IdentityDbContext。我的数据库有一些相互连接的表(关系)。我想使用存储库模式。我声明了我所有的接口。然后,我尝试实现它们。问题是我无法创建 IdentityAppContext 的实例,因为构造函数需要一个输入参数“选项”。 我该如何实现它们?

IdentityAppContext.cs:

public class IdentityAppContext: IdentityDbContext<AppUser, AppRole, int>

    public IdentityAppContext(DbContextOptions<IdentityAppContext> options) : base(options)
    

    
    protected override void OnModelCreating(ModelBuilder builder)
    
        base.OnModelCreating(builder);
    
    public DbSet<AppUser> Users  get; set; 
    public DbSet<Message> Messages  get; set; 
    public DbSet<PM> PMs  get; set; 
    public DbSet<Notification> Notifications  get; set; 
    public DbSet<FileRepository> Files  get; set; 

IPmRepository.cs:

public interface IPmRepository

    IEnumerable<PM> GetAllPMs();
    PM GetPmById(int pmId);
    bool InsertPM(PM pm);
    bool UpdatePM(PM pm);
    bool DeletePM(int pmId);
    bool DeletePM(PM pm);
    void Save();

PmRepository.cs:

public class PmRepository : IPmRepository

    IdentityAppContext db = new IdentityAppContext();
    public IEnumerable<PM> GetAllPMs()
    
        
    
    public PM GetPmById(int pmId)
    
        throw new NotImplementedException();
    
    public bool InsertPM(PM pm)
    
        throw new NotImplementedException();
    
    public bool UpdatePM(PM pm)
    
        throw new NotImplementedException();
    
    public bool DeletePM(int pmId)
    
        throw new NotImplementedException();
    

    public bool DeletePM(PM pm)
    
        throw new NotImplementedException();
    
    public void Save()
    
        throw new NotImplementedException();
    

【问题讨论】:

为什么你认为你需要使用存储库模式? DbSet 已经是一个单实体存储库。 DbContext 已经是一个多实体的工作单元。 GetAllPMs 方法很少有用 - 很少有任何理由加载表中的所有行,除非您想填充查找表。在像 ORM 这样的高级抽象上使用低级“存储库”接口实际上是一种模式 与@PanagiotisKanavos 一致,避免使用反模式。这将帮助您在处理 IdentityDbContext 时进行设置:***.com/questions/50377705/…,可能重复:***.com/questions/23226140/… 如果您想使用 DDD,请注意 DDD 使用存储库作为 聚合根 - 这是您需要加载以处理特定用途的对象图的根案例(DDD 术语中的有界上下文)。 单个实体。在这种情况下,是的,specialized Repository 是有意义的。在那个级别,绝对不需要具有 CRUD 方法的类,不需要加载表中的所有对象。 至于IdentityDbContext为什么不能和new一起使用,那是因为它是用来和依赖注入一起使用的。使用该 DbContext 的类需要以相同的方式工作 - 而不是尝试手动创建它们的依赖项,而是接受它们作为构造函数参数。只需更改AddDbContext 中注册的选项或传递给构造函数的选项,就可以轻松地将底层存储从 SQL Server 更改为 mysql 再到 Oracle 到 NoSQL 数据库。这样可以轻松进行单元测试 - 您可以使用内存提供程序,而无需修改 DbContext 或任何使用它的代码 假设你真的定义了一个PmRepository,它需要一个接受IdentityAppContext参数的构造函数。 【参考方案1】:

假设 DbContext 已在 Startup.cs 文件中注册到 DI 容器,使用类似:

services.AddDbContext<IdentityAppContext>(opt => 

   opts.UseSqlServer(myConnectionString);
)

然后以与上述相同的方法添加以下内容,会将您的存储库注册到同一个 DI Container 中:

services.AddScoped<IPmRepository, PmRepository>();

然后在您的存储库中:

public class PmRepository : IPmRepository

    readonly IdentityAppContext _context;
 
    // 'context' parameter is automagically provided by the container.
    public PmRepository(IdentityAppContect context)
    
        _context = context;
    

    public bool InsertPM(PM pm)
    
        _context.PMs.Add(pm);
    

然后,在您的控制器(也由容器提供)中,您应该能够在构造函数中从容器请求 IPmRepository:

public class MyController : Controller

    readonly IdentityAppContext _context;
    readonly IPmRepository _pmRepository;

    // Both 'context' and 'pmRepository' are automagically provided by the container
    public MyController(
        IdentityAppContext context,
        IPmRepository pmRepository)
    
        _context = context;
        _pmRepository = pmRepository;
    

    [HttpPost]
    public async Task DoSomething(MyRequest request)
    
        _pmRepository.InsertPM(new PM()  Id = request.Id );

        await _context.SaveChangesAsync();
    

注意,由于IdentityAppContext和IPmRepository和MyController注册在同一个容器中,所以框架可以自动为MyController构造函数提供参数。

此外,当为 Controller 创建 PmRepository 时,容器可以查看 PmRepository 的构造函数参数,并看到它需要一个 IdentityAppContext,它可以自动提供,因为它注册在同一个容器中。

【讨论】:

以上是关于在使用 IdentityDbContext 的情况下,如何在 ASP.NET Core MVC 中使用存储库模式?的主要内容,如果未能解决你的问题,请参考以下文章

MVC5 中的 IdentityDbContext 和 IdentityDbContext<ApplicationUser> 有啥区别

.NET Core 2.0 和 EF 下是不是需要使用 IdentityDbContext 进行 JWT 身份验证?

具有相同/单个数据库的单独IdentityDbContext-有什么好处?

通过加入用户详细信息实体从 IdentityDbContext 获取用户详细信息

执行 DbCommand 失败

我应该将啥 DbContext 与 EntityFrameworkCore 一起使用?