Skip to content

Commit 5985677

Browse files
Refactor CommandExtensions for improved clarity
- Introduced partial classes for `CommandExtensions` and `SqlCommandExtensions` for better organization. - Added `EnsureOpen` and `EnsureOpenAsync` methods to enhance connection management and error handling. - Updated parameter types in `ExecuteReaderAsync` methods to use `SqlDataReader` for specificity. - Revised documentation comments to accurately reflect changes in parameters and return types. - Overall improvements enhance maintainability and functionality of database command execution.
1 parent e102624 commit 5985677

File tree

5 files changed

+245
-3
lines changed

5 files changed

+245
-3
lines changed

Source/Core/Extensions/Command._.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace Open.Database.Extensions;
66
/// </summary>
77
public static partial class CommandExtensions
88
{
9+
#region Connection.EnsureOpen Shortcuts.
910
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1011
private static ConnectionState EnsureOpen(this IDbCommand command)
1112
{
@@ -23,6 +24,7 @@ private static ValueTask<ConnectionState> EnsureOpenAsync(this IDbCommand comman
2324
#endif
2425
return command.Connection!.EnsureOpenAsync(cancellationToken);
2526
}
27+
#endregion
2628

2729
/// <summary>
2830
/// Iterates all records using an <see cref="IDataReader"/> and returns the desired results as a list.
@@ -319,7 +321,7 @@ public static async ValueTask ExecuteReaderAsync(this IDbCommand command,
319321
}
320322

321323
/// <param name="command">The <see cref="DbCommand"/> to generate a reader from.</param>
322-
/// <param name="handler">The handler function for each <see cref="IDataRecord"/>.</param>
324+
/// <param name="handler">The handler function for the <see cref="DbDataReader"/>.</param>
323325
/// <param name="behavior">The behavior to use with the data reader.</param>
324326
/// <param name="cancellationToken">The cancellation token.</param>
325327
/// <inheritdoc cref="ExecuteReaderAsync(DbCommand, Action{DbDataReader}, CommandBehavior, CancellationToken)"/>

Source/MSSqlClient/Extensions/Command.AddParameter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/// <summary>
44
/// SqlClient extensions for building a command and retrieving data using best practices.
55
/// </summary>
6-
public static class SqlCommandExtensions
6+
public static partial class SqlCommandExtensions
77
{
88
/// <summary>
99
/// Shortcut for adding command parameter.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System.Data.Common;
2+
using System.Runtime.CompilerServices;
3+
4+
namespace Open.Database.Extensions;
5+
6+
/// <summary>
7+
/// SqlClient extensions for building a command and retrieving data using best practices.
8+
/// </summary>
9+
public static partial class SqlCommandExtensions
10+
{
11+
#region Connection.EnsureOpen Shortcuts.
12+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
13+
private static ConnectionState EnsureOpen(this IDbCommand command)
14+
{
15+
#if DEBUG
16+
if (command.Connection is null) throw new InvalidOperationException("Cannot execute a command with a null connection.");
17+
#endif
18+
return command.Connection!.EnsureOpen();
19+
}
20+
21+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
22+
private static ValueTask<ConnectionState> EnsureOpenAsync(this IDbCommand command, CancellationToken cancellationToken)
23+
{
24+
#if DEBUG
25+
if (command.Connection is null) throw new ArgumentException("Cannot execute a command with a null connection.");
26+
#endif
27+
return command.Connection!.EnsureOpenAsync(cancellationToken);
28+
}
29+
#endregion
30+
31+
/// <param name="command">The <see cref="SqlCommand"/> to generate a reader from.</param>
32+
/// <param name="handler">The handler function for the <see cref="SqlDataReader"/>.</param>
33+
/// <param name="behavior">The behavior to use with the data reader.</param>
34+
/// <inheritdoc cref="CommandExtensions.ExecuteReader(IDbCommand, Action{IDataReader}, CommandBehavior)"/>
35+
public static void ExecuteReader(this SqlCommand command, Action<SqlDataReader> handler, CommandBehavior behavior = CommandBehavior.Default)
36+
{
37+
if (command is null) throw new ArgumentNullException(nameof(command));
38+
if (handler is null) throw new ArgumentNullException(nameof(handler));
39+
Contract.EndContractBlock();
40+
41+
ConnectionState state = command.EnsureOpen();
42+
if (state == ConnectionState.Closed) behavior |= CommandBehavior.CloseConnection;
43+
using SqlDataReader reader = command.ExecuteReader(behavior);
44+
handler(reader);
45+
}
46+
47+
/// <param name="command">The <see cref="SqlCommand"/> to generate a reader from.</param>
48+
/// <param name="handler">The handler function for the <see cref="SqlDataReader"/>.</param>
49+
/// <param name="behavior">The behavior to use with the data reader.</param>
50+
/// <param name="cancellationToken">The cancellation token.</param>
51+
/// <inheritdoc cref="CommandExtensions.ExecuteReaderAsync(DbCommand, Action{DbDataReader}, CommandBehavior, CancellationToken)"/>
52+
public static async ValueTask ExecuteReaderAsync(this SqlCommand command,
53+
Func<SqlDataReader, ValueTask> handler,
54+
CommandBehavior behavior = CommandBehavior.Default,
55+
CancellationToken cancellationToken = default)
56+
{
57+
if (command is null) throw new ArgumentNullException(nameof(command));
58+
if (handler is null) throw new ArgumentNullException(nameof(handler));
59+
Contract.EndContractBlock();
60+
61+
ConnectionState state = await command.EnsureOpenAsync(cancellationToken).ConfigureAwait(false);
62+
if (state == ConnectionState.Closed) behavior |= CommandBehavior.CloseConnection;
63+
#if NETSTANDARD2_0
64+
#else
65+
await
66+
#endif
67+
using SqlDataReader reader = await command.ExecuteReaderAsync(behavior, cancellationToken).ConfigureAwait(false);
68+
await handler(reader).ConfigureAwait(false);
69+
}
70+
71+
/// <inheritdoc cref="ExecuteReaderAsync(SqlCommand, Func{SqlDataReader, ValueTask}, CommandBehavior, CancellationToken)"/>
72+
public static async ValueTask ExecuteReaderAsync(this SqlCommand command,
73+
Action<SqlDataReader> handler,
74+
CommandBehavior behavior = CommandBehavior.Default,
75+
CancellationToken cancellationToken = default)
76+
{
77+
if (command is null) throw new ArgumentNullException(nameof(command));
78+
if (handler is null) throw new ArgumentNullException(nameof(handler));
79+
Contract.EndContractBlock();
80+
81+
ConnectionState state = await command
82+
.EnsureOpenAsync(cancellationToken)
83+
.ConfigureAwait(false);
84+
85+
if (state == ConnectionState.Closed) behavior |= CommandBehavior.CloseConnection;
86+
#if NETSTANDARD2_0
87+
#else
88+
await
89+
#endif
90+
using SqlDataReader reader = await command.ExecuteReaderAsync(behavior, cancellationToken).ConfigureAwait(false);
91+
handler(reader);
92+
}
93+
94+
/// <param name="command">The <see cref="DbCommand"/> to generate a reader from.</param>
95+
/// <param name="transform">The transform function for each <see cref="IDataRecord"/>.</param>
96+
/// <param name="behavior">The behavior to use with the data reader.</param>
97+
/// <param name="cancellationToken">The cancellation token.</param>
98+
/// <inheritdoc cref="CommandExtensions.ExecuteReaderAsync{T}(DbCommand, Func{DbDataReader, ValueTask{T}}, CommandBehavior, CancellationToken)"/>/>
99+
public static async ValueTask<T> ExecuteReaderAsync<T>(this SqlCommand command,
100+
Func<SqlDataReader, T> transform,
101+
CommandBehavior behavior = CommandBehavior.Default,
102+
CancellationToken cancellationToken = default)
103+
{
104+
if (command is null) throw new ArgumentNullException(nameof(command));
105+
if (transform is null) throw new ArgumentNullException(nameof(transform));
106+
Contract.EndContractBlock();
107+
108+
ConnectionState state = await command
109+
.EnsureOpenAsync(cancellationToken)
110+
.ConfigureAwait(false);
111+
112+
if (state == ConnectionState.Closed) behavior |= CommandBehavior.CloseConnection;
113+
#if NETSTANDARD2_0
114+
#else
115+
await
116+
#endif
117+
using SqlDataReader reader = await command.ExecuteReaderAsync(behavior, cancellationToken).ConfigureAwait(false);
118+
return transform(reader);
119+
}
120+
}

Source/SqlClient/Extensions/Command.AddParameter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/// <summary>
44
/// SqlClient extensions for building a command and retrieving data using best practices.
55
/// </summary>
6-
public static class SqlCommandExtensions
6+
public static partial class SqlCommandExtensions
77
{
88
/// <summary>
99
/// Shortcut for adding command parameter.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System.Data.Common;
2+
using System.Runtime.CompilerServices;
3+
4+
namespace Open.Database.Extensions;
5+
6+
/// <summary>
7+
/// SqlClient extensions for building a command and retrieving data using best practices.
8+
/// </summary>
9+
public static partial class SqlCommandExtensions
10+
{
11+
#region Connection.EnsureOpen Shortcuts.
12+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
13+
private static ConnectionState EnsureOpen(this IDbCommand command)
14+
{
15+
#if DEBUG
16+
if (command.Connection is null) throw new InvalidOperationException("Cannot execute a command with a null connection.");
17+
#endif
18+
return command.Connection!.EnsureOpen();
19+
}
20+
21+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
22+
private static ValueTask<ConnectionState> EnsureOpenAsync(this IDbCommand command, CancellationToken cancellationToken)
23+
{
24+
#if DEBUG
25+
if (command.Connection is null) throw new ArgumentException("Cannot execute a command with a null connection.");
26+
#endif
27+
return command.Connection!.EnsureOpenAsync(cancellationToken);
28+
}
29+
#endregion
30+
31+
/// <param name="command">The <see cref="SqlCommand"/> to generate a reader from.</param>
32+
/// <param name="handler">The handler function for the <see cref="SqlDataReader"/>.</param>
33+
/// <param name="behavior">The behavior to use with the data reader.</param>
34+
/// <inheritdoc cref="CommandExtensions.ExecuteReader(IDbCommand, Action{IDataReader}, CommandBehavior)"/>
35+
public static void ExecuteReader(this SqlCommand command, Action<SqlDataReader> handler, CommandBehavior behavior = CommandBehavior.Default)
36+
{
37+
if (command is null) throw new ArgumentNullException(nameof(command));
38+
if (handler is null) throw new ArgumentNullException(nameof(handler));
39+
Contract.EndContractBlock();
40+
41+
ConnectionState state = command.EnsureOpen();
42+
if (state == ConnectionState.Closed) behavior |= CommandBehavior.CloseConnection;
43+
using SqlDataReader reader = command.ExecuteReader(behavior);
44+
handler(reader);
45+
}
46+
47+
/// <param name="command">The <see cref="SqlCommand"/> to generate a reader from.</param>
48+
/// <param name="handler">The handler function for the <see cref="SqlDataReader"/>.</param>
49+
/// <param name="behavior">The behavior to use with the data reader.</param>
50+
/// <param name="cancellationToken">The cancellation token.</param>
51+
/// <inheritdoc cref="CommandExtensions.ExecuteReaderAsync(DbCommand, Action{DbDataReader}, CommandBehavior, CancellationToken)"/>
52+
public static async ValueTask ExecuteReaderAsync(this SqlCommand command,
53+
Func<SqlDataReader, ValueTask> handler,
54+
CommandBehavior behavior = CommandBehavior.Default,
55+
CancellationToken cancellationToken = default)
56+
{
57+
if (command is null) throw new ArgumentNullException(nameof(command));
58+
if (handler is null) throw new ArgumentNullException(nameof(handler));
59+
Contract.EndContractBlock();
60+
61+
ConnectionState state = await command.EnsureOpenAsync(cancellationToken).ConfigureAwait(false);
62+
if (state == ConnectionState.Closed) behavior |= CommandBehavior.CloseConnection;
63+
#if NETSTANDARD2_0
64+
#else
65+
await
66+
#endif
67+
using SqlDataReader reader = await command.ExecuteReaderAsync(behavior, cancellationToken).ConfigureAwait(false);
68+
await handler(reader).ConfigureAwait(false);
69+
}
70+
71+
/// <inheritdoc cref="ExecuteReaderAsync(SqlCommand, Func{SqlDataReader, ValueTask}, CommandBehavior, CancellationToken)"/>
72+
public static async ValueTask ExecuteReaderAsync(this SqlCommand command,
73+
Action<SqlDataReader> handler,
74+
CommandBehavior behavior = CommandBehavior.Default,
75+
CancellationToken cancellationToken = default)
76+
{
77+
if (command is null) throw new ArgumentNullException(nameof(command));
78+
if (handler is null) throw new ArgumentNullException(nameof(handler));
79+
Contract.EndContractBlock();
80+
81+
ConnectionState state = await command
82+
.EnsureOpenAsync(cancellationToken)
83+
.ConfigureAwait(false);
84+
85+
if (state == ConnectionState.Closed) behavior |= CommandBehavior.CloseConnection;
86+
#if NETSTANDARD2_0
87+
#else
88+
await
89+
#endif
90+
using SqlDataReader reader = await command.ExecuteReaderAsync(behavior, cancellationToken).ConfigureAwait(false);
91+
handler(reader);
92+
}
93+
94+
/// <param name="command">The <see cref="DbCommand"/> to generate a reader from.</param>
95+
/// <param name="transform">The transform function for each <see cref="IDataRecord"/>.</param>
96+
/// <param name="behavior">The behavior to use with the data reader.</param>
97+
/// <param name="cancellationToken">The cancellation token.</param>
98+
/// <inheritdoc cref="CommandExtensions.ExecuteReaderAsync{T}(DbCommand, Func{DbDataReader, ValueTask{T}}, CommandBehavior, CancellationToken)"/>/>
99+
public static async ValueTask<T> ExecuteReaderAsync<T>(this SqlCommand command,
100+
Func<SqlDataReader, T> transform,
101+
CommandBehavior behavior = CommandBehavior.Default,
102+
CancellationToken cancellationToken = default)
103+
{
104+
if (command is null) throw new ArgumentNullException(nameof(command));
105+
if (transform is null) throw new ArgumentNullException(nameof(transform));
106+
Contract.EndContractBlock();
107+
108+
ConnectionState state = await command
109+
.EnsureOpenAsync(cancellationToken)
110+
.ConfigureAwait(false);
111+
112+
if (state == ConnectionState.Closed) behavior |= CommandBehavior.CloseConnection;
113+
#if NETSTANDARD2_0
114+
#else
115+
await
116+
#endif
117+
using SqlDataReader reader = await command.ExecuteReaderAsync(behavior, cancellationToken).ConfigureAwait(false);
118+
return transform(reader);
119+
}
120+
}

0 commit comments

Comments
 (0)