在没有依赖注入的情况下手动实例化多个 DbContext
Instantiate multiple DbContext manually without dependency injection
我想创建一个 ASP.Net 核心网络服务,它将 select 来自一个 SQL 服务器数据库的行并将它们插入 X SQL 服务器数据库.所有数据库都具有相同的结构(相同的模型)。
我不想注入 DbContext,因为我不知道我必须使用多少上下文,而且很难维护。
是否可以在控制器或管理器中手动创建 DbContext,例如:
MyContextClass dbContext = new MyContextClass("myConnectionString");
谢谢
是的,可以只创建一个新的 DbContext
。
但是,当使用 DI 时,您应该编写并注入类似 DbContextFactory
class 的内容,您可以使用它来创建新的上下文,并且它本身会从您的配置中获取 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;
}
}
为了方便使用,创建一个扩展 class:
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"));
我想创建一个 ASP.Net 核心网络服务,它将 select 来自一个 SQL 服务器数据库的行并将它们插入 X SQL 服务器数据库.所有数据库都具有相同的结构(相同的模型)。
我不想注入 DbContext,因为我不知道我必须使用多少上下文,而且很难维护。
是否可以在控制器或管理器中手动创建 DbContext,例如:
MyContextClass dbContext = new MyContextClass("myConnectionString");
谢谢
是的,可以只创建一个新的 DbContext
。
但是,当使用 DI 时,您应该编写并注入类似 DbContextFactory
class 的内容,您可以使用它来创建新的上下文,并且它本身会从您的配置中获取 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;
}
}
为了方便使用,创建一个扩展 class:
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"));