From ec2fcfb419ddca9ec902abc76f322aadbca3f617 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Sun, 10 Mar 2019 21:23:06 +0800 Subject: [PATCH] v0.1.14 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加 延时属性编译错误信息; - 优化 FreeSql.Repository Autofac 泛型注入; --- Examples/repository_01/Startup.cs | 83 +++++++++- Examples/repository_01/repository_01.csproj | 2 +- FreeSql.Repository/DependencyInjection.cs | 155 ++++++++++++------ FreeSql.Repository/FreeSql.Repository.csproj | 2 +- FreeSql/FreeSql.csproj | 6 +- FreeSql/Internal/UtilsExpressionTree.cs | 9 +- FreeSql/MySql/MySqlAdo/MySqlConnectionPool.cs | 23 ++- .../Oracle/OracleAdo/OracleConnectionPool.cs | 21 ++- .../PostgreSQLAdo/PostgreSQLConnectionPool.cs | 21 ++- .../SqlServerAdo/SqlServerConnectionPool.cs | 21 ++- .../Sqlite/SqliteAdo/SqliteConnectionPool.cs | 21 ++- 11 files changed, 277 insertions(+), 87 deletions(-) diff --git a/Examples/repository_01/Startup.cs b/Examples/repository_01/Startup.cs index e981f6d3..db53c365 100644 --- a/Examples/repository_01/Startup.cs +++ b/Examples/repository_01/Startup.cs @@ -1,5 +1,6 @@ using Autofac; using Autofac.Extensions.DependencyInjection; +using FreeSql.DataAnnotations; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; @@ -11,6 +12,77 @@ using System; using System.Text; namespace repository_01 { + + public interface IBaseModel { + + TKey Id { get; set; } + } + + /// + /// 用户密码信息 + /// + public class SysUserLogOn : IBaseModel { + [Column(IsPrimary = true)] + public Guid Id { get; set; } = Guid.NewGuid(); + + public Guid SysUserId { get; set; } + + public string UserPassword { get; set; } + [Column(DbType = "varchar(100)")] + public string UserSecretkey { get; set; } + public DateTime PreviousVisitTime { get; set; } = DateTime.Now; + public DateTime LastVisitTime { get; set; } = DateTime.Now; + public int LogOnCount { get; set; } + + + public virtual SysUser SysUser { get; set; } + } + public class SysUser : IBaseModel { + [Column(IsPrimary = true)] + public Guid Id { get; set; } = Guid.NewGuid(); + + [Column(DbType = "varchar(50)")] + public string AccountName { get; set; } + [Column(DbType = "varchar(50)")] + public string Name { get; set; } + public string HeadIcon { get; set; } + public Gender Gender { get; set; } = Gender.Man; + public DateTime Birthday { get; set; } = DateTime.MinValue; + [Column(DbType = "varchar(100)")] + public string MobilePhone { get; set; } + public string Email { get; set; } + public string WeChat { get; set; } + public string Description { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public Guid? CreateUserId { get; set; } + public DateTime LastModifyTime { get; set; } = DateTime.Now; + public Guid? LastModifyUserId { get; set; } + + + + + public AccountState State { get; set; } = AccountState.Normal; + + } + public enum Gender { + Man = 1, + Woman = 2, + } + + public enum AccountState { + /// + /// 正常 + /// + Normal = 1, + /// + /// 被禁用 + /// + Disabled = 2, + /// + /// 已注销 + /// + Closed = 3 + } public class Startup { public Startup(IConfiguration configuration, ILoggerFactory loggerFactory) { Configuration = configuration; @@ -19,7 +91,14 @@ namespace repository_01 { .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10") .UseLogger(loggerFactory.CreateLogger()) .UseAutoSyncStructure(true) + .UseLazyLoading(true) .Build(); + + var sysu = new SysUser { }; + Fsql.Insert().AppendData(sysu).ExecuteAffrows(); + Fsql.Insert().AppendData(new SysUserLogOn { SysUserId = sysu.Id }).ExecuteAffrows(); + var a = Fsql.Select().ToList(); + var b = Fsql.Select().Any(); } public IConfiguration Configuration { get; } @@ -41,8 +120,8 @@ namespace repository_01 { var builder = new ContainerBuilder(); - builder.RegisterFreeRepository(a => a.Id == 1); - builder.RegisterFreeGuidRepository(a => a.Id == 1, oldname => $"{oldname}_{DateTime.Now.Year}"); + builder.RegisterFreeRepositoryAddFilter(() => a => a.Title == DateTime.Now.ToString() + System.Threading.Thread.CurrentThread.ManagedThreadId); + //builder.RegisterFreeGuidRepository(a => a.Id == 1, oldname => $"{oldname}_{DateTime.Now.Year}"); builder.Populate(services); var container = builder.Build(); diff --git a/Examples/repository_01/repository_01.csproj b/Examples/repository_01/repository_01.csproj index 3905e922..7ac6fd4d 100644 --- a/Examples/repository_01/repository_01.csproj +++ b/Examples/repository_01/repository_01.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + netcoreapp2.1 InProcess diff --git a/FreeSql.Repository/DependencyInjection.cs b/FreeSql.Repository/DependencyInjection.cs index 84ca2729..50c87bb4 100644 --- a/FreeSql.Repository/DependencyInjection.cs +++ b/FreeSql.Repository/DependencyInjection.cs @@ -8,62 +8,123 @@ using System.Reflection; public static class FreeSqlRepositoryAutofacDependencyInjection { - public static void RegisterFreeGuidRepository(this ContainerBuilder builder, Expression> filter, Func asTable) => - builder.RegisterRepository(filter, asTable, 1); - public static void RegisterFreeRepository(this ContainerBuilder builder, Expression> filter) => - builder.RegisterRepository(filter, null, 2); + public static void RegisterFreeRepository(this ContainerBuilder builder) => RegisterFreeRepositoryPrivate(builder, null, null); + public static void RegisterFreeRepositoryAddFilter(this ContainerBuilder builder, Func>> filterHandler) => RegisterFreeRepositoryPrivate(builder, filterHandler, null); - static void RegisterRepository(this ContainerBuilder builder, Expression> filter, Func asTable, int regType) { + static ConcurrentDictionary _dicRegisterFreeRepositorySetFilterFunc = new ConcurrentDictionary(); + static ConcurrentDictionary _dicRegisterFreeRepositorySetAsTableFunc = new ConcurrentDictionary(); + static void RegisterFreeRepositoryPrivate(ContainerBuilder builder, Func>> filterHandler, Func asTableHandler) { - Func reposFunc = type => { + Func setFilterFunc = reposType => _dicRegisterFreeRepositorySetFilterFunc.GetOrAdd(reposType, type => { + var reposParameter = Expression.Parameter(type); + var fitlerParameter = Expression.Parameter(typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(type.GenericTypeArguments[0], typeof(bool)))); + return Expression.Lambda( + Expression.Block( + Expression.Call(reposParameter, type.GetMethod("set_Filter", BindingFlags.Instance | BindingFlags.NonPublic), fitlerParameter) + ), + new[] { + reposParameter, fitlerParameter + } + ).Compile(); + }); + Func convertFilter = type => { + var filter = filterHandler?.Invoke(); + if (filter == null) return null; var entityType = type.GenericTypeArguments[0]; var filterParameter1 = Expression.Parameter(entityType, filter.Parameters[0].Name); - var convertFilter = Expression.Lambda( - typeof(Func<,>).MakeGenericType(entityType, typeof(bool)), - new ReplaceVisitor().Modify(filter.Body, filterParameter1), - filterParameter1 - ); - var repos = Expression.Parameter(type); - var blocks = new List(); - if (filter != null) blocks.Add(Expression.Call(repos, type.GetMethod("set_Filter", BindingFlags.Instance | BindingFlags.NonPublic), Expression.Constant(convertFilter))); - if (asTable != null) blocks.Add(Expression.Call(repos, type.GetMethod("set_AsTable", BindingFlags.Instance | BindingFlags.NonPublic), Expression.Constant(asTable))); - return Expression.Lambda( - //Expression.New( - // typeof(GuidRepository<>).MakeGenericType(type.GenericTypeArguments).GetConstructors()[1], - // Expression.Constant(a.Context.Resolve()), - // Expression.Constant(convertFilter), - // Expression.Constant(asTable) - //) - Expression.Block(blocks), - repos - ); + try { + return Expression.Lambda( + typeof(Func<,>).MakeGenericType(entityType, typeof(bool)), + new ReplaceVisitor().Modify(filter.Body, filterParameter1), + filterParameter1 + ); + } catch { + return null; + } }; - if (regType == 1) - builder.RegisterGeneric(typeof(GuidRepository<>)).As( - typeof(GuidRepository<>), - typeof(BaseRepository<>), typeof(BaseRepository<,>), - typeof(IBasicRepository<>), typeof(IBasicRepository<,>), - typeof(IReadOnlyRepository<>), typeof(IReadOnlyRepository<,>) - ).OnActivating(a => { - if (filter != null) - _dicAddGuidRepositoryFunc.GetOrAdd(a.Instance.GetType(), t => reposFunc(t).Compile()).DynamicInvoke(a.Instance); - }).InstancePerDependency(); + builder.RegisterGeneric(typeof(GuidRepository<>)).As( + typeof(GuidRepository<>), + typeof(BaseRepository<>), + typeof(IBasicRepository<>), + typeof(IReadOnlyRepository<>) + ).OnActivating(a => { + if (filterHandler != null) { + var type = a.Instance.GetType(); + setFilterFunc(type)?.DynamicInvoke(a.Instance, convertFilter(type)); + } + }).InstancePerDependency(); - - if (regType == 2) - builder.RegisterGeneric(typeof(DefaultRepository<,>)).As( - typeof(DefaultRepository<,>), - typeof(BaseRepository<,>), - typeof(IBasicRepository<,>), - typeof(IReadOnlyRepository<,>) - ).OnActivating(a => { - if (filter != null) - _dicAddGuidRepositoryFunc.GetOrAdd(a.Instance.GetType(), t => reposFunc(t).Compile()).DynamicInvoke(a.Instance); - }).InstancePerDependency(); + builder.RegisterGeneric(typeof(DefaultRepository<,>)).As( + typeof(DefaultRepository<,>), + typeof(BaseRepository<,>), + typeof(IBasicRepository<,>), + typeof(IReadOnlyRepository<,>) + ).OnActivating(a => { + if (filterHandler != null) { + var type = a.Instance.GetType(); + setFilterFunc(type)?.DynamicInvoke(a.Instance, convertFilter(type)); + } + }).InstancePerDependency(); } - static ConcurrentDictionary _dicAddGuidRepositoryFunc = new ConcurrentDictionary(); + //static void RegisterRepository(this ContainerBuilder builder, Expression> filter, Func asTable, int regType) { + + // Func reposFunc = type => { + // var entityType = type.GenericTypeArguments[0]; + // var filterParameter1 = Expression.Parameter(entityType, filter.Parameters[0].Name); + // var convertFilter = Expression.Lambda( + // typeof(Func<,>).MakeGenericType(entityType, typeof(bool)), + // new ReplaceVisitor().Modify(filter.Body, filterParameter1), + // filterParameter1 + // ); + // var repos = Expression.Parameter(type); + // var blocks = new List(); + // if (filter != null) blocks.Add(Expression.Call(repos, type.GetMethod("set_Filter", BindingFlags.Instance | BindingFlags.NonPublic), Expression.Constant(convertFilter))); + // if (asTable != null) blocks.Add(Expression.Call(repos, type.GetMethod("set_AsTable", BindingFlags.Instance | BindingFlags.NonPublic), Expression.Constant(asTable))); + // return Expression.Lambda( + // //Expression.New( + // // typeof(GuidRepository<>).MakeGenericType(type.GenericTypeArguments).GetConstructors()[1], + // // Expression.Constant(a.Context.Resolve()), + // // Expression.Constant(convertFilter), + // // Expression.Constant(asTable) + // //) + // Expression.Block(blocks), + // repos + // ); + // }; + + // if (regType == 1) + // builder.RegisterGeneric(typeof(GuidRepository<>)).As( + // typeof(GuidRepository<>), + // typeof(BaseRepository<>), typeof(BaseRepository<,>), + // typeof(IBasicRepository<>), typeof(IBasicRepository<,>), + // typeof(IReadOnlyRepository<>), typeof(IReadOnlyRepository<,>) + // ).OnActivating(a => { + // if (filter != null) + // _dicAddGuidRepositoryFunc.GetOrAdd(a.Instance.GetType(), t => { + // try { reposFunc(t).Compile(); } catch { } + // return null; + // })?.DynamicInvoke(a.Instance); + // }).InstancePerDependency(); + + + // if (regType == 2) + // builder.RegisterGeneric(typeof(DefaultRepository<,>)).As( + // typeof(DefaultRepository<,>), + // typeof(BaseRepository<,>), + // typeof(IBasicRepository<,>), + // typeof(IReadOnlyRepository<,>) + // ).OnActivating(a => { + // if (filter != null) + // _dicAddGuidRepositoryFunc.GetOrAdd(a.Instance.GetType(), t => { + // try { reposFunc(t).Compile(); } catch { } + // return null; + // })?.DynamicInvoke(a.Instance); + // }).InstancePerDependency(); + //} + + //static ConcurrentDictionary _dicAddGuidRepositoryFunc = new ConcurrentDictionary(); class ReplaceVisitor : ExpressionVisitor { private ParameterExpression parameter; diff --git a/FreeSql.Repository/FreeSql.Repository.csproj b/FreeSql.Repository/FreeSql.Repository.csproj index ddb7266b..05cdce70 100644 --- a/FreeSql.Repository/FreeSql.Repository.csproj +++ b/FreeSql.Repository/FreeSql.Repository.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 0.1.13 + 0.1.14 YeXiangQin FreeSql 通用仓库层实现,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite,读写分离、分表分库。 https://github.com/2881099/FreeSql diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj index 0218f987..c9b9a504 100644 --- a/FreeSql/FreeSql.csproj +++ b/FreeSql/FreeSql.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 0.1.13 + 0.1.14 true YeXiangQin 打造 .NETCore 最方便的 ORM,DbFirst 与 CodeFirst 混合使用,提供从实体同步数据库,或者从数据库生成实体代码,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite,读写分离、分表分库。 @@ -20,8 +20,8 @@ - - + + diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index 04806f9f..f4246b50 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -449,8 +449,13 @@ namespace FreeSql.Internal { } if (overrieds > 0) { cscode.AppendLine("}"); - var assemly = Generator.TemplateEngin._compiler.Value.CompileCode(cscode.ToString()); - var type = assemly.DefinedTypes.Where(a => a.FullName.EndsWith(trytbTypeLazyName)).FirstOrDefault(); + Assembly assembly = null; + try { + assembly = Generator.TemplateEngin._compiler.Value.CompileCode(cscode.ToString()); + } catch (Exception ex) { + throw new Exception($"【延时加载】{trytbTypeName} 编译错误:{ex.Message}\r\n\r\n{cscode}"); + } + var type = assembly.DefinedTypes.Where(a => a.FullName.EndsWith(trytbTypeLazyName)).FirstOrDefault(); trytb.TypeLazy = type; trytb.TypeLazySetOrm = type.GetProperty("__fsql_orm__", BindingFlags.Instance | BindingFlags.NonPublic).GetSetMethod(true); } diff --git a/FreeSql/MySql/MySqlAdo/MySqlConnectionPool.cs b/FreeSql/MySql/MySqlAdo/MySqlConnectionPool.cs index f86267e7..5630c6a7 100644 --- a/FreeSql/MySql/MySqlAdo/MySqlConnectionPool.cs +++ b/FreeSql/MySql/MySqlAdo/MySqlConnectionPool.cs @@ -41,6 +41,7 @@ namespace FreeSql.MySql { public string Name { get; set; } = "MySql MySqlConnection 对象池"; public int PoolSize { get; set; } = 100; public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero; public int AsyncGetCapacity { get; set; } = 10000; public bool IsThrowGetTimeoutException { get; set; } = true; public int CheckAvailableInterval { get; set; } = 5; @@ -50,17 +51,25 @@ namespace FreeSql.MySql { public string ConnectionString { get => _connectionString; set { - var connStr = value ?? ""; - var poolsizePatern = @"Max\s*pool\s*size\s*=\s*(\d+)"; - Match m = Regex.Match(connStr, poolsizePatern, RegexOptions.IgnoreCase); + _connectionString = value ?? ""; + + var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)"; + var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100; - var connStrIncr = dicConnStrIncr.AddOrUpdate(connStr, 1, (oldkey, oldval) => oldval + 1); + var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => oldval + 1); PoolSize = poolsize + connStrIncr; _connectionString = m.Success ? - Regex.Replace(connStr, poolsizePatern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) : - $"{connStr};Max pool size={PoolSize}"; + Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) : + $"{_connectionString};Max pool size={PoolSize}"; - var initConns = new List>(); + pattern = @"Connection\s*LifeTime\s*=\s*(\d+)"; + m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); + if (m.Success) { + IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value)); + _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase); + } + + var initConns = new List>(); for (var a = 0; a < PoolSize; a++) try { var conn = _pool.Get(); diff --git a/FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs b/FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs index 1ba5e205..9db33d4d 100644 --- a/FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs +++ b/FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs @@ -55,6 +55,7 @@ namespace FreeSql.Oracle { public string Name { get; set; } = "Oracle Connection 对象池"; public int PoolSize { get; set; } = 100; public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero; public int AsyncGetCapacity { get; set; } = 10000; public bool IsThrowGetTimeoutException { get; set; } = true; public int CheckAvailableInterval { get; set; } = 5; @@ -64,15 +65,23 @@ namespace FreeSql.Oracle { public string ConnectionString { get => _connectionString; set { - var connStr = value ?? ""; - var poolsizePatern = @"Max\s*pool\s*size\s*=\s*(\d+)"; - Match m = Regex.Match(connStr, poolsizePatern, RegexOptions.IgnoreCase); + _connectionString = value ?? ""; + + var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)"; + Match m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100; - var connStrIncr = dicConnStrIncr.AddOrUpdate(connStr, 1, (oldkey, oldval) => oldval + 1); + var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => oldval + 1); PoolSize = poolsize + connStrIncr; _connectionString = m.Success ? - Regex.Replace(connStr, poolsizePatern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) : - $"{connStr};Max pool size={PoolSize}"; + Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) : + $"{_connectionString};Max pool size={PoolSize}"; + + pattern = @"Connection\s*LifeTime\s*=\s*(\d+)"; + m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); + if (m.Success) { + IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value)); + _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase); + } var initConns = new List>(); for (var a = 0; a < PoolSize; a++) diff --git a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLConnectionPool.cs b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLConnectionPool.cs index e79c2d91..7e418b76 100644 --- a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLConnectionPool.cs +++ b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLConnectionPool.cs @@ -50,6 +50,7 @@ namespace FreeSql.PostgreSQL { public string Name { get; set; } = "PostgreSQL NpgsqlConnection 对象池"; public int PoolSize { get; set; } = 50; public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero; public int AsyncGetCapacity { get; set; } = 10000; public bool IsThrowGetTimeoutException { get; set; } = true; public int CheckAvailableInterval { get; set; } = 5; @@ -59,15 +60,23 @@ namespace FreeSql.PostgreSQL { public string ConnectionString { get => _connectionString; set { - var connStr = value ?? ""; - var poolsizePatern = @"Maximum\s*pool\s*size\s*=\s*(\d+)"; - Match m = Regex.Match(connStr, poolsizePatern, RegexOptions.IgnoreCase); + _connectionString = value ?? ""; + + var pattern = @"Maximum\s*pool\s*size\s*=\s*(\d+)"; + Match m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100; - var connStrIncr = dicConnStrIncr.AddOrUpdate(connStr, 1, (oldkey, oldval) => oldval + 1); + var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => oldval + 1); PoolSize = poolsize + connStrIncr; _connectionString = m.Success ? - Regex.Replace(connStr, poolsizePatern, $"Maximum pool size={PoolSize}", RegexOptions.IgnoreCase) : - $"{connStr};Maximum pool size={PoolSize}"; + Regex.Replace(_connectionString, pattern, $"Maximum pool size={PoolSize}", RegexOptions.IgnoreCase) : + $"{_connectionString};Maximum pool size={PoolSize}"; + + pattern = @"Connection\s*LifeTime\s*=\s*(\d+)"; + m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); + if (m.Success) { + IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value)); + _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase); + } var initConns = new List>(); for (var a = 0; a < PoolSize; a++) diff --git a/FreeSql/SqlServer/SqlServerAdo/SqlServerConnectionPool.cs b/FreeSql/SqlServer/SqlServerAdo/SqlServerConnectionPool.cs index 81653ee4..ee55a758 100644 --- a/FreeSql/SqlServer/SqlServerAdo/SqlServerConnectionPool.cs +++ b/FreeSql/SqlServer/SqlServerAdo/SqlServerConnectionPool.cs @@ -45,6 +45,7 @@ namespace FreeSql.SqlServer { public string Name { get; set; } = "SqlServer SqlConnection 对象池"; public int PoolSize { get; set; } = 100; public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero; public int AsyncGetCapacity { get; set; } = 10000; public bool IsThrowGetTimeoutException { get; set; } = true; public int CheckAvailableInterval { get; set; } = 5; @@ -54,15 +55,23 @@ namespace FreeSql.SqlServer { public string ConnectionString { get => _connectionString; set { - var connStr = value ?? ""; - var poolsizePatern = @"Max\s*pool\s*size\s*=\s*(\d+)"; - Match m = Regex.Match(connStr, poolsizePatern, RegexOptions.IgnoreCase); + _connectionString = value ?? ""; + + var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)"; + Match m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100; - var connStrIncr = dicConnStrIncr.AddOrUpdate(connStr, 1, (oldkey, oldval) => oldval + 1); + var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => oldval + 1); PoolSize = poolsize + connStrIncr; _connectionString = m.Success ? - Regex.Replace(connStr, poolsizePatern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) : - $"{connStr};Max pool size={PoolSize}"; + Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) : + $"{_connectionString};Max pool size={PoolSize}"; + + pattern = @"Connection\s*LifeTime\s*=\s*(\d+)"; + m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); + if (m.Success) { + IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value)); + _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase); + } var initConns = new List>(); for (var a = 0; a < PoolSize; a++) diff --git a/FreeSql/Sqlite/SqliteAdo/SqliteConnectionPool.cs b/FreeSql/Sqlite/SqliteAdo/SqliteConnectionPool.cs index a50f8743..6dd5fa08 100644 --- a/FreeSql/Sqlite/SqliteAdo/SqliteConnectionPool.cs +++ b/FreeSql/Sqlite/SqliteAdo/SqliteConnectionPool.cs @@ -45,6 +45,7 @@ namespace FreeSql.Sqlite { public string Name { get; set; } = "Sqlite SQLiteConnection 对象池"; public int PoolSize { get; set; } = 100; public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero; public int AsyncGetCapacity { get; set; } = 10000; public bool IsThrowGetTimeoutException { get; set; } = true; public int CheckAvailableInterval { get; set; } = 5; @@ -55,15 +56,23 @@ namespace FreeSql.Sqlite { public string ConnectionString { get => _connectionString; set { - var connStr = value ?? ""; - var poolsizePatern = @"Max\s*pool\s*size\s*=\s*(\d+)"; - Match m = Regex.Match(connStr, poolsizePatern, RegexOptions.IgnoreCase); + _connectionString = value ?? ""; + + var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)"; + Match m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100; - var connStrIncr = dicConnStrIncr.AddOrUpdate(connStr, 1, (oldkey, oldval) => oldval + 1); + var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => oldval + 1); PoolSize = poolsize + connStrIncr; _connectionString = m.Success ? - Regex.Replace(connStr, poolsizePatern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) : - $"{connStr};Max pool size={PoolSize}"; + Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) : + $"{_connectionString};Max pool size={PoolSize}"; + + pattern = @"Connection\s*LifeTime\s*=\s*(\d+)"; + m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); + if (m.Success) { + IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value)); + _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase); + } var att = Regex.Split(_connectionString, @"Attachs\s*=\s*", RegexOptions.IgnoreCase); if (att.Length == 2) {