Skip to content

Commit c9239f9

Browse files
Add Open.Database.Extensions project and refactor code
- Updated solution file to include new project for Open.Database.Extensions with build configurations. - Converted Param struct to readonly record struct in ExpressiveCommandBase.Param.cs for improved immutability. - Modified AddParam methods in ExpressiveCommandBase.cs to support new Param structure and added overloads for direction. - Changed versioning scheme in Directory.Build.props to use version prefix and suffix. - Enhanced parameter handling in ExpressiveSqlCommand.cs to check for null values during parameter creation. - Created Open.Database.Extensions.csproj to define project structure and dependencies.
1 parent 099526c commit c9239f9

7 files changed

+143
-145
lines changed

Open.Database.Extensions.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
2424
EndProject
2525
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Open.Database.Extensions.MSSqlClient", "Source\MSSqlClient\Open.Database.Extensions.MSSqlClient.csproj", "{B9245504-9E2F-417F-87AC-8950BFB4FD4E}"
2626
EndProject
27+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Open.Database.Extensions", "Source\Extensions\Open.Database.Extensions.csproj", "{446C228B-E12F-424D-AB46-B856422EBDAE}"
28+
EndProject
2729
Global
2830
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2931
Debug|Any CPU = Debug|Any CPU
@@ -54,6 +56,10 @@ Global
5456
{B9245504-9E2F-417F-87AC-8950BFB4FD4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
5557
{B9245504-9E2F-417F-87AC-8950BFB4FD4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
5658
{B9245504-9E2F-417F-87AC-8950BFB4FD4E}.Release|Any CPU.Build.0 = Release|Any CPU
59+
{446C228B-E12F-424D-AB46-B856422EBDAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
60+
{446C228B-E12F-424D-AB46-B856422EBDAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
61+
{446C228B-E12F-424D-AB46-B856422EBDAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
62+
{446C228B-E12F-424D-AB46-B856422EBDAE}.Release|Any CPU.Build.0 = Release|Any CPU
5763
EndGlobalSection
5864
GlobalSection(SolutionProperties) = preSolution
5965
HideSolutionNode = FALSE

Source/Core/ExpressiveCommandBase.Param.cs

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,58 +11,38 @@ public abstract partial class ExpressiveCommandBase<TConnection, TCommand, TRead
1111
/// A struct that represents the param to be created when the command is executed.
1212
/// TDbType facilitates the difference between DbType and SqlDbType.
1313
/// </summary>
14-
public struct Param : IEquatable<Param>
14+
public readonly record struct Param : IEquatable<Param>
1515

1616
{
1717
/// <summary>
18-
/// The name of the param.
18+
/// Constructs a <see cref="Param"/>.
1919
/// </summary>
20-
public string Name { get; set; }
20+
public Param(string name, object? value, TDbType? type = null, ParameterDirection direction = ParameterDirection.Input)
21+
{
22+
Name = name;
23+
Value = value;
24+
Type = type;
25+
Direction = direction;
26+
}
2127

2228
/// <summary>
23-
/// The value of the param.
29+
/// The name of the param.
2430
/// </summary>
25-
public object Value { get; set; }
31+
public string Name { get; }
2632

2733
/// <summary>
28-
/// The DbType of the param.
34+
/// The value of the param.
2935
/// </summary>
30-
public TDbType? Type { get; set; }
31-
32-
/// <inheritdoc />
33-
public readonly bool Equals(Param other)
34-
=> Name == other.Name
35-
&& EqualityComparer<object>.Default.Equals(Value, other.Value)
36-
&& EqualityComparer<TDbType?>.Default.Equals(Type, other.Type);
37-
38-
/// <inheritdoc />
39-
public override readonly bool Equals(object? obj)
40-
=> obj is Param o && Equals(o);
41-
42-
/// <inheritdoc />
43-
#if NETSTANDARD2_0
44-
[SuppressMessage("Roslynator", "RCS1123:Add parentheses when necessary", Justification = "<Pending>")]
45-
public override readonly int GetHashCode()
46-
{
47-
int hashCode = 1477810893;
48-
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name);
49-
hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(Value);
50-
hashCode = hashCode * -1521134295 + EqualityComparer<TDbType?>.Default.GetHashCode(Type);
51-
return hashCode;
52-
}
53-
#else
54-
public override readonly int GetHashCode()
55-
=> HashCode.Combine(Name, Value, Type);
56-
#endif
36+
public object? Value { get; }
5737

5838
/// <summary>
59-
/// Equality operator.
39+
/// The DbType of the param.
6040
/// </summary>
61-
public static bool operator ==(Param left, Param right) => left.Equals(right);
41+
public TDbType? Type { get; }
6242

6343
/// <summary>
64-
/// Inequality operator.
44+
/// The direction of the param.
6545
/// </summary>
66-
public static bool operator !=(Param left, Param right) => !left.Equals(right);
46+
public ParameterDirection Direction { get; }
6747
}
6848
}

Source/Core/ExpressiveCommandBase.cs

Lines changed: 80 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -179,138 +179,115 @@ public TThis UseCancellationToken(CancellationToken token)
179179
}
180180

181181
#region AddParam
182+
182183
/// <summary>
183184
/// Adds a parameter to the params list.
184185
/// </summary>
185186
/// <param name="name">The name of the parameter.</param>
186187
/// <param name="value">The value of the parameter.</param>
187188
/// <param name="type">The database type of the parameter.</param>
189+
/// <param name="direction">The direction of the parameter.</param>
188190
/// <returns>This instance for use in method chaining.</returns>
189-
public TThis AddParam(string name, object value, TDbType type)
191+
/// <exception cref="ArgumentNullException"><paramref name="name"/> is null.</exception>
192+
/// <exception cref="ArgumentException"><paramref name="name"/> is blank.</exception>
193+
public TThis AddParam(string name, object value, TDbType type, ParameterDirection direction = ParameterDirection.Input)
190194
{
191195
if (name is null) throw new ArgumentNullException(nameof(name));
192-
else if (string.IsNullOrWhiteSpace(name))
196+
if (string.IsNullOrWhiteSpace(name))
193197
throw new ArgumentException("Parameter names cannot be empty or white space.", nameof(name));
194198
Contract.EndContractBlock();
195199

196-
Params.Add(new Param
197-
{
198-
Name = name,
199-
Value = value,
200-
Type = type
201-
});
202-
200+
Params.Add(new(name, value, type, direction));
203201
return (TThis)this;
204202
}
205203

206-
/// <summary>
207-
/// Adds a parameter to the params list.
208-
/// </summary>
209-
/// <param name="name">The name of the parameter.</param>
210-
/// <param name="value">The value of the parameter.</param>
211-
/// <returns>This instance for use in method chaining.</returns>
212-
public TThis AddParam(string name, object value)
204+
/// <inheritdoc cref="AddParam(string, object, TDbType, ParameterDirection)"/>
205+
public TThis AddParam(string name, object? value, ParameterDirection direction = ParameterDirection.Input)
213206
{
214207
if (name is null) throw new ArgumentNullException(nameof(name));
215-
else if (string.IsNullOrWhiteSpace(name))
208+
if (string.IsNullOrWhiteSpace(name))
216209
throw new ArgumentException("Parameter names cannot be empty or white space.", nameof(name));
217210
Contract.EndContractBlock();
218211

219-
Params.Add(new Param
220-
{
221-
Name = name,
222-
Value = value ?? DBNull.Value
223-
});
224-
212+
Params.Add(new(name, value ?? DBNull.Value, null, direction));
225213
return (TThis)this;
226214
}
227215

228-
/// <summary>
229-
/// Adds a parameter to the params list.
230-
/// </summary>
231-
/// <param name="name">The name of the parameter.</param>
232-
/// <param name="value">The value of the parameter.</param>
233-
/// <param name="type">The database type of the parameter.</param>
234-
/// <returns>This instance for use in method chaining.</returns>
235-
public TThis AddParam<T>(string name, T? value, TDbType type)
216+
/// <inheritdoc cref="AddParam(string, object, TDbType, ParameterDirection)"/>
217+
public TThis AddParam<T>(string name, T? value, TDbType? type = null, ParameterDirection direction = ParameterDirection.Input)
236218
where T : struct
237219
{
238220
if (name is null) throw new ArgumentNullException(nameof(name));
239-
else if (string.IsNullOrWhiteSpace(name))
221+
if (string.IsNullOrWhiteSpace(name))
240222
throw new ArgumentException("Parameter names cannot be empty or white space.", nameof(name));
241223
Contract.EndContractBlock();
242224

243-
Params.Add(new Param
244-
{
245-
Name = name,
246-
Type = type,
247-
Value = value ?? (object)DBNull.Value
248-
});
225+
Params.Add(new(name, value ?? (object)DBNull.Value, type, direction));
226+
return (TThis)this;
227+
}
228+
229+
/// <inheritdoc cref="AddParam(string, object, TDbType, ParameterDirection)"/>
230+
public TThis AddParam(string name, string? value, TDbType? type = null, ParameterDirection direction = ParameterDirection.Input)
231+
{
232+
if (name is null) throw new ArgumentNullException(nameof(name));
233+
if (string.IsNullOrWhiteSpace(name))
234+
throw new ArgumentException("Parameter names cannot be empty or white space.", nameof(name));
235+
Contract.EndContractBlock();
249236

237+
Params.Add(new(name, value ?? (object)DBNull.Value, type, direction));
250238
return (TThis)this;
251239
}
252240

253-
/// <summary>
254-
/// Adds a parameter to the params list.
255-
/// </summary>
256-
/// <param name="name">The name of the parameter.</param>
257-
/// <param name="value">The value of the parameter.</param>
258-
/// <returns>This instance for use in method chaining.</returns>
259-
public TThis AddParam<T>(string name, T? value)
260-
where T : struct
241+
/// <inheritdoc cref="AddParam(string, object, TDbType, ParameterDirection)"/>
242+
public TThis AddParam(string name, TDbType type, ParameterDirection direction = ParameterDirection.Input)
261243
{
262244
if (name is null) throw new ArgumentNullException(nameof(name));
245+
if (string.IsNullOrWhiteSpace(name))
246+
throw new ArgumentException("Parameter names cannot be empty or white space.", nameof(name));
263247
Contract.EndContractBlock();
264248

265-
Params.Add(new Param
266-
{
267-
Name = name,
268-
Value = value ?? (object)DBNull.Value
269-
});
249+
Params.Add(new (name, null, type, direction));
250+
return (TThis)this;
251+
}
252+
253+
/// <inheritdoc cref="AddParam(string, object, TDbType, ParameterDirection)"/>
254+
public TThis AddParam(string name, ParameterDirection direction = ParameterDirection.Input)
255+
{
256+
if (name is null) throw new ArgumentNullException(nameof(name));
257+
if (string.IsNullOrWhiteSpace(name))
258+
throw new ArgumentException("Parameter names cannot be empty or white space.", nameof(name));
259+
Contract.EndContractBlock();
270260

261+
Params.Add(new(name, null, null, direction));
271262
return (TThis)this;
272263
}
273264

274265
/// <summary>
275-
/// Adds a parameter to the params list.
266+
/// Adds a return parameter to the params list.
276267
/// </summary>
277-
/// <param name="name">The name of the parameter.</param>
278-
/// <returns>This instance for use in method chaining.</returns>
279-
public TThis AddParam(string name)
268+
/// <inheritdoc cref="AddParam(string, object, TDbType, ParameterDirection)"/>
269+
public TThis AddReturnParam(string name, TDbType type)
280270
{
281271
if (name is null) throw new ArgumentNullException(nameof(name));
282-
else if (string.IsNullOrWhiteSpace(name))
272+
if (string.IsNullOrWhiteSpace(name))
283273
throw new ArgumentException("Parameter names cannot be empty or white space.", nameof(name));
284274
Contract.EndContractBlock();
285275

286-
Params.Add(new Param
287-
{
288-
Name = name
289-
});
290-
276+
Params.Add(new(name, null, type, ParameterDirection.ReturnValue));
291277
return (TThis)this;
292278
}
293279

294-
/// <summary>
295-
/// Conditionally adds a parameter to the params list.
296-
/// </summary>
297-
/// <param name="condition">The condition to add the param by. Only adds if true.</param>
298-
/// <param name="name">The name of the parameter.</param>
299-
/// <param name="value">The value of the parameter.</param>
300-
/// <returns>This instance for use in method chaining.</returns>
301-
public TThis AddParamIf<T>(bool condition, string name, T? value)
302-
where T : struct
303-
=> condition ? AddParam(name, value) : (TThis)this;
280+
/// <inheritdoc cref="AddReturnParam(string, TDbType)"/>
281+
public TThis AddReturnParam(string name)
282+
{
283+
if (name is null) throw new ArgumentNullException(nameof(name));
284+
if (string.IsNullOrWhiteSpace(name))
285+
throw new ArgumentException("Parameter names cannot be empty or white space.", nameof(name));
286+
Contract.EndContractBlock();
304287

305-
/// <summary>
306-
/// Conditionally adds a parameter to the params list.
307-
/// </summary>
308-
/// <param name="condition">The condition to add the param by. Only adds if true.</param>
309-
/// <param name="name">The name of the parameter.</param>
310-
/// <param name="value">The value of the parameter.</param>
311-
/// <returns>This instance for use in method chaining.</returns>
312-
public TThis AddParamIf(bool condition, string name, object value)
313-
=> condition ? AddParam(name, value) : (TThis)this;
288+
Params.Add(new(name, null, null, ParameterDirection.ReturnValue));
289+
return (TThis)this;
290+
}
314291

315292
/// <summary>
316293
/// Conditionally adds a parameter to the params list.
@@ -319,30 +296,32 @@ public TThis AddParamIf(bool condition, string name, object value)
319296
/// <param name="name">The name of the parameter.</param>
320297
/// <param name="value">The value of the parameter.</param>
321298
/// <param name="type">The database type of the parameter.</param>
322-
/// <returns>This instance for use in method chaining.</returns>
323-
public TThis AddParamIf(bool condition, string name, object value, TDbType type)
324-
=> condition ? AddParam(name, value, type) : (TThis)this;
299+
/// <param name="direction">The direction of the parameter.</param>
300+
/// <inheritdoc cref="AddParam(string, object, TDbType, ParameterDirection)"/>
301+
public TThis AddParamIf(bool condition, string name, object value, TDbType type, ParameterDirection direction = ParameterDirection.Input)
302+
=> condition ? AddParam(name, value, type, direction) : (TThis)this;
325303

326-
/// <summary>
327-
/// Conditionally adds a parameter to the params list.
328-
/// </summary>
329-
/// <param name="condition">The condition to add the param by. Only adds if true.</param>
330-
/// <param name="name">The name of the parameter.</param>
331-
/// <param name="value">The value of the parameter.</param>
332-
/// <param name="type">The database type of the parameter.</param>
333-
/// <returns>This instance for use in method chaining.</returns>
334-
public TThis AddParamIf<T>(bool condition, string name, T? value, TDbType type)
304+
/// <inheritdoc cref="AddParamIf(bool, string, object, TDbType, ParameterDirection)"/>
305+
public TThis AddParamIf<T>(bool condition, string name, T? value, ParameterDirection direction = ParameterDirection.Input)
335306
where T : struct
336-
=> condition ? AddParam(name, value, type) : (TThis)this;
307+
=> condition ? AddParam(name, value, null, direction) : (TThis)this;
337308

338-
/// <summary>
339-
/// Conditionally adds a parameter to the params list.
340-
/// </summary>
341-
/// <param name="condition">The condition to add the param by. Only adds if true.</param>
342-
/// <param name="name">The name of the parameter.</param>
343-
/// <returns>This instance for use in method chaining.</returns>
344-
public TThis AddParamIf(bool condition, string name)
345-
=> condition ? AddParam(name) : (TThis)this;
309+
/// <inheritdoc cref="AddParamIf(bool, string, object, TDbType, ParameterDirection)"/>
310+
public TThis AddParamIf(bool condition, string name, object? value, ParameterDirection direction = ParameterDirection.Input)
311+
=> condition ? AddParam(name, value, direction) : (TThis)this;
312+
313+
/// <inheritdoc cref="AddParamIf(bool, string, object, TDbType, ParameterDirection)"/>
314+
public TThis AddParamIf<T>(bool condition, string name, T? value, TDbType? type, ParameterDirection direction = ParameterDirection.Input)
315+
where T : struct
316+
=> condition ? AddParam(name, value, type, direction) : (TThis)this;
317+
318+
/// <inheritdoc cref="AddParamIf(bool, string, object, TDbType, ParameterDirection)"/>
319+
public TThis AddParamIf(bool condition, string name, TDbType type, ParameterDirection direction = ParameterDirection.Input)
320+
=> condition ? AddParam(name, type, direction) : (TThis)this;
321+
322+
/// <inheritdoc cref="AddParamIf(bool, string, object, TDbType, ParameterDirection)"/>
323+
public TThis AddParamIf(bool condition, string name, ParameterDirection direction = ParameterDirection.Input)
324+
=> condition ? AddParam(name, direction) : (TThis)this;
346325

347326
/// <summary>
348327
/// Handles adding the list of parameters to a new command.

Source/Directory.Build.props

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
<PropertyGroup>
44
<RootNamespace>Open.Database.Extensions</RootNamespace>
5-
<Version>9.0.0</Version>
5+
6+
<VersionPrefix>9.0.1</VersionPrefix>
7+
<VersionSuffix Condition="'$(Configuration)' == 'Debug'">debug</VersionSuffix>
68

79
<TargetFrameworks>netstandard2.0; netstandard2.1; net8.0; net9.0;</TargetFrameworks>
810
<LangVersion>latest</LangVersion>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<Description>
5+
Useful set of utilities and abstractions for simplifying modern data-access operations and ensuring DI compatibility.
6+
This is simply a meta-package that includes Open.Database.Extensions.Core.
7+
</Description>
8+
<PackageTags>ado;ado extensions;sql;connection factory;extensions;</PackageTags>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<ProjectReference Include="..\Core\Open.Database.Extensions.Core.csproj" />
13+
</ItemGroup>
14+
15+
</Project>

Source/MSSqlClient/ExpressiveSqlCommand.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,18 @@ protected override void AddParams(SqlCommand command)
7171

7272
foreach (Param p in Params)
7373
{
74-
SqlParameter np = command
75-
.Parameters
76-
.AddWithValue(p.Name, p.Value);
74+
SqlParameter np;
75+
if (p.Value is null)
76+
{
77+
np = command.CreateParameter();
78+
np.ParameterName = p.Name;
79+
}
80+
else
81+
{
82+
np = command.Parameters.AddWithValue(p.Name, p.Value);
83+
}
7784

85+
np.Direction = p.Direction;
7886
if (p.Type.HasValue)
7987
np.SqlDbType = p.Type.Value;
8088
}

0 commit comments

Comments
 (0)