第三节:EF Core上下文DbContext相关配置和生命周期
一. 配置相关
1. 数据库连接字符串的写法
(1).账号密码:Server=localhost;Database=EFDB01;User ID=sa;Password=123456;
(2).windows身份:Server=localhost;Database=EFDB01;Trusted_Connection=True;
2. 命令超时和默认关闭状态追踪
(1).命令超时: providerOptions => providerOptions.CommandTimeout(60),表示60秒超时。
(2).关闭查询状态追踪:UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking),表示关闭追踪;
(PS: 默认是 QueryTrackingBehavior.TrackAll 开启追踪)
详见下面案例:
a. QueryTrackingBehavior.NoTracking: 对应的是Detached状态,即有游离状态。
b. QueryTrackingBehavior.TrackAll: 对应的是Unchanged状态,即未发生改变的。
1 { 2 var d1 = context1.T_UserInfor.First(); 3 //关闭跟踪对应的是:Detached;开启跟踪对应的是:Unchanged 4 var state = context1.Entry(d1).State; 5 }
3. 日志记录
最好在控制台中配置,能输出生成的SQL语句。
配置代码分享:
1 public partial class EFDB01Context : DbContext 2 { 3 //public static readonly LoggerFactory MyLoggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) }); 4 public static readonly LoggerFactory MyLoggerFactory = new LoggerFactory(new[] 5 { 6 new ConsoleLoggerProvider((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information, true) 7 }); 8 public EFDB01Context() 9 { 10 11 } 12 public virtual DbSet<T_RoleInfor> T_RoleInfor { get; set; } 13 public virtual DbSet<T_UserInfor> T_UserInfor { get; set; } 14 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 15 { 16 optionsBuilder.UseSqlServer("Server=localhost;Database=EFDB01;User ID=sa;Password=123456;").UseLoggerFactory(MyLoggerFactory); 17 } 18 }
输出结果:
4. 连接弹性
详见官方文章:https://docs.microsoft.com/zh-cn/ef/core/miscellaneous/connection-resiliency
5. 线程安全问题
(1).说明
EF Core不支持在同一DbContext实例上运行多个并行操作。这包括异步查询的并行执行以及从多个线程进行的任何显式并发使用。因此,应await立即异步调用, 或对并行DbContext执行的操作使用单独的实例。
当EFCore检测到并行使用某个DbContext实例时, 触发InvalidOperationException异常;但是当并发访问未被检测时, 可能会导致未定义的行为、应用程序崩溃和数据损坏.
(2).情况一:在对同一 DbContext 启动任何其他操作之前, 忘记等待异步操作完成。
使用异步方法, EF Core 可以启动以非阻止方式访问数据库的操作。 但是, 如果调用方不等待其中一种方法完成, 并继续在上DbContext执行其他操作,则的DbContext状态可能会损坏。
(3).情况二:Core MVC通过依赖关系注入在多个线程之间隐式共享 DbContext 实例
默认AddDbContext情况下,注入的上下文是请求内单例的,所以每个请求都获得了单独的DbContext,请求与请求之间的DbContext是线程安全的;但是,在同一个请求中,任何并行显式执行多个线程的代码都应该DbContext确保不会同时访问实例,否则会出现上述“情况一”的状况。
(4). 案例说明:要避免下面案例的那种情况,公用同一个上下文,是没法保证线程安全的。
代码分享:
1 { 2 var optionsBuilder = new DbContextOptionsBuilder<EFDB01Context>(); 3 optionsBuilder.UseSqlServer(configuration.GetConnectionString("EFStr")); 4 EFDB01Context context = new EFDB01Context(optionsBuilder.Options); 5 Task.Run(() => 6 { 7 while (true) 8 { 9 var u1 = new T_UserInfor() 10 { 11 id = Guid.NewGuid().ToString("N"), 12 userName = "ypf2", 13 userSex = "男2", 14 userAge = 19, 15 addTime = DateTime.Now 16 }; 17 context.Set<T_UserInfor>().Add(u1); 18 int result = context.SaveChanges(); 19 } 20 }); 21 22 Task.Run(() => 23 { 24 while (true) 25 { 26 var u1 = new T_UserInfor() 27 { 28 id = Guid.NewGuid().ToString("N"), 29 userName = "ypf2", 30 userSex = "男2", 31 userAge = 19, 32 addTime = DateTime.Now 33 }; 34 context.Set<T_UserInfor>().Add(u1); 35 int result = context.SaveChanges(); 36 } 37 }); 38 Task.Delay(TimeSpan.FromMinutes(15)).Wait(); 39 }
6. 连接数和连接池问题
(1).查询数据库连接数语句:SELECT * FROM SYSPROCESSES WHERE DBID = DB_ID('数据库名')
(2).手动设置连接池的最大(小)数量: "Server=localhost;Database=Test;Trusted_Connection=True;Max Pool Size=100;Min Pool Size=5"
(3).连接池的运行原理:
概念:连接到数据源可能需要很长时间。 为了最大程度地降低打开连接的成本,ADO.NET 使用一种称为连接池的优化技术,这会最大程度地降低重复打开和关闭连接的成本。
A. 当一个程序执行Connection.open()时候,ADO.Net就需要判断,此连接是否支持Connection Pool (Pooling 默认为True)
①:如果指定为False, ADO.Net就与数据库之间创建一个连接,然后返回给程序。
②:如果指定为 True,ADO.Net就会根据ConnectString创建一个Connection Pool,然后向Connection Pool中填充Connection。填充多少个Connection由Min Pool Size (默认为0)属性来决定。例如如果指定为5,则ADO.Net会一次与SQL数据库之间打开5个连接,然后将4个Connection,保存在 Connection Pool中,1个Connection返回给程序。
B. 当程序执行到Connection.close() 的时候。如果Pooling 为True,ADO.net 就把当前的Connection放到Connection Pool并且保持与数据库之间的连接。
同时还会判断Connection Lifetime(默认为0)属性,0代表无限大,如果Connection存在的时间超过了Connection LifeTime,ADO.net就会关闭的Connection同时断开与数据库的连接,而不是重新保存到Connection Pool中。
C. 当下一次Connection.Open() 执行的时候,ADO.Net就会判断新的ConnectionString与之前保存在Connection Pool中的Connection的connectionString是否一致。
D. ADO.Net需要判断当前的Connection Pool中是否有可以使用的Connection(没有被其他程序所占用),如果没有的话,ADO.Net就需要判断ConnectionString设 置的Max Pool Size (默认为100)
①. 如果Connection Pool中的所有Connection没有达到Max Pool Size,ADO.net则会再次连接数据库,创建一个连接,然后将Connection返回给程序。
②. 如果已经达到了 Max Pool Size,ADO.Net就不会再次创建任何新的连接,而是等待Connection Pool中被其他程序所占用的Connection释放,这个等待时间受SqlConnection.ConnectionTimeout(默认是15 秒)限制,也就是说如果时间超过了15秒,SqlConnection就会抛出超时错误。
E. 如果有可用的Connection,从Connection Pool 取出的Connection也不是直接就返回给程序,ADO.Net还需要检查ConnectionString的ConnectionReset属性 (默认为True)是否需要对Connection 做一次reset。
更详细的介绍请参考官方文档:https://docs.microsoft.com/zh-cn/dotnet/framework/data/adonet/sql-server-connection-pooling
7. 总结
(1).SaveChanges的时候数据库连接自动释放,所以不需要手动释放。
(2).调用using的方法可以,因为dispose里讲很多东西都滞空了,完全没问题;但在Core MVC中,EF上下文都是通过依赖注入,能控制生命周期,所以不再需要using。
(3).手动open然后手动close,连接数没有释放,因为连接池的概念,当然你可以手动配置连接池数目(强制删除连接池:ClearAllPools),只有当IIS关闭,连接才彻底释放。
二. 生命周期
1.源码分析
public enum ServiceLifetime { Singleton = 0, Scoped = 1, Transient = 2 }
(1).Singleton :整个应用程序生命周期以内只创建一个实例。
(2).Scoped: 在同一个Scope内只初始化一个实例 ,可以理解为(每一个 request 级别只创建一个实例)
(3).Transient: 每一次 GetService 都会创建一个新的实例。
注:默认是Scoped,即单次请求内是单例的。
可以自行配置:
通过查源码可知,默认就是Scoped的。
1 // 2 // 摘要: 3 // Extension methods for setting up Entity Framework related services in an Microsoft.Extensions.DependencyInjection.IServiceCollection. 4 public static class EntityFrameworkServiceCollectionExtensions 5 { 6 // 7 // 摘要: 8 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection. 9 // You use this method when using dependency injection in your application, such 10 // as with ASP.NET. For more information on setting up dependency injection, see 11 // http://go.microsoft.com/fwlink/?LinkId=526890. 12 // 13 // 参数: 14 // serviceCollection: 15 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 16 // to. 17 // 18 // optionsAction: 19 // An optional action to configure the Microsoft.EntityFrameworkCore.DbContextOptions 20 // for the context. This provides an alternative to performing configuration of 21 // the context by overriding the Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 22 // method in your derived context. 23 // If an action is supplied here, the Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 24 // method will still be run if it has been overridden on the derived context. Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 25 // configuration will be applied in addition to configuration performed here. 26 // In order for the options to be passed into your context, you need to expose a 27 // constructor on your context that takes Microsoft.EntityFrameworkCore.DbContextOptions`1 28 // and passes it to the base constructor of Microsoft.EntityFrameworkCore.DbContext. 29 // 30 // contextLifetime: 31 // The lifetime with which to register the DbContext service in the container. 32 // 33 // optionsLifetime: 34 // The lifetime with which to register the DbContextOptions service in the container. 35 // 36 // 类型参数: 37 // TContext: 38 // The type of context to be registered. 39 // 40 // 返回结果: 41 // The same service collection so that multiple calls can be chained. 42 public static IServiceCollection AddDbContext<TContext>([NotNullAttribute] this IServiceCollection serviceCollection, [CanBeNullAttribute] Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContext : DbContext; 43 // 44 // 摘要: 45 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection. 46 // You use this method when using dependency injection in your application, such 47 // as with ASP.NET. For more information on setting up dependency injection, see 48 // http://go.microsoft.com/fwlink/?LinkId=526890. 49 // 50 // 参数: 51 // serviceCollection: 52 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 53 // to. 54 // 55 // optionsAction: 56 // An optional action to configure the Microsoft.EntityFrameworkCore.DbContextOptions 57 // for the context. This provides an alternative to performing configuration of 58 // the context by overriding the Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 59 // method in your derived context. 60 // If an action is supplied here, the Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 61 // method will still be run if it has been overridden on the derived context. Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 62 // configuration will be applied in addition to configuration performed here. 63 // In order for the options to be passed into your context, you need to expose a 64 // constructor on your context that takes Microsoft.EntityFrameworkCore.DbContextOptions`1 65 // and passes it to the base constructor of Microsoft.EntityFrameworkCore.DbContext. 66 // 67 // contextLifetime: 68 // The lifetime with which to register the DbContext service in the container. 69 // 70 // optionsLifetime: 71 // The lifetime with which to register the DbContextOptions service in the container. 72 // 73 // 类型参数: 74 // TContextService: 75 // The class or interface that will be used to resolve the context from the container. 76 // 77 // TContextImplementation: 78 // The concrete implementation type to create. 79 // 80 // 返回结果: 81 // The same service collection so that multiple calls can be chained. 82 public static IServiceCollection AddDbContext<TContextService, TContextImplementation>([NotNullAttribute] this IServiceCollection serviceCollection, [CanBeNullAttribute] Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContextImplementation : DbContext, TContextService; 83 // 84 // 摘要: 85 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection. 86 // You use this method when using dependency injection in your application, such 87 // as with ASP.NET. For more information on setting up dependency injection, see 88 // http://go.microsoft.com/fwlink/?LinkId=526890. 89 // 90 // 参数: 91 // serviceCollection: 92 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 93 // to. 94 // 95 // contextLifetime: 96 // The lifetime with which to register the DbContext service in the container. 97 // 98 // optionsLifetime: 99 // The lifetime with which to register the DbContextOptions service in the container. 100 // 101 // 类型参数: 102 // TContext: 103 // The type of context to be registered. 104 // 105 // 返回结果: 106 // The same service collection so that multiple calls can be chained. 107 public static IServiceCollection AddDbContext<TContext>([NotNullAttribute] this IServiceCollection serviceCollection, ServiceLifetime contextLifetime, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContext : DbContext; 108 // 109 // 摘要: 110 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection. 111 // You use this method when using dependency injection in your application, such 112 // as with ASP.NET. For more information on setting up dependency injection, see 113 // http://go.microsoft.com/fwlink/?LinkId=526890. 114 // 115 // 参数: 116 // serviceCollection: 117 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 118 // to. 119 // 120 // contextLifetime: 121 // The lifetime with which to register the DbContext service in the container. 122 // 123 // optionsLifetime: 124 // The lifetime with which to register the DbContextOptions service in the container. 125 // 126 // 类型参数: 127 // TContextService: 128 // The class or interface that will be used to resolve the context from the container. 129 // 130 // TContextImplementation: 131 // The concrete implementation type to create. 132 // 133 // 返回结果: 134 // The same service collection so that multiple calls can be chained. 135 public static IServiceCollection AddDbContext<TContextService, TContextImplementation>([NotNullAttribute] this IServiceCollection serviceCollection, ServiceLifetime contextLifetime, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) 136 where TContextService : class 137 where TContextImplementation : DbContext, TContextService; 138 // 139 // 摘要: 140 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection. 141 // You use this method when using dependency injection in your application, such 142 // as with ASP.NET. For more information on setting up dependency injection, see 143 // http://go.microsoft.com/fwlink/?LinkId=526890. 144 // This overload has an optionsAction that provides the applications System.IServiceProvider. 145 // This is useful if you want to setup Entity Framework to resolve its internal 146 // services from the primary application service provider. By default, we recommend 147 // using the other overload, which allows Entity Framework to create and maintain 148 // its own System.IServiceProvider for internal Entity Framework services. 149 // 150 // 参数: 151 // serviceCollection: 152 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 153 // to. 154 // 155 // optionsAction: 156 // An optional action to configure the Microsoft.EntityFrameworkCore.DbContextOptions 157 // for the context. This provides an alternative to performing configuration of 158 // the context by overriding the Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 159 // method in your derived context. 160 // If an action is supplied here, the Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 161 // method will still be run if it has been overridden on the derived context. Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 162 // configuration will be applied in addition to configuration performed here. 163 // In order for the options to be passed into your context, you need to expose a 164 // constructor on your context that takes Microsoft.EntityFrameworkCore.DbContextOptions`1 165 // and passes it to the base constructor of Microsoft.EntityFrameworkCore.DbContext. 166 // 167 // contextLifetime: 168 // The lifetime with which to register the DbContext service in the container. 169 // 170 // optionsLifetime: 171 // The lifetime with which to register the DbContextOptions service in the container. 172 // 173 // 类型参数: 174 // TContext: 175 // The type of context to be registered. 176 // 177 // 返回结果: 178 // The same service collection so that multiple calls can be chained. 179 public static IServiceCollection AddDbContext<TContext>([NotNullAttribute] this IServiceCollection serviceCollection, [CanBeNullAttribute] Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContext : DbContext; 180 // 181 // 摘要: 182 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection. 183 // You use this method when using dependency injection in your application, such 184 // as with ASP.NET. For more information on setting up dependency injection, see 185 // http://go.microsoft.com/fwlink/?LinkId=526890. 186 // This overload has an optionsAction that provides the applications System.IServiceProvider. 187 // This is useful if you want to setup Entity Framework to resolve its internal 188 // services from the primary application service provider. By default, we recommend 189 // using the other overload, which allows Entity Framework to create and maintain 190 // its own System.IServiceProvider for internal Entity Framework services. 191 // 192 // 参数: 193 // serviceCollection: 194 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 195 // to. 196 // 197 // optionsAction: 198 // An optional action to configure the Microsoft.EntityFrameworkCore.DbContextOptions 199 // for the context. This provides an alternative to performing configuration of 200 // the context by overriding the Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 201 // method in your derived context. 202 // If an action is supplied here, the Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 203 // method will still be run if it has been overridden on the derived context. Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 204 // configuration will be applied in addition to configuration performed here. 205 // In order for the options to be passed into your context, you need to expose a 206 // constructor on your context that takes Microsoft.EntityFrameworkCore.DbContextOptions`1 207 // and passes it to the base constructor of Microsoft.EntityFrameworkCore.DbContext. 208 // 209 // contextLifetime: 210 // The lifetime with which to register the DbContext service in the container. 211 // 212 // optionsLifetime: 213 // The lifetime with which to register the DbContextOptions service in the container. 214 // 215 // 类型参数: 216 // TContextService: 217 // The class or interface that will be used to resolve the context from the container. 218 // 219 // TContextImplementation: 220 // The concrete implementation type to create. 221 // 222 // 返回结果: 223 // The same service collection so that multiple calls can be chained. 224 public static IServiceCollection AddDbContext<TContextService, TContextImplementation>([NotNullAttribute] this IServiceCollection serviceCollection, [CanBeNullAttribute] Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContextImplementation : DbContext, TContextService; 225 // 226 // 摘要: 227 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection 228 // and enables DbContext pooling. Instance pooling can increase throughput in high-scale 229 // scenarios such as web servers by re-using DbContext instances, rather than creating 230 // new instances for each request. You use this method when using dependency injection 231 // in your application, such as with ASP.NET. For more information on setting up 232 // dependency injection, see http://go.microsoft.com/fwlink/?LinkId=526890. 233 // 234 // 参数: 235 // serviceCollection: 236 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 237 // to. 238 // 239 // optionsAction: 240 // A required action to configure the Microsoft.EntityFrameworkCore.DbContextOptions 241 // for the context. When using context pooling, options configuration must be performed 242 // externally; Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 243 // will not be called. 244 // 245 // poolSize: 246 // Sets the maximum number of instances retained by the pool. 247 // 248 // 类型参数: 249 // TContext: 250 // The type of context to be registered. 251 // 252 // 返回结果: 253 // The same service collection so that multiple calls can be chained. 254 public static IServiceCollection AddDbContextPool<TContext>([NotNullAttribute] this IServiceCollection serviceCollection, [NotNullAttribute] Action<DbContextOptionsBuilder> optionsAction, int poolSize = 128) where TContext : DbContext; 255 // 256 // 摘要: 257 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection 258 // and enables DbContext pooling. Instance pooling can increase throughput in high-scale 259 // scenarios such as web servers by re-using DbContext instances, rather than creating 260 // new instances for each request. You use this method when using dependency injection 261 // in your application, such as with ASP.NET. For more information on setting up 262 // dependency injection, see http://go.microsoft.com/fwlink/?LinkId=526890. 263 // 264 // 参数: 265 // serviceCollection: 266 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 267 // to. 268 // 269 // optionsAction: 270 // A required action to configure the Microsoft.EntityFrameworkCore.DbContextOptions 271 // for the context. When using context pooling, options configuration must be performed 272 // externally; Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 273 // will not be called. 274 // 275 // poolSize: 276 // Sets the maximum number of instances retained by the pool. 277 // 278 // 类型参数: 279 // TContextService: 280 // The class or interface that will be used to resolve the context from the container. 281 // 282 // TContextImplementation: 283 // The concrete implementation type to create. 284 // 285 // 返回结果: 286 // The same service collection so that multiple calls can be chained. 287 public static IServiceCollection AddDbContextPool<TContextService, TContextImplementation>([NotNullAttribute] this IServiceCollection serviceCollection, [NotNullAttribute] Action<DbContextOptionsBuilder> optionsAction, int poolSize = 128) 288 where TContextService : class 289 where TContextImplementation : DbContext, TContextService; 290 // 291 // 摘要: 292 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection 293 // and enables DbContext pooling. Instance pooling can increase throughput in high-scale 294 // scenarios such as web servers by re-using DbContext instances, rather than creating 295 // new instances for each request. You use this method when using dependency injection 296 // in your application, such as with ASP.NET. For more information on setting up 297 // dependency injection, see http://go.microsoft.com/fwlink/?LinkId=526890. 298 // This overload has an optionsAction that provides the applications System.IServiceProvider. 299 // This is useful if you want to setup Entity Framework to resolve its internal 300 // services from the primary application service provider. By default, we recommend 301 // using the other overload, which allows Entity Framework to create and maintain 302 // its own System.IServiceProvider for internal Entity Framework services. 303 // 304 // 参数: 305 // serviceCollection: 306 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 307 // to. 308 // 309 // optionsAction: 310 // A required action to configure the Microsoft.EntityFrameworkCore.DbContextOptions 311 // for the context. When using context pooling, options configuration must be performed 312 // externally; Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 313 // will not be called. 314 // 315 // poolSize: 316 // Sets the maximum number of instances retained by the pool. 317 // 318 // 类型参数: 319 // TContext: 320 // The type of context to be registered. 321 // 322 // 返回结果: 323 // The same service collection so that multiple calls can be chained. 324 public static IServiceCollection AddDbContextPool<TContext>([NotNullAttribute] this IServiceCollection serviceCollection, [NotNullAttribute] Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, int poolSize = 128) where TContext : DbContext; 325 // 326 // 摘要: 327 // Registers the given context as a service in the Microsoft.Extensions.DependencyInjection.IServiceCollection 328 // and enables DbContext pooling. Instance pooling can increase throughput in high-scale 329 // scenarios such as web servers by re-using DbContext instances, rather than creating 330 // new instances for each request. You use this method when using dependency injection 331 // in your application, such as with ASP.NET. For more information on setting up 332 // dependency injection, see http://go.microsoft.com/fwlink/?LinkId=526890. 333 // This overload has an optionsAction that provides the applications System.IServiceProvider. 334 // This is useful if you want to setup Entity Framework to resolve its internal 335 // services from the primary application service provider. By default, we recommend 336 // using the other overload, which allows Entity Framework to create and maintain 337 // its own System.IServiceProvider for internal Entity Framework services. 338 // 339 // 参数: 340 // serviceCollection: 341 // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services 342 // to. 343 // 344 // optionsAction: 345 // A required action to configure the Microsoft.EntityFrameworkCore.DbContextOptions 346 // for the context. When using context pooling, options configuration must be performed 347 // externally; Microsoft.EntityFrameworkCore.DbContext.OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder) 348 // will not be called. 349 // 350 // poolSize: 351 // Sets the maximum number of instances retained by the pool. 352 // 353 // 类型参数: 354 // TContextService: 355 // The class or interface that will be used to resolve the context from the container. 356 // 357 // TContextImplementation: 358 // The concrete implementation type to create. 359 // 360 // 返回结果: 361 // The same service collection so that multiple calls can be chained. 362 public static IServiceCollection AddDbContextPool<TContextService, TContextImplementation>([NotNullAttribute] this IServiceCollection serviceCollection, [NotNullAttribute] Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, int poolSize = 128) 363 where TContextService : class 364 where TContextImplementation : DbContext, TContextService; 365 }
2. 测试案例
在EF上下文的构造函数中生成一个Guid,如果是单例的,构造函数只会被调用一次,我们通过比较两个上下文是否相等 或者 比较单次、多次请求中Guid的值是否相同来验证依赖注入的上下文的各种生命周期。
1 public EFDB01Context context1; 2 public EFDB01Context context2; 3 public FirstController(EFDB01Context db1, EFDB01Context db2) 4 { 5 context1 = db1; 6 context2 = db2; 7 } 8 /// <summary> 9 /// 生命周期测试 10 /// </summary> 11 public IActionResult TestLifeTime() 12 { 13 //测试方法一(判断两个上下文是否完全相同) 14 bool isSame1 = object.ReferenceEquals(context1,context2); 15 ViewBag.isSame = isSame1; 16 17 //测试方法二(通过多次请求来判断Guid值是否相等) 18 ViewBag.MyGuid1 = context1.myGuid; 19 ViewBag.MyGuid2 = context2.myGuid; 20 21 return View(); 22 }
(1).将参数设置为Singleton: 每次请求的context1和context2的值相等,单次请求和多次请求MyGuid1、MyGuid2的值均相等,从而证明是全局单例的。
(2).将参数设置为Scoped:每次请求的context1和context2的值相等,单次请求中MyGuid1和MyGuid2的值相等,多次请求的情况下,每次产生的MyGuid1之间均不相同, 每次产生的MyGuid2之间均不相同,从而证明是请求内单例的。
(3).将参数设置为Transient:每次请求的context1和context2的值不相等,单次请求中MyGuid1和MyGuid2的值也不相等,多次请求的情况下,每次产生的MyGuid1之间均不相同, 每次产生的MyGuid2之间均不相同,从而证明是瞬时的。
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。