Skip to content

Commit 9feb5ca

Browse files
committed
#35 enhanced the shared db connection to track threads and the number of connections defined per thread.
1 parent 58f9a78 commit 9feb5ca

File tree

9 files changed

+83
-38
lines changed

9 files changed

+83
-38
lines changed

SubSonic/Extensions/Internal/Objects.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ namespace SubSonic
1414
/// </remarks>
1515
internal static partial class InternalExtensions
1616
{
17+
public static bool IsIntGreaterThan(this object left, object right)
18+
{
19+
if (left is int _left)
20+
{
21+
if (right is int _right)
22+
{
23+
return _left > _right;
24+
}
25+
}
26+
27+
return false;
28+
}
1729
public static bool IsOfType<TType>(this object source)
1830
{
1931
return IsOfType(source, typeof(TType));

SubSonic/Infrastructure/Builders/DbSqlQueryBuilder/DbSqlQueryBuilderAsyncQueryProvider.cs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,7 @@ await Scope.Connection.OpenAsync(cancellationToken)
8080
{
8181
dbQuery.CleanUpParameters();
8282

83-
if (!(Scope.Connection is null))
84-
{
85-
Scope.Connection.Close();
86-
}
83+
Scope.Connection.Close();
8784
}
8885
}
8986
}
@@ -217,7 +214,7 @@ public async IAsyncEnumerable<TResult> ExecuteAsync<TResult>([NotNull] Expressio
217214
throw Error.ArgumentNull(nameof(query));
218215
}
219216

220-
using SharedDbConnectionScope Scope = DbContext.ServiceProvider.GetService<SharedDbConnectionScope>();
217+
using SharedDbConnectionScope Scope = DbContext.Current.UseSharedDbConnection();
221218
IDbQuery dbQuery = ToQuery(query);
222219

223220
Type elementType = query.Type.GetQualifiedType();
@@ -226,8 +223,6 @@ public async IAsyncEnumerable<TResult> ExecuteAsync<TResult>([NotNull] Expressio
226223

227224
try
228225
{
229-
await Scope.Connection.OpenAsync(cancellationToken)
230-
.ConfigureAwait(false);
231226
if (isEntityModel)
232227
{
233228
using (DbDataReader reader = await Scope.Database
@@ -259,13 +254,11 @@ await Scope.Connection.OpenAsync(cancellationToken)
259254
}
260255
finally
261256
{
262-
if (Scope.Connection != null)
263-
{
264-
await Scope.Connection
265-
.CloseAsync()
266-
.ConfigureAwait(false);
267-
}
268-
257+
#if NETSTANDARD2_1
258+
await Scope.Connection.CloseAsync().ConfigureAwait(true);
259+
#else
260+
Scope.Connection.Close();
261+
#endif
269262
dbQuery.CleanUpParameters();
270263
}
271264
}

SubSonic/Infrastructure/Builders/DbSqlQueryBuilder/DbSqlQueryBuilderQueryProvider.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace SubSonic.Infrastructure.Builders
1313
using Linq;
1414
using Linq.Expressions;
1515
using Logging;
16+
using System.Globalization;
1617

1718
public partial class DbSqlQueryBuilder
1819
{
@@ -146,10 +147,20 @@ public TResult Execute<TResult>(Expression expression)
146147
{
147148
if (BuildSelect(dbSelect, where) is DbSelectExpression select)
148149
{
149-
return Execute<TResult>(DbExpression.DbSelectAggregate(select, new[]
150+
TResult result = Execute<TResult>(DbExpression.DbSelectAggregate(select, new[]
150151
{
151152
DbExpression.DbAggregate(typeof(TResult), AggregateType.Count, select.Columns.First(x => x.Property.IsPrimaryKey).Expression)
152153
}));
154+
155+
if (select.Take is ConstantExpression take)
156+
{
157+
if (result.IsIntGreaterThan(take.Value))
158+
{
159+
return (TResult)Convert.ChangeType(take.Value, typeof(TResult), CultureInfo.InvariantCulture);
160+
}
161+
}
162+
163+
return result;
153164
}
154165
}
155166

SubSonic/Infrastructure/Database/DbDatabase.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ internal DbConnection CurrentSharedConnection
6363

6464
private static void DBSharedConnection_Disposed(object sender, EventArgs e)
6565
{
66+
dBSharedConnection?.Close();
6667
dBSharedConnection = null;
6768
}
6869

@@ -270,6 +271,11 @@ public async Task<DbDataReader> ExecuteReaderAsync(IDbQuery dbQuery, Cancellatio
270271

271272
try
272273
{
274+
if (Scope.Connection.State != ConnectionState.Open)
275+
{
276+
Scope.Connection.Open();
277+
}
278+
273279
return await cmd
274280
.ExecuteReaderAsync(dbQuery.Behavior, cancellationToken)
275281
.ConfigureAwait(false);
@@ -280,6 +286,10 @@ public async Task<DbDataReader> ExecuteReaderAsync(IDbQuery dbQuery, Cancellatio
280286

281287
throw;
282288
}
289+
finally
290+
{
291+
292+
}
283293
}
284294
}
285295

SubSonic/Infrastructure/Providers/Connections/SharedDbConnectionScope.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Data.Common;
4+
using System.Diagnostics;
45
using System.Text;
6+
using System.Threading;
57
using System.Threading.Tasks;
68

79
namespace SubSonic.Infrastructure
@@ -10,23 +12,32 @@ public class SharedDbConnectionScope
1012
: IConnectionScope
1113
, IDisposable
1214
{
13-
[ThreadStatic]
14-
private static Stack<SharedDbConnectionScope> __instances;
15+
//[ThreadStatic]
16+
private static Dictionary<int, Stack<SharedDbConnectionScope>> __db_instances;
1517

1618
private readonly DbDatabase dbDatabase;
1719

1820
public SharedDbConnectionScope(DbDatabase dbDatabase)
1921
{
2022
this.dbDatabase = dbDatabase ?? throw new ArgumentNullException(nameof(dbDatabase));
2123
this.dbDatabase.InitializeSharedConnection();
24+
this.threadId = Thread.CurrentThread.ManagedThreadId;
2225

23-
if (__instances == null)
26+
if (__db_instances == null)
2427
{
25-
__instances = new Stack<SharedDbConnectionScope>();
28+
__db_instances = new Dictionary<int, Stack<SharedDbConnectionScope>>();
2629
}
27-
__instances.Push(this);
30+
31+
if (!__db_instances.ContainsKey(threadId))
32+
{
33+
__db_instances[threadId] = new Stack<SharedDbConnectionScope>();
34+
}
35+
36+
__db_instances[threadId].Push(this);
2837
}
2938

39+
private readonly int threadId;
40+
3041
public DbConnection Connection => dbDatabase.CurrentSharedConnection;
3142

3243
public DbDatabase Database => dbDatabase;
@@ -41,11 +52,18 @@ protected virtual void Dispose(bool disposing)
4152
{
4253
if (disposing)
4354
{
44-
__instances?.Pop();
55+
SharedDbConnectionScope scope = __db_instances[threadId].Pop();
56+
57+
Debug.Assert(scope.dbDatabase.CurrentSharedConnection.State == System.Data.ConnectionState.Closed, "open connection is being disposed.");
58+
59+
if (__db_instances[threadId]?.Count == 0)
60+
{
61+
__db_instances.Remove(threadId);
62+
}
4563

46-
if(__instances?.Count == 0)
64+
if (__db_instances.Count == 0)
4765
{
48-
this.dbDatabase.ResetSharedConnection();
66+
scope.dbDatabase.ResetSharedConnection();
4967
}
5068

5169
disposedValue = true;

SubSonic/Linq/Expressions/DbSelectAggregateExpression.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ namespace SubSonic.Linq.Expressions
1111
public class DbSelectAggregateExpression
1212
: DbConstantExpression
1313
{
14-
private readonly DbSelectExpression select;
1514
protected internal DbSelectAggregateExpression(DbSelectExpression select, IEnumerable<DbExpression> columns)
1615
: base(
1716
select.IsNullThrowArgumentNull(nameof(select)).QueryObject,
@@ -25,18 +24,20 @@ protected internal DbSelectAggregateExpression(DbSelectExpression select, IEnume
2524

2625
Columns = new ReadOnlyCollection<DbExpression>(columns.ToList());
2726

28-
this.select = select;
27+
Select = select;
2928
}
3029

30+
public DbSelectExpression Select { get; }
31+
3132
public ReadOnlyCollection<DbExpression> Columns { get; }
3233

33-
public bool IsCte => select.IsCte;
34+
public bool IsCte => Select.IsCte;
3435

35-
public DbTableExpression From => select.From;
36+
public DbTableExpression From => Select.From;
3637

37-
public Expression Where => select.Where;
38+
public Expression Where => Select.Where;
3839

39-
public ReadOnlyCollection<Expression> GroupBy => select.GroupBy;
40+
public ReadOnlyCollection<Expression> GroupBy => Select.GroupBy;
4041

4142
public string QueryText
4243
{

SubSonic/Linq/Expressions/Structure/SqlFormatter/TSqlFormatter.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public partial class TSqlFormatter
2222
: DbExpressionVisitor
2323
{
2424
[ThreadStatic]
25-
private static Stack<TSqlFormatter> __instances;
25+
private static Stack<TSqlFormatter> __formatter_instances;
2626
private int depth = 0;
2727
private readonly TextWriter writer;
2828
private readonly ISqlContext context;
@@ -49,15 +49,15 @@ protected TSqlFormatter(TextWriter writer, ISqlContext context)
4949
this.context = context ?? throw new ArgumentNullException(nameof(context));
5050
this.provider = context.Provider ?? throw new InvalidOperationException();
5151

52-
if (__instances is null)
52+
if (__formatter_instances is null)
5353
{
54-
__instances = new Stack<TSqlFormatter>();
54+
__formatter_instances = new Stack<TSqlFormatter>();
5555
}
5656

57-
__instances.Push(this);
57+
__formatter_instances.Push(this);
5858
}
5959

60-
protected static int IndentationWidth => __instances.Count;
60+
protected static int IndentationWidth => __formatter_instances.Count;
6161

6262
protected bool IsNested { get; set; } = false;
6363

SubSonic/Linq/Expressions/Structure/SqlFormatter/TSqlFormatterDisposable.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ protected virtual void Dispose(bool disposing)
2020
{
2121
if (disposing)
2222
{
23-
__instances.Pop();
23+
__formatter_instances.Pop();
2424

25-
if(__instances.Count == 0)
25+
if(__formatter_instances.Count == 0)
2626
{
27-
__instances = null;
27+
__formatter_instances = null;
2828
}
2929
}
3030

SubSonic/SubSonic.Core.DataAccessLayer.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<IncludeSymbols>true</IncludeSymbols>
1010
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
1111
<PackageTags>DAL;SqlServer;C#;.NetFramework;.NetCore;</PackageTags>
12-
<Version>4.1.0-alpha.5</Version>
12+
<Version>4.1.0-alpha.6</Version>
1313
<PackageId>SubSonic.Core.DAL</PackageId>
1414
<Company>SubSonic-Core</Company>
1515
<PackageProjectUrl>https://github.com/SubSonic-Core/SubSonic/wiki</PackageProjectUrl>

0 commit comments

Comments
 (0)