Dapper.SimpleSqlBuilder.StrongName
2.0.0-beta
See the version list below for details.
dotnet add package Dapper.SimpleSqlBuilder.StrongName --version 2.0.0-beta
NuGet\Install-Package Dapper.SimpleSqlBuilder.StrongName -Version 2.0.0-beta
<PackageReference Include="Dapper.SimpleSqlBuilder.StrongName" Version="2.0.0-beta" />
paket add Dapper.SimpleSqlBuilder.StrongName --version 2.0.0-beta
#r "nuget: Dapper.SimpleSqlBuilder.StrongName, 2.0.0-beta"
// Install Dapper.SimpleSqlBuilder.StrongName as a Cake Addin #addin nuget:?package=Dapper.SimpleSqlBuilder.StrongName&version=2.0.0-beta&prerelease // Install Dapper.SimpleSqlBuilder.StrongName as a Cake Tool #tool nuget:?package=Dapper.SimpleSqlBuilder.StrongName&version=2.0.0-beta&prerelease
Dapper Simple Sql Builder
A simple SQL builder (that tries not to do too much 😊) for Dapper using string interpolation for building dynamic sql.
This library provides a simple and easy way to build dynamic SQL and commands, that can be executed using the Dapper library. This is achieved by leveraging FormattableString to capture parameters and produce parameterized SQL.
The library doesn't do anything special but parameterize the SQL, therefore all of Dapper's features and quirks still apply.
Packages
Dapper.SimpleSqlBuilder: A simple sql builder for Dapper using string interpolation.
Dapper.SimpleSqlBuilder.StrongName: A package that uses Dapper.StrongName.
Dapper.SimpleSqlBuilder.DependencyInjection: A dependency injection extension for .Net Core.
Simple Builder
String Interpolation
Static SQL
using Dapper.SimpleSqlBuilder;
int userTypeId = 10;
var builder = SimpleBuilder.Create($@"
SELECT * FROM User
WHERE UserTypeId = {userTypeId} AND AGE >= {25}");
The concern you might have here is the issue of sql injection, however this is mitigated by the library as the SQL statement is converted to this.
SELECT * FROM User
WHERE UserTypeId = @p0 AND AGE >= @p1
And all values passed in the interpolated string are taken out and replaced with parameter placeholders. The parameter values are put into Dapper's DynamicParameters collection.
To execute the query with Dapper is as simple as this.
dbConnection.Execute(builder.Sql, builder.Parameters);
Dynamic SQL
You can concatenate multiple interpolated strings to build your dynamic sql.
var user = new User { TypeId = 10, Role = "Admin", Age = 20 };
var builder = SimpleBuilder.Create($"SELECT * FROM User");
builder += $" WHERE UserTypeId = {user.TypeId}";
if (user.Age is not null)
{
builder += $" AND AGE >= {user.Age}"
}
This will produce the sql below.
SELECT * FROM User WHERE UserTypeId = @p0 AND AGE >= @p1
Builder Chaining
If you prefer an alternative to interpolated string concatenation, you can use the Append methods (Append(...)
& AppendNewLine(...)
) which can be chained.
int id = 10;
var builder = SimpleBuilder.Create($"SELECT * FROM User")
.AppendNewLine($"WHERE UserTypeId = {id}")
.Append($"AND Age >= {25}")
.AppendNewLine($"ORDER BY Age ASC");
This will produce the sql below.
SELECT * FROM User
WHERE UserTypeId = @p0 AND Age >= @p1
ORDER BY Name ASC
You can also use it with conditional statements.
var builder = SimpleBuilder.Create()
.Append($"SELECT * FROM User WHERE UserTypeId = {user.TypeId}");
if (user.Age is not null)
{
builder.Append($"AND Age >= {user.Age}");
}
builder.Append($"ORDER BY Age ASC");
Note: The Append(...)
method adds a space before the sql text by default. You can use AppendIntact(...)
if you don't want this behaviour.
Performing INSERT, UPDATE AND DELETE operations
Performing INSERT Operations
You can perform INSERT operations by passing the values in the interpolated string as seen below.
var builder = SimpleBuilder.Create($@"
INSERT INTO User (Role, Age)
VALUES ({user.Role}, {user.Age}");
Performing UPDATE Operations
You can perform UPDATE operations by passing the values in the interpolated string as seen below.
var builder = SimpleBuilder.Create($@"
UPDATE User SET Role = {user.Role}
WHERE Id = {user.Id}");
Performing DELETE Operations
You can perform DELETE operations by passing the values in interpolated string as seen below.
var builder = SimpleBuilder.Create($"DELETE FROM User WHERE Id = {user.Id}");
Executing Stored Procedures
var builder = SimpleBuilder.Create($"UserResources.ProcessUserInformation")
.AddParameter("UserRole", userRole)
.AddParameter("UserAge", userAge)
.AddParameter("UserId", dbType: DbType.Int32, direction: ParameterDirection.Output)
.AddParameter("Result", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
dbConnection.Execute(builder.Sql, builder.Parameters, commandType: CommandType.StoredProcedure);
int id = builder.GetValue<int>("UserId");
int result = builder.GetValue<int>("Result");
Formattable String
The library supports passing Formattable strings within Formattable strings.
int userTypeId = 10;
FormattableString subQuery = $"SELECT Description from UserType WHERE Id = {userTypeId}";
var builder = SimpleBuilder.Create(@$"
SELECT x.*, ({subQuery}) AS Description
FROM User x
WHERE UserTypeId = {userTypeId}");
This will create the sql below.
SELECT x.*, (SELECT Description from UserType WHERE Id = @p0) AS Description
FROM User x
WHERE UserTypeId = @p1;
Parameter properties
The library enables you to configure parameter properties via the AddParameter(...)
method. For example, you may want to define a DbType
for a parameter, and the code below is how you might do this.
var builder = SimpleBuilder.Create($"SELECT * FROM User Where Id = @id")
.AddParameter("id", value: user.Id, dbType: DbType.Int64);
However, the library also provides an extension method to easily achieve this while using interpolated strings.
using Dapper.SimpleSqlBuilder.Extensions;
// Define parameter properties
var idParam = user.Id.DefineParam(dbType: DbType.Int64);
var builder = SimpleBuilder.Create($"SELECT * FROM User Where Id = {idParam}");
// OR
// Defining parameter properties inline
var builder = SimpleBuilder
.Create($"SELECT * FROM User Where Id = {user.Id.DefineParam(dbType: DbType.Int64)}");
The DefineParam(...)
extension method enables you to define the DbType
, Size
, Precision
and Scale
of your parameter. This should only be used for parameters passed into the interpolated string, as the parameter direction is always set to Input
for values in the interpolated string.
As an alternative to the extension method you can manually create the parameter object.
var idParam = new SimpleParameterInfo(dbType: DbType.Int64);
Configuring Simple Builder Settings
You can configure the simple builder settings through the SimpleBuilderSettings
static class by calling the Configure(...)
method. However, if you are using the dependency injection library refer to the Dependency Injection section on how to configure the simple builder settings.
The code below shows how to do this.
SimpleBuilderSettings.Configure
(
parameterNameTemplate: "param", //Optional. Default is "p"
parameterPrefix: ":", //Optional. Default is "@"
reuseParameters: true // //Optional. Default is "false"
);
Configuring Parameter Name Template
The default parameter name template is p
, meaning when parameters are created they will be named p0 p1 p2 ...
You can configure this by passing your desired value to the parameterNameTemplate
argument.
SimpleBuilderSettings.Configure(parameterNameTemplate: "param");
Configuring Parameter Prefix
The default parameter prefix is @
, meaning when parameters are passed to the database they will be passed as @p0 @p1 @p2 ...
, and this will not be applicable to all databases. You can configure this by passing your desired value to the parameterPrefix
argument.
SimpleBuilderSettings.Configure(parameterPrefix: ":");
This can also be configured per simple builder instance if you want to override the global settings.
var builder = SimpleBuilder.Create(parameterPrefix: ":");
Configuring Parameter Reuse
The library supports parameter reuse, and the default is false
. Go to the Reusing Parameters section to learn more. You can configure this by passing your desired value to the reuseParameters
argument.
SimpleBuilderSettings.Configure(reuseParameters: true);
This can also be configured per simple builder instance if you want to override the global settings.
var builder = SimpleBuilder.Create(reuseParameters: true);
Reusing Parameters
The library supports reusing the same parameter name for parameters with the same value, type, and properties. This is turned off by default, however can be enabled globally via the simple builder settings or per simple builder instance.
Note: Parameter reuse does not apply to null
values.
See below for illustration.
// Configuring globally
SimpleBuilderSettings.Configure(reuseParameters: true);
int maxAge = 30;
int userTypeId = 10;
var builder = SimpleBuilder.Create(@$"
SELECT x.*, (SELECT Description from UserType WHERE Id = {userTypeId}) AS Description
FROM User x
WHERE UserTypeId = {userTypeId}
AND Age <= {maxAge}");
The generated sql will be.
SELECT x.*, (SELECT Description from UserType WHERE Id = @p0) AS Description
FROM User x
WHERE UserTypeId = @p0
AND Age <= @p1"
Raw values (:raw)
Do not use raw values if you don't trust the source or have not sanitized your value, as this can lead to sql injection.
There might be scenarios where you may want to pass a raw value into the interpolated string and not parameterize the value.
Example 1.1: Dynamic Data Retrieval
IEnumerable<dynamic> GetTableData(string tableName, DateTime createDate)
{
var builder = SimpleBuilder.Create($"SELECT * FROM {tableName:raw} WHERE CreatedDate = {createDate}");
return dbConnection.Query(builder.Sql, builder.Parameters);
}
Example 1.2: Dynamic Table Name
void CreateTable(string tableName)
{
var builder = SimpleBuilder.Create($@"
CREATE TABLE {tableName:raw}
(
Id INT PRIMARY KEY,
Age INT NOT NULL,
Role NVARCHAR(100) NOT NULL
)");
dbConnection.Execute(builder.Sql);
}
Example 2 : Column names with nameof()
var builder = SimpleBuilder.Create($@"
SELECT {nameof(user.Id):raw}, {nameof(user.Age):raw}, {nameof(user.Age):raw}
FROM User");
Dependency Injection
An alternative to using the static classes to access the simple builder and settings is via dependency injection. Use the Dapper.SimpleSqlBuilder.DependencyInjection nuget package instead of the default package. The library supports the default dependency injection pattern in .Net Core.
using Dapper.SimpleSqlBuilder.DependencyInjection;
services.AddSimpleSqlBuilder();
Usage in a class.
class MyClass
{
private readonly simpleBuilder;
public MyClass(ISimpleBuilder simpleBuilder)
{
this.simpleBuilder = simpleBuilder;
}
public void MyMethod()
{
int id = 10;
var builder = simpleBuilder.Create($"SELECT * FROM User WHERE ID = {id}");
//Other code below .....
}
}
Configuring Simple Builder settings
You can also configure the simple builder settings and the ISimpleBuilder
instance service lifetime.
services.AddSimpleSqlBuilder(
serviceLifeTime = ServiceLifetime.Scoped, //Optional. Default is ServiceLifetime.Singleton
configure =>
{
configure.DatabaseParameterNameTemplate = "param"; //Optional. Default is "p"
configure.DatabaseParameterPrefix = ":"; //Optional. Default is "@"
configure.ReuseParameters = true; //Optional. Default is "false"
});
Database Support
The library supports any database that Dapper supports. However, the library has been tested against MSSQL, MySQL and PostgreSQL databases. The integration test can be found here SimpleSqlBuilder.IntegrationTests. The tests provide real world examples of how the library can the utilised.
Benchmark
The benchmark below shows the performance of the SimpleSqlBuilder
compared to Dapper's SqlBuilder for building queries only (this does not benchmark sql execution).
BenchmarkDotNet=v0.13.2, OS=Windows 11 (10.0.22000.918/21H2)
Intel Core i7-8750H CPU 2.20GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK=6.0.400
[Host] : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT AVX2
DefaultJob : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT AVX2
Method | Mean | Allocated |
---|---|---|
'SqlBuilder (Dapper) - Simple query' | 1.658 μs | 2.6 KB |
'SimpleSqlBuilder - Simple query' | 1.952 μs | 4.08 KB |
'SimpleSqlBuilder - Simple query (Reuse parameters)' | 2.537 μs | 4.92 KB |
'SqlBuilder (Dapper) - Large query' | 84.578 μs | 274.55 KB |
'SimpleSqlBuilder - Large query' | 149.545 μs | 281.65 KB |
'SimpleSqlBuilder - Large query (Reuse parameters)' | 195.550 μs | 293.99 KB |
Refer to the benchmark project for more information.
Contributing
Refer to the Contributing guide for more details.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 is compatible. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.1
- Dapper.StrongName (>= 2.0.123)
- Microsoft.Bcl.HashCode (>= 1.1.1)
-
.NETStandard 2.0
- Dapper.StrongName (>= 2.0.123)
- Microsoft.Bcl.HashCode (>= 1.1.1)
-
net6.0
- Dapper.StrongName (>= 2.0.123)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
4.0.5 | 488 | 7/4/2024 |
4.0.3-beta | 98 | 7/3/2024 |
4.0.0-beta | 97 | 7/1/2024 |
3.7.4 | 126 | 5/19/2024 |
3.7.2-beta | 93 | 5/15/2024 |
3.7.0-beta | 94 | 5/15/2024 |
3.6.2 | 146 | 2/6/2024 |
3.6.0-beta | 106 | 2/6/2024 |
3.5.1 | 203 | 12/13/2023 |
3.5.0-beta | 104 | 12/13/2023 |
3.4.1 | 178 | 10/30/2023 |
3.4.0-beta | 120 | 10/29/2023 |
3.3.9 | 187 | 7/19/2023 |
3.3.8-beta | 126 | 7/19/2023 |
3.3.1 | 212 | 6/9/2023 |
3.2.8-beta | 125 | 6/9/2023 |
3.2.4 | 417 | 5/28/2023 |
3.2.3-beta | 120 | 5/27/2023 |
3.2.2-beta | 123 | 5/27/2023 |
3.2.0-beta | 109 | 5/19/2023 |
3.1.3 | 232 | 3/4/2023 |
3.1.1-beta | 138 | 3/4/2023 |
3.1.0-beta | 132 | 3/4/2023 |
3.0.3 | 258 | 2/13/2023 |
3.0.1-beta | 140 | 2/12/2023 |
3.0.0-beta | 145 | 2/12/2023 |
2.0.1 | 284 | 1/23/2023 |
2.0.0-beta | 144 | 1/21/2023 |
1.1.0 | 310 | 1/16/2023 |
1.0.0 | 420 | 10/9/2022 |
0.9.3-beta | 155 | 10/8/2022 |