Skip to content

Commit 4af3cb7

Browse files
committed
base
1 parent b84621f commit 4af3cb7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+7101
-1
lines changed

.vs/Database/v14/.suo

3.5 KB
Binary file not shown.

Command.vb

+406
Large diffs are not rendered by default.

Connection.vb

+265
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
Imports Desharp
2+
Imports System.Configuration
3+
Imports System.Data.SqlClient
4+
Imports MySql.Data.MySqlClient
5+
Imports System.Data.Common
6+
Imports System.Reflection
7+
Imports System.Threading
8+
9+
Public Class Connection
10+
Protected Shared supportedProviders As New List(Of String) From {
11+
"System.Data.SqlClient",
12+
"MySql.Data.MySqlClient"
13+
}
14+
Protected Shared config As New Dictionary(Of Int16, String())
15+
Protected Shared namesAndIndexes As New Dictionary(Of String, Int32)
16+
Protected Shared connections As New Dictionary(Of String, Dictionary(Of Int16, DbConnection))
17+
Protected Shared threadLock As New Object()
18+
''' <summary>
19+
''' Load config and set up connection strings.
20+
''' </summary>
21+
Shared Sub New()
22+
If (Connection.config.Count = 0) Then
23+
Dim config As ConnectionStringsSection = DirectCast(
24+
ConfigurationSettings.GetConfig("connectionStrings"),
25+
ConnectionStringsSection
26+
)
27+
Dim i As Int16 = 0
28+
For Each cfgItem As ConnectionStringSettings In config.ConnectionStrings
29+
If Not Connection.supportedProviders.Contains(cfgItem.ProviderName) Then
30+
Throw New Exception($"This DB engine is not supperted: '{cfgItem.ProviderName}'.")
31+
End If
32+
Connection.config.Add(
33+
i, New String() {cfgItem.ProviderName, cfgItem.ConnectionString}
34+
)
35+
Connection.namesAndIndexes.Add(cfgItem.Name, i)
36+
i += 1
37+
Next
38+
End If
39+
End Sub
40+
''' <summary>
41+
''' Get and open connection by config index.
42+
''' </summary>
43+
''' <param name="connectionIndex">Config connection index.</param>
44+
''' <returns></returns>
45+
Public Shared Function [Get](connectionIndex As Int32) As DbConnection
46+
If Not Connection.config.ContainsKey(connectionIndex) Then
47+
Throw New Exception($"Connection settings under index doesn't exist: {connectionIndex}.")
48+
End If
49+
Dim conn As DbConnection
50+
Dim processAndThreadKey As String = Connection.getProcessAndThreadKey()
51+
If (
52+
Connection.connections.ContainsKey(processAndThreadKey) AndAlso
53+
Connection.connections(processAndThreadKey).ContainsKey(connectionIndex)
54+
) Then
55+
conn = Connection.connections(processAndThreadKey).Item(connectionIndex)
56+
Else
57+
Dim typeAndDsn As String() = Connection.config(connectionIndex)
58+
If typeAndDsn(0) = "System.Data.SqlClient" Then
59+
conn = New SqlConnection(typeAndDsn(1))
60+
ElseIf typeAndDsn(0) = "MySql.Data.MySqlClient" Then
61+
conn = New MySqlConnection(typeAndDsn(1))
62+
End If
63+
Connection.register(processAndThreadKey, connectionIndex, conn)
64+
Try
65+
conn.Open()
66+
Connection.addErrorHandler(conn)
67+
Catch ex As Exception
68+
Debug.Log(ex)
69+
End Try
70+
End If
71+
Return conn
72+
End Function
73+
''' <summary>
74+
''' Get and open connection by config name.
75+
''' </summary>
76+
''' <param name="connectionName">Config connection name.</param>
77+
''' <returns></returns>
78+
Public Shared Function [Get](connectionName As String) As DbConnection
79+
Dim connIndex As Int32
80+
If Connection.namesAndIndexes.ContainsKey(connectionName) Then
81+
connIndex = Connection.namesAndIndexes(connectionName)
82+
Else
83+
Throw New Exception($"Connection settings under name doesn't exist: {connectionName}.")
84+
End If
85+
Return Connection.Get(connIndex)
86+
End Function
87+
''' <summary>
88+
''' Close and drop all connections for current process and thread.
89+
''' Call this method always at thread end.
90+
''' </summary>
91+
Public Shared Sub Close()
92+
Dim processAndThreadKey = Connection.getProcessAndThreadKey()
93+
Dim conn As DbConnection
94+
If Connection.connections.ContainsKey(processAndThreadKey) Then
95+
For Each item In Connection.connections(processAndThreadKey)
96+
conn = item.Value
97+
If conn.State = ConnectionState.Open Then
98+
conn.Close()
99+
conn.Dispose()
100+
End If
101+
Next
102+
SyncLock Connection.threadLock
103+
Connection.connections.Remove(processAndThreadKey)
104+
End SyncLock
105+
End If
106+
End Sub
107+
''' <summary>
108+
''' Close and drop connection by config index for current process and thread.
109+
''' Call this method always after you have loaded all from any secondary database.
110+
''' </summary>
111+
''' <param name="connectionIndex">Config connection index.</param>
112+
Public Shared Sub Close(connectionIndex As Int32)
113+
Connection.Close(connectionIndex, Process.GetCurrentProcess().Id, Thread.CurrentThread.ManagedThreadId)
114+
End Sub
115+
''' <summary>
116+
''' Close and drop connection by config name for current process And thread.
117+
''' Call this method always after you have loaded all from any secondary database.
118+
''' </summary>
119+
''' <param name="connectionName">Config connection name.</param>
120+
Public Shared Sub Close(connectionName As String)
121+
If Connection.namesAndIndexes.ContainsKey(connectionName) Then
122+
Connection.Close(Connection.namesAndIndexes(connectionName), Process.GetCurrentProcess().Id, Thread.CurrentThread.ManagedThreadId)
123+
End If
124+
End Sub
125+
''' <summary>
126+
''' Close and drop connection by config index for specificly called process and thread.
127+
''' Call this method only if you know what you are doing:-)
128+
''' </summary>
129+
''' <param name="connectionIndex">Config connection index.</param>
130+
''' <param name="processId">Specific process id.</param>
131+
''' <param name="threadId">Specific thread id.</param>
132+
Public Shared Sub Close(connectionIndex As Int32, processId As Int32, threadId As Int32)
133+
Dim processAndThreadKey = $"{processId}_{threadId}"
134+
Dim conns As Dictionary(Of Int16, DbConnection)
135+
Dim conn As DbConnection
136+
If Connection.connections.ContainsKey(processAndThreadKey) Then
137+
conns = Connection.connections(processAndThreadKey)
138+
conn = conns(connectionIndex)
139+
If conn.State = ConnectionState.Open Then
140+
conn.Close()
141+
conn.Dispose()
142+
End If
143+
SyncLock Connection.threadLock
144+
conns.Remove(connectionIndex)
145+
If conns.Count = 0 Then
146+
conns.Remove(processAndThreadKey)
147+
End If
148+
End SyncLock
149+
End If
150+
End Sub
151+
''' <summary>
152+
''' Close and drop connections for specificly called process.
153+
''' </summary>
154+
Public Shared Sub CloseAllInProcess(processId As Int32)
155+
Dim keyBegin As String = processId.ToString() + "_"
156+
Dim key As String
157+
Dim conns As Dictionary(Of Int16, DbConnection)
158+
SyncLock Connection.threadLock
159+
For i As Int32 = Connection.connections.Keys.Count - 1 To 0 Step -1
160+
If Connection.connections.Keys.Contains(i) Then
161+
key = Connection.connections.Keys(i)
162+
Else
163+
Continue For
164+
End If
165+
If key.IndexOf(keyBegin) = 0 Then
166+
conns = Connection.connections(key)
167+
For Each item In conns
168+
If item.Value.State = ConnectionState.Open Then
169+
item.Value.Close()
170+
item.Value.Dispose()
171+
End If
172+
Next
173+
Connection.connections.Remove(key)
174+
End If
175+
Next
176+
End SyncLock
177+
End Sub
178+
''' <summary>
179+
''' Create and begin transaction on first config connection.
180+
''' </summary>
181+
''' <param name="transactionName">Transaction name.</param>
182+
''' <param name="isolationLevel">Transaction isolation level.</param>
183+
''' <returns>New transaction.</returns>
184+
Public Shared Function BeginTransaction(Optional transactionName As String = "", Optional isolationLevel As IsolationLevel = IsolationLevel.Unspecified) As DbTransaction
185+
Dim defaultConnectionIndex As Int16 = 0
186+
Return Connection.BeginTransaction(defaultConnectionIndex, transactionName, isolationLevel)
187+
End Function
188+
''' <summary>
189+
''' Create and begin transaction on specified connection config index.
190+
''' </summary>
191+
''' <param name="connectionIndex">Config connection index.</param>
192+
''' <param name="transactionName">Transaction name.</param>
193+
''' <param name="isolationLevel">Transaction isolation level.</param>
194+
''' <returns>New transaction.</returns>
195+
Public Shared Function BeginTransaction(connectionIndex As Int16, Optional transactionName As String = "", Optional isolationLevel As IsolationLevel = IsolationLevel.Unspecified) As DbTransaction
196+
Dim conn As DbConnection = Connection.Get(connectionIndex)
197+
Dim connType As Type = conn.GetType()
198+
If connType.IsAssignableFrom(GetType(SqlConnection)) Then
199+
Dim msConn As SqlConnection = DirectCast(conn, SqlConnection)
200+
Return msConn.BeginTransaction(isolationLevel, transactionName)
201+
ElseIf connType.IsAssignableFrom(GetType(MySqlConnection)) Then
202+
Dim myConn As MySqlConnection = DirectCast(conn, MySqlConnection)
203+
Return myConn.BeginTransaction(isolationLevel)
204+
End If
205+
Return Nothing
206+
End Function
207+
''' <summary>
208+
''' Create and begin transaction on specified connection config name.
209+
''' </summary>
210+
''' <param name="connectionName">Config connection name.</param>
211+
''' <param name="transactionName">Transaction name.</param>
212+
''' <param name="isolationLevel">Transaction isolation level.</param>
213+
''' <returns>New transaction.</returns>
214+
Public Shared Function BeginTransaction(connectionName As String, Optional transactionName As String = "", Optional isolationLevel As IsolationLevel = IsolationLevel.Unspecified) As DbTransaction
215+
Dim connectionIndex As Int16
216+
If Connection.namesAndIndexes.ContainsKey(connectionName) Then
217+
connectionIndex = Connection.namesAndIndexes(connectionName)
218+
Else
219+
Throw New Exception($"Connection settings under name doesn't exist: {connectionName}.")
220+
End If
221+
Return Connection.BeginTransaction(connectionIndex, transactionName, isolationLevel)
222+
End Function
223+
''' <summary>
224+
''' Add InfoMessage handler for opened connection to to log SQL errors.
225+
''' </summary>
226+
''' <param name="conn"></param>
227+
Protected Shared Sub addErrorHandler(conn As DbConnection)
228+
Dim connType As Type = conn.GetType()
229+
If connType.IsAssignableFrom(GetType(SqlConnection)) Then
230+
Dim msConn As SqlConnection = DirectCast(conn, SqlConnection)
231+
AddHandler msConn.InfoMessage, AddressOf Connection.errorHandler
232+
ElseIf connType.IsAssignableFrom(GetType(MySqlConnection)) Then
233+
Dim myConn As MySqlConnection = DirectCast(conn, MySqlConnection)
234+
AddHandler myConn.InfoMessage, AddressOf Connection.errorHandler
235+
End If
236+
End Sub
237+
Protected Shared Sub errorHandler(sender As Object, sqlErrorArgs As EventArgs)
238+
Dim fi As FieldInfo = sqlErrorArgs.GetType().GetField("exception", BindingFlags.NonPublic)
239+
Dim exception = fi.GetValue(sqlErrorArgs)
240+
If Debug.Enabled() Then
241+
Debug.Dump(exception)
242+
Else
243+
Debug.Log(exception)
244+
End If
245+
End Sub
246+
247+
Protected Shared Sub register(processAndThreadKey As String, connectionIndex As Int32, conn As DbConnection)
248+
Dim conns As Dictionary(Of Int16, DbConnection)
249+
SyncLock Connection.threadLock
250+
If Connection.connections.ContainsKey(processAndThreadKey) Then
251+
conns = Connection.connections(processAndThreadKey)
252+
conns(connectionIndex) = conn
253+
Else
254+
Connection.connections.Add(processAndThreadKey, New Dictionary(Of Short, DbConnection) From {
255+
{connectionIndex, conn}
256+
})
257+
End If
258+
End SyncLock
259+
End Sub
260+
261+
Protected Shared Function getProcessAndThreadKey() As String
262+
Return $"{Process.GetCurrentProcess().Id}_{Thread.CurrentThread.ManagedThreadId}"
263+
End Function
264+
265+
End Class

0 commit comments

Comments
 (0)