Skip to content

Commit cb7ce2b

Browse files
author
James Craig
committed
Added async capabilities to SQLHelper.
1 parent 178aa5d commit cb7ce2b

File tree

5 files changed

+531
-63
lines changed

5 files changed

+531
-63
lines changed

src/SQLHelper.DB/ExtensionMethods/DbCommandExtensions.cs

+16
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ limitations under the License.
1919
using System;
2020
using System.Data;
2121
using System.Data.Common;
22+
using System.Threading.Tasks;
2223

2324
namespace SQLHelper.ExtensionMethods
2425
{
@@ -188,6 +189,21 @@ public static DbCommand Commit(this DbCommand command)
188189
return command.ExecuteScalar().To(defaultValue);
189190
}
190191

192+
/// <summary>
193+
/// Executes the stored procedure as a scalar query async
194+
/// </summary>
195+
/// <param name="command">Command object</param>
196+
/// <param name="defaultValue">Default value if there is an issue</param>
197+
/// <returns>The object of the first row and first column</returns>
198+
public static async Task<DataType> ExecuteScalarAsync<DataType>(this DbCommand command, DataType defaultValue = default(DataType))
199+
{
200+
if (command == null)
201+
return defaultValue;
202+
command.Open();
203+
var ReturnValue = await command.ExecuteScalarAsync();
204+
return ReturnValue.To(defaultValue);
205+
}
206+
191207
/// <summary>
192208
/// Gets a parameter or creates it, if it is not found
193209
/// </summary>

src/SQLHelper.DB/HelperClasses/Batch.cs

+174-62
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ limitations under the License.
2424
using System.Globalization;
2525
using System.Linq;
2626
using System.Text.RegularExpressions;
27+
using System.Threading.Tasks;
2728

2829
namespace SQLHelper.HelperClasses
2930
{
@@ -133,6 +134,15 @@ public IList<IList<dynamic>> Execute()
133134
return ExecuteCommands();
134135
}
135136

137+
/// <summary>
138+
/// Executes the commands and returns the results (async)
139+
/// </summary>
140+
/// <returns>The results of the batched commands</returns>
141+
public async Task<IList<IList<dynamic>>> ExecuteAsync()
142+
{
143+
return await ExecuteCommandsAsync();
144+
}
145+
136146
/// <summary>
137147
/// Removes duplicate commands from the batch
138148
/// </summary>
@@ -177,6 +187,61 @@ protected bool CheckTransaction()
177187
});
178188
}
179189

190+
private static void GetResults(List<IList<dynamic>> ReturnValue, DbCommand ExecutableCommand, List<IParameter> FinalParameters, bool Finalizable, string FinalSQLCommand)
191+
{
192+
ExecutableCommand.CommandText = FinalSQLCommand;
193+
FinalParameters.ForEach(x => x.AddParameter(ExecutableCommand));
194+
if (Finalizable)
195+
{
196+
using (DbDataReader TempReader = ExecutableCommand.ExecuteReader())
197+
{
198+
ReturnValue.Add(GetValues(TempReader));
199+
while (TempReader.NextResult())
200+
{
201+
ReturnValue.Add(GetValues(TempReader));
202+
}
203+
}
204+
}
205+
else
206+
{
207+
var TempValue = new List<dynamic>
208+
{
209+
ExecutableCommand.ExecuteNonQuery()
210+
};
211+
ReturnValue.Add(TempValue);
212+
}
213+
}
214+
215+
private static async Task GetResultsAsync(List<IList<dynamic>> ReturnValue, DbCommand ExecutableCommand, List<IParameter> FinalParameters, bool Finalizable, string FinalSQLCommand)
216+
{
217+
ExecutableCommand.CommandText = FinalSQLCommand;
218+
FinalParameters.ForEach(x => x.AddParameter(ExecutableCommand));
219+
if (Finalizable)
220+
{
221+
using (DbDataReader TempReader = await ExecutableCommand.ExecuteReaderAsync())
222+
{
223+
ReturnValue.Add(GetValues(TempReader));
224+
while (TempReader.NextResult())
225+
{
226+
ReturnValue.Add(GetValues(TempReader));
227+
}
228+
}
229+
}
230+
else
231+
{
232+
var TempValue = new List<dynamic>
233+
{
234+
await ExecutableCommand.ExecuteNonQueryAsync()
235+
};
236+
ReturnValue.Add(TempValue);
237+
}
238+
}
239+
240+
/// <summary>
241+
/// Gets the values.
242+
/// </summary>
243+
/// <param name="tempReader">The temporary reader.</param>
244+
/// <returns>The resulting values</returns>
180245
private static IList<dynamic> GetValues(DbDataReader tempReader)
181246
{
182247
if (tempReader == null)
@@ -199,6 +264,10 @@ private static IList<dynamic> GetValues(DbDataReader tempReader)
199264
return ReturnValue;
200265
}
201266

267+
/// <summary>
268+
/// Executes the commands.
269+
/// </summary>
270+
/// <returns>The list of results</returns>
202271
private IList<IList<dynamic>> ExecuteCommands()
203272
{
204273
if (Source == null)
@@ -217,11 +286,7 @@ private IList<IList<dynamic>> ExecuteCommands()
217286
Connection.ConnectionString = Source.Connection;
218287
using (DbCommand ExecutableCommand = Factory.CreateCommand())
219288
{
220-
ExecutableCommand.Connection = Connection;
221-
ExecutableCommand.CommandType = CommandType.Text;
222-
if (CheckTransaction())
223-
ExecutableCommand.BeginTransaction();
224-
ExecutableCommand.Open();
289+
SetupCommand(Connection, ExecutableCommand);
225290

226291
try
227292
{
@@ -233,64 +298,57 @@ private IList<IList<dynamic>> ExecuteCommands()
233298
string FinalSQLCommand = "";
234299
int ParameterTotal = 0;
235300
ExecutableCommand.Parameters.Clear();
236-
for (int y = Count; y < Commands.Count; ++y)
237-
{
238-
ICommand Command = Commands[y];
239-
if (ParameterTotal + Command.Parameters.Count > 2100)
240-
break;
241-
ParameterTotal += Command.Parameters.Count;
242-
Finalizable |= Commands[y].Finalizable;
243-
if (Command.CommandType == CommandType.Text)
244-
{
245-
var TempCommandText = Command.SQLCommand ?? "";
246-
string Suffix = "Command" + Count.ToString(CultureInfo.InvariantCulture);
247-
FinalSQLCommand += string.IsNullOrEmpty(Command.SQLCommand) ?
248-
"" :
249-
ParameterRegex.Replace(Command.SQLCommand, x =>
250-
{
251-
var Param = Command.Parameters.FirstOrDefault(z => z.ID == x.Groups["ParamName"].Value);
252-
if (Param != null)
253-
return x.Value + Suffix;
254-
return x.Value;
255-
}) + Environment.NewLine;
301+
SetupParameters(ref Count, FinalParameters, ref Finalizable, ref FinalSQLCommand, ref ParameterTotal);
302+
GetResults(ReturnValue, ExecutableCommand, FinalParameters, Finalizable, FinalSQLCommand);
303+
if (Count >= CommandCount)
304+
break;
305+
}
306+
ExecutableCommand.Commit();
307+
}
308+
catch { ExecutableCommand.Rollback(); throw; }
309+
finally { ExecutableCommand.Close(); }
310+
}
311+
}
312+
FinalizeCommands(ReturnValue);
313+
return ReturnValue;
314+
}
256315

257-
foreach (IParameter TempParameter in Command.Parameters)
258-
{
259-
FinalParameters.Add(TempParameter.CreateCopy(Suffix));
260-
}
261-
}
262-
else
263-
{
264-
FinalSQLCommand += Command.SQLCommand + Environment.NewLine;
265-
foreach (IParameter TempParameter in Command.Parameters)
266-
{
267-
FinalParameters.Add(TempParameter.CreateCopy(""));
268-
}
269-
}
270-
++Count;
271-
}
316+
/// <summary>
317+
/// Executes the commands asynchronously.
318+
/// </summary>
319+
/// <returns>The list of results</returns>
320+
private async Task<IList<IList<dynamic>>> ExecuteCommandsAsync()
321+
{
322+
if (Source == null)
323+
return new List<IList<dynamic>>();
324+
if (Commands == null)
325+
return new List<IList<dynamic>>();
326+
var ReturnValue = new List<IList<dynamic>>();
327+
if (Commands.Count == 0)
328+
{
329+
ReturnValue.Add(new List<dynamic>());
330+
return ReturnValue;
331+
}
332+
var Factory = Source.Factory;
333+
using (DbConnection Connection = Factory.CreateConnection())
334+
{
335+
Connection.ConnectionString = Source.Connection;
336+
using (DbCommand ExecutableCommand = Factory.CreateCommand())
337+
{
338+
SetupCommand(Connection, ExecutableCommand);
272339

273-
ExecutableCommand.CommandText = FinalSQLCommand;
274-
FinalParameters.ForEach(x => x.AddParameter(ExecutableCommand));
275-
if (Finalizable)
276-
{
277-
using (DbDataReader TempReader = ExecutableCommand.ExecuteReader())
278-
{
279-
ReturnValue.Add(GetValues(TempReader));
280-
while (TempReader.NextResult())
281-
{
282-
ReturnValue.Add(GetValues(TempReader));
283-
}
284-
}
285-
}
286-
else
287-
{
288-
var TempValue = new List<dynamic>
289-
{
290-
ExecutableCommand.ExecuteNonQuery()
291-
};
292-
ReturnValue.Add(TempValue);
293-
}
340+
try
341+
{
342+
int Count = 0;
343+
while (true)
344+
{
345+
var FinalParameters = new List<IParameter>();
346+
bool Finalizable = false;
347+
string FinalSQLCommand = "";
348+
int ParameterTotal = 0;
349+
ExecutableCommand.Parameters.Clear();
350+
SetupParameters(ref Count, FinalParameters, ref Finalizable, ref FinalSQLCommand, ref ParameterTotal);
351+
await GetResultsAsync(ReturnValue, ExecutableCommand, FinalParameters, Finalizable, FinalSQLCommand);
294352
if (Count >= CommandCount)
295353
break;
296354
}
@@ -300,6 +358,12 @@ private IList<IList<dynamic>> ExecuteCommands()
300358
finally { ExecutableCommand.Close(); }
301359
}
302360
}
361+
FinalizeCommands(ReturnValue);
362+
return ReturnValue;
363+
}
364+
365+
private void FinalizeCommands(List<IList<dynamic>> ReturnValue)
366+
{
303367
for (int x = 0, y = 0; x < Commands.Count(); ++x)
304368
{
305369
if (Commands[x].Finalizable)
@@ -310,7 +374,55 @@ private IList<IList<dynamic>> ExecuteCommands()
310374
else
311375
Commands[x].Finalize(new List<dynamic>());
312376
}
313-
return ReturnValue;
377+
}
378+
379+
private void SetupCommand(DbConnection Connection, DbCommand ExecutableCommand)
380+
{
381+
ExecutableCommand.Connection = Connection;
382+
ExecutableCommand.CommandType = CommandType.Text;
383+
if (CheckTransaction())
384+
ExecutableCommand.BeginTransaction();
385+
ExecutableCommand.Open();
386+
}
387+
388+
private void SetupParameters(ref int Count, List<IParameter> FinalParameters, ref bool Finalizable, ref string FinalSQLCommand, ref int ParameterTotal)
389+
{
390+
for (int y = Count; y < Commands.Count; ++y)
391+
{
392+
ICommand Command = Commands[y];
393+
if (ParameterTotal + Command.Parameters.Count > 2100)
394+
break;
395+
ParameterTotal += Command.Parameters.Count;
396+
Finalizable |= Commands[y].Finalizable;
397+
if (Command.CommandType == CommandType.Text)
398+
{
399+
var TempCommandText = Command.SQLCommand ?? "";
400+
string Suffix = "Command" + Count.ToString(CultureInfo.InvariantCulture);
401+
FinalSQLCommand += string.IsNullOrEmpty(Command.SQLCommand) ?
402+
"" :
403+
ParameterRegex.Replace(Command.SQLCommand, x =>
404+
{
405+
var Param = Command.Parameters.FirstOrDefault(z => z.ID == x.Groups["ParamName"].Value);
406+
if (Param != null)
407+
return x.Value + Suffix;
408+
return x.Value;
409+
}) + Environment.NewLine;
410+
411+
foreach (IParameter TempParameter in Command.Parameters)
412+
{
413+
FinalParameters.Add(TempParameter.CreateCopy(Suffix));
414+
}
415+
}
416+
else
417+
{
418+
FinalSQLCommand += Command.SQLCommand + Environment.NewLine;
419+
foreach (IParameter TempParameter in Command.Parameters)
420+
{
421+
FinalParameters.Add(TempParameter.CreateCopy(""));
422+
}
423+
}
424+
++Count;
425+
}
314426
}
315427
}
316428
}

src/SQLHelper.DB/HelperClasses/Interfaces/IBatch.cs

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
using System;
1818
using System.Collections.Generic;
1919
using System.Data;
20+
using System.Threading.Tasks;
2021

2122
namespace SQLHelper.HelperClasses.Interfaces
2223
{
@@ -78,6 +79,12 @@ public interface IBatch
7879
/// <returns>The results of the batched commands</returns>
7980
IList<IList<dynamic>> Execute();
8081

82+
/// <summary>
83+
/// Executes the commands and returns the results (async)
84+
/// </summary>
85+
/// <returns>The results of the batched commands</returns>
86+
Task<IList<IList<dynamic>>> ExecuteAsync();
87+
8188
/// <summary>
8289
/// Removes duplicate commands from the batch
8390
/// </summary>

src/SQLHelper.DB/SQLHelper.cs

+25-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ limitations under the License.
2323
using System.Data;
2424
using System.Data.Common;
2525
using System.Linq;
26+
using System.Threading.Tasks;
2627

2728
namespace SQLHelper
2829
{
@@ -141,12 +142,21 @@ public SQLHelper CreateBatch()
141142
/// <summary>
142143
/// Executes this instance.
143144
/// </summary>
144-
/// <returns></returns>
145+
/// <returns>The results of the batched queries.</returns>
145146
public IList<IList<dynamic>> Execute()
146147
{
147148
return Batch.Execute();
148149
}
149150

151+
/// <summary>
152+
/// Executes the queries asynchronously.
153+
/// </summary>
154+
/// <returns>The result of the queries</returns>
155+
public async Task<IList<IList<dynamic>>> ExecuteAsync()
156+
{
157+
return await Batch.ExecuteAsync();
158+
}
159+
150160
/// <summary>
151161
/// Executes the batched commands and returns the first value, ignoring the rest.
152162
/// </summary>
@@ -161,6 +171,20 @@ public TData ExecuteScalar<TData>()
161171
return Value[Value.Keys.First()].To<object, TData>();
162172
}
163173

174+
/// <summary>
175+
/// Executes the batched commands and returns the first value, ignoring the rest (async).
176+
/// </summary>
177+
/// <typeparam name="TData">The type of the data to return.</typeparam>
178+
/// <returns>The first value of the batch</returns>
179+
public async Task<TData> ExecuteScalarAsync<TData>()
180+
{
181+
var BatchResults = await Batch.ExecuteAsync();
182+
IDictionary<string, object> Value = BatchResults[0][0] as IDictionary<string, object>;
183+
if (Value == null)
184+
return ((object)BatchResults[0][0]).To<object, TData>();
185+
return Value[Value.Keys.First()].To<object, TData>();
186+
}
187+
164188
/// <summary>
165189
/// Removes duplicate queries from the batch.
166190
/// </summary>

0 commit comments

Comments
 (0)