forked from DapperLib/Dapper
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDbConnectionExtensions.cs
More file actions
129 lines (115 loc) · 4.99 KB
/
Copy pathDbConnectionExtensions.cs
File metadata and controls
129 lines (115 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections.Concurrent;
using System.Data.Common;
using System.Linq.Expressions;
using System.Reflection;
namespace Dapper.ProviderTools
{
/// <summary>
/// Helper utilities for working with database connections
/// </summary>
public static class DbConnectionExtensions
{
/// <summary>
/// Attempt to get the client connection id for a given connection
/// </summary>
public static bool TryGetClientConnectionId(this DbConnection connection, out Guid clientConnectionId)
{
clientConnectionId = default;
return connection is not null && ByTypeHelpers.Get(connection.GetType()).TryGetClientConnectionId(
connection, out clientConnectionId);
}
/// <summary>
/// Clear all pools associated with the provided connection type
/// </summary>
public static bool TryClearAllPools(this DbConnection connection)
=> connection is not null && ByTypeHelpers.Get(connection.GetType()).TryClearAllPools();
/// <summary>
/// Clear the pools associated with the provided connection
/// </summary>
public static bool TryClearPool(this DbConnection connection)
=> connection is not null && ByTypeHelpers.Get(connection.GetType()).TryClearPool(connection);
private sealed class ByTypeHelpers
{
private static readonly ConcurrentDictionary<Type, ByTypeHelpers> s_byType
= new ConcurrentDictionary<Type, ByTypeHelpers>();
private readonly Func<DbConnection, Guid>? _getClientConnectionId;
private readonly Action<DbConnection>? _clearPool;
private readonly Action? _clearAllPools;
public bool TryGetClientConnectionId(DbConnection connection, out Guid clientConnectionId)
{
if (_getClientConnectionId is null)
{
clientConnectionId = default;
return false;
}
clientConnectionId = _getClientConnectionId(connection);
return true;
}
public bool TryClearPool(DbConnection connection)
{
if (_clearPool is null) return false;
_clearPool(connection);
return true;
}
public bool TryClearAllPools()
{
if (_clearAllPools is null) return false;
_clearAllPools();
return true;
}
public static ByTypeHelpers Get(Type type)
{
if (!s_byType.TryGetValue(type, out var value))
{
s_byType[type] = value = new ByTypeHelpers(type);
}
return value;
}
private ByTypeHelpers(Type type)
{
_getClientConnectionId = TryGetInstanceProperty<Guid>("ClientConnectionId", type);
try
{
var clearAllPools = type.GetMethod("ClearAllPools", BindingFlags.Public | BindingFlags.Static,
null, Type.EmptyTypes, null);
if (clearAllPools is not null)
{
_clearAllPools = (Action)Delegate.CreateDelegate(typeof(Action), clearAllPools);
}
}
catch { }
try
{
var clearPool = type.GetMethod("ClearPool", BindingFlags.Public | BindingFlags.Static,
null, new[] { type }, null);
if (clearPool is not null)
{
var p = Expression.Parameter(typeof(DbConnection), "connection");
var body = Expression.Call(clearPool, Expression.Convert(p, type));
var lambda = Expression.Lambda<Action<DbConnection>>(body, p);
_clearPool = lambda.Compile();
}
}
catch { }
}
private static Func<DbConnection, T>? TryGetInstanceProperty<T>(string name, Type type)
{
try
{
var prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
if (prop is null || !prop.CanRead) return null;
if (prop.PropertyType != typeof(T)) return null;
var p = Expression.Parameter(typeof(DbConnection), "connection");
var body = Expression.Property(Expression.Convert(p, type), prop);
var lambda = Expression.Lambda<Func<DbConnection, T>>(body, p);
return lambda.Compile();
}
catch
{
return null;
}
}
}
}
}