网站怎么做链接跳转,app ui模板,南京小程序开发公司哪家好,wordpress适合国人的编辑器EF Core 5 中的 DbContextFactoryIntro使用过 EF Core 大多都会遇到这样一个场景#xff0c;希望能够并行查询#xff0c;但是如果使用同一个 DbContext 实例进行并行操作的时候就会遇到一个 InvalidOperationException 的异常#xff0c;在 EF Core 2.x/3.x 版本中#xf… EF Core 5 中的 DbContextFactoryIntro使用过 EF Core 大多都会遇到这样一个场景希望能够并行查询但是如果使用同一个 DbContext 实例进行并行操作的时候就会遇到一个 InvalidOperationException 的异常在 EF Core 2.x/3.x 版本中 EF Core DbContext 的生命周期默认是 Scoped如果要并行查询需要创建多个 Scope在子 Scope 中创建 DbContext 来进行操作EF Core 5 中的 DbContextFactory 可以用来简化这样的操作且看下文示例DbContextFactoryDbContextFactory 就如同它的名字一样就是一个 DbContext 的工厂就是用来创建 DbContext 的IDbContextFactory 接口定义如下Github 源码 https://github.com/dotnet/efcore/blob/v5.0.0/src/EFCore/IDbContextFactory.cspublic interface IDbContextFactoryout TContext where TContext : DbContext
{/// summary/// para/// Creates a new see crefDbContext / instance./// /para/// para/// The caller is responsible for disposing the context; it will not be disposed by the dependency injection container./// /para/// /summary/// returns A new context instance. /returnsTContext CreateDbContext();
}
需要注意的是如果使用 DbContextFactory 来创建 DbContext需要自己来释放 DbContext需要自己使用 using 或者 Dispose 来释放资源另外 DbContextFactory 生命周期不同于 DbContext默认的生命周期的 Singleton也正是因为这样使得我们可以简化并行查询的代码可以参考https://github.com/dotnet/efcore/blob/v5.0.0/src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs#L607Sample来看一个实际的示例这是一个并行操作插入100条记录的简单示例看一下如何使用 DbContextFactory 进行并行操作var services new ServiceCollection();
services.AddDbContextFactoryTestDbContext(options
{options.UseInMemoryDatabase(Tests);
});
using var provider services.BuildServiceProvider();
var contextFactory provider.GetRequiredServiceIDbContextFactoryTestDbContext();Enumerable.Range(1, 100).Select(async i {using (var dbContext contextFactory.CreateDbContext()){dbContext.Posts.Add(new Post() { Id i 101, Author $author_{i}, Title $title_{i} });return await dbContext.SaveChangesAsync();}}).WhenAll().Wait();using var context contextFactory.CreateDbContext();
Console.WriteLine(context.Posts.Count());
实现源码EF Core 的 DbContextFactory 的实现不算复杂一起来看一下首先看一下 DbContextFactory 的实现public class DbContextFactoryTContext : IDbContextFactoryTContext where TContext : DbContext
{private readonly IServiceProvider _serviceProvider;private readonly DbContextOptionsTContext _options;private readonly FuncIServiceProvider, DbContextOptionsTContext, TContext _factory;public DbContextFactory([NotNull] IServiceProvider serviceProvider,[NotNull] DbContextOptionsTContext options,[NotNull] IDbContextFactorySourceTContext factorySource){Check.NotNull(serviceProvider, nameof(serviceProvider));Check.NotNull(options, nameof(options));Check.NotNull(factorySource, nameof(factorySource));_serviceProvider serviceProvider;_options options;_factory factorySource.Factory;}public virtual TContext CreateDbContext() _factory(_serviceProvider, _options);
}
可以看到 DbContextFactory 的实现里用到了一个 IDbContextFactorySource再来看一下 DbContextFactorySource 的实现实现如下public class DbContextFactorySourceTContext : IDbContextFactorySourceTContext where TContext : DbContext
{public DbContextFactorySource() Factory CreateActivator();public virtual FuncIServiceProvider, DbContextOptionsTContext, TContext Factory { get; }private static FuncIServiceProvider, DbContextOptionsTContext, TContext CreateActivator(){var constructors typeof(TContext).GetTypeInfo().DeclaredConstructors.Where(c !c.IsStatic c.IsPublic).ToArray();if (constructors.Length 1){var parameters constructors[0].GetParameters();if (parameters.Length 1){var isGeneric parameters[0].ParameterType typeof(DbContextOptionsTContext);if (isGeneric|| parameters[0].ParameterType typeof(DbContextOptions)){var optionsParam Expression.Parameter(typeof(DbContextOptionsTContext), options);var providerParam Expression.Parameter(typeof(IServiceProvider), provider);return Expression.LambdaFuncIServiceProvider, DbContextOptionsTContext, TContext(Expression.New(constructors[0],isGeneric? optionsParam: (Expression)Expression.Convert(optionsParam, typeof(DbContextOptions))),providerParam, optionsParam).Compile();}}}var factory ActivatorUtilities.CreateFactory(typeof(TContext), new Type[0]);return (p, _) (TContext)factory(p, null);}
}
从上面的源码中可以看得出来 DbContextFactory 把工厂拆成了两部分DbContextFactorySource 提供一个工厂方法提供一个委托来创建 DbContext而 DbContextFactory 则利用 DbContextFactorySource 提供的工厂方法来创建 DbContext.MoreDbContextFactory 可以使得在并行操作的时候会更加方便一些但是注意要自己控制好 DbContext 生命周期防止内存泄漏。对于 EF Core DbContextFactory 的实现不得不说这样的实现灵活性更强一些但是又感觉有一些多余想要扩展 DbContextFactory 的实现直接重写一个 DbContextFactory 的实现服务注册的时候注入就可以了你觉得呢~~Referencehttps://github.com/dotnet/efcore/blob/v5.0.0/src/EFCore/IDbContextFactory.cshttps://github.com/dotnet/efcore/blob/v5.0.0/src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs#L607https://github.com/dotnet/efcore/blob/v5.0.0/src/EFCore/Internal/DbContextFactory.cshttps://github.com/dotnet/efcore/blob/v5.0.0/src/EFCore/Internal/DbContextFactorySource.cshttps://github.com/WeihanLi/SamplesInPractice/blob/master/EF5Samples/DbContextFactoryTest.cs