首页 > 解决方案 > 手动实例化多个 DbContext 无需依赖注入

问题描述

我想创建一个 ASP.Net Core Web 服务,它将从一个 SQL Server 数据库中选择行并将它们插入到 X SQL Server 数据库中。所有数据库都具有相同的结构(相同的模型)。

我不想注入 DbContext,因为我不知道必须使用多少上下文并且很难维护。

是否可以在控制器或管理器中手动创建 DbContext,例如:

MyContextClass dbContext = new MyContextClass("myConnectionString");

谢谢

标签: c#entity-frameworkasp.net-coredbcontext

解决方案


是的,可以只创建一个新的DbContext. 但是,在使用 DI 时,您应该编写和注入类似于DbContextFactory类的东西,您可以使用它来创建新的上下文,并且它本身可以DbContextOptions从您的配置中获取。

public class ContextFactory<TContext>
    where TContext : DbContext
{
    private readonly Func<TContext> _createContext;

    public ContextFactory(Func<TContext> createContext)
    {
        _createContext = createContext ?? throw new ArgumentNullException(nameof(createContext));
    }

    TContext CreateForRead()
    {
        var context = Create();

        context.ChangeTracker.AutoDetectChangesEnabled = false;
        context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

        return context;
    }

    TContext CreateForWrite() => Create();

    private TContext Create()
    {
        var context = _createContext();
        if (context == null)
            throw new NullReferenceException($"{nameof(_createContext)} must not return null.");

        return context;
    }
}

为了更方便使用,创建一个扩展类:

public static class ServiceCollectionDataExtensions
{
    public static void AddDatabase<TDbContext>(this IServiceCollection services, string connectionString)
        where TDbContext : DbContext
    {
        if (services == null)
            throw new ArgumentNullException(nameof(services));

        if (string.IsNullOrEmpty(connectionString))
            throw new ArgumentNullException(nameof(connectionString));

        services.AddDbContext<TDbContext>(c => c.UseSqlServer(connectionString), ServiceLifetime.Transient);
        services.AddScoped(provider => new ContextFactory<TDbContext>(() => ActivatorUtilities.CreateInstance<TDbContext>(provider, provider.GetRequiredService<DbContextOptions<TDbContext>>())));
    }
}

然后在您public void ConfigureServices(IServiceCollection services)的配置中添加连接字符串:

services.AddDatabase<MyDbContext>(Configuration.GetConnectionString("MyDatabase"));

推荐阅读