Skip to content

Instantly share code, notes, and snippets.

@zonaro
Last active July 7, 2023 16:43
Show Gist options
  • Save zonaro/c1057959b12d723bb5f1bec2284bdd08 to your computer and use it in GitHub Desktop.
Save zonaro/c1057959b12d723bb5f1bec2284bdd08 to your computer and use it in GitHub Desktop.
This file add overloads for each Dapper.SQLMapper method, allowing the use of FormattableString for building parametrized queries. Each parameter of string will be converted into a SQL parameter.
using System.Data;
using System.Globalization;
using System.Text.RegularExpressions;
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This file add overloads for each Dapper.SQLMapper method, allowing the use of FormattableString *
* for building parametrized queries. Each parameter of string will be converted into a SQL parameter. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
namespace Dapper
{
/// <inheritdoc cref="SqlMapper"/>
public static class SqlMapperExtensions
{
private const string DefaultParameterPrefix = "@__p";
#region Public Methods
/// <inheritdoc cref="SqlMapper.Execute"/>
public static int Execute(this IDbConnection cnn, FormattableString sql, object? param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string parameterPrefix = DefaultParameterPrefix, CultureInfo culture = null)
{
var (queryString, parameters) = sql.ToDapper(parameterPrefix, param, culture);
return cnn.Execute(queryString, parameters, transaction, commandTimeout, commandType);
}
/// <inheritdoc cref="SqlMapper.ExecuteAsync"/>
public static Task<int> ExecuteAsync(this IDbConnection cnn, FormattableString sql, object? param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string parameterPrefix = DefaultParameterPrefix, CultureInfo culture = null)
{
var (queryString, parameters) = sql.ToDapper(parameterPrefix, param, culture);
return cnn.ExecuteAsync(queryString, parameters, transaction, commandTimeout, commandType);
}
/// <inheritdoc cref="SqlMapper.Query{T}"/>
public static IEnumerable<T> Query<T>(this IDbConnection cnn, FormattableString sql, object? param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null, string parameterPrefix = DefaultParameterPrefix, CultureInfo culture = null)
{
var (queryString, parameters) = sql.ToDapper(parameterPrefix, param, culture);
return cnn.Query<T>(queryString, parameters, transaction, buffered, commandTimeout, commandType);
}
/// <inheritdoc cref="SqlMapper.QueryAsync{T}"/>
public static Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, FormattableString sql, object? param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string parameterPrefix = DefaultParameterPrefix, CultureInfo culture = null)
{
var (queryString, parameters) = sql.ToDapper(parameterPrefix, param, culture);
return cnn.QueryAsync<T>(queryString, parameters, transaction, commandTimeout, commandType);
}
/// <inheritdoc cref="SqlMapper.QueryFirst{T}"/>
public static T QueryFirst<T>(this IDbConnection cnn, FormattableString sql, object? param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string parameterPrefix = DefaultParameterPrefix, CultureInfo culture = null)
{
var (queryString, parameters) = sql.ToDapper(parameterPrefix, param, culture);
return cnn.QueryFirst<T>(queryString, parameters, transaction, commandTimeout, commandType);
}
/// <inheritdoc cref="SqlMapper.QueryFirstAsync{T}"/>
public static Task<T> QueryFirstAsync<T>(this IDbConnection cnn, FormattableString sql, object? param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string parameterPrefix = DefaultParameterPrefix, CultureInfo culture = null)
{
var (queryString, parameters) = sql.ToDapper(parameterPrefix, param, culture);
return cnn.QueryFirstAsync<T>(queryString, parameters, transaction, commandTimeout, commandType);
}
/// <inheritdoc cref="SqlMapper.QueryFirstOrDefault{T}"/>
public static T QueryFirstOrDefault<T>(this IDbConnection cnn, FormattableString sql, object? param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string parameterPrefix = DefaultParameterPrefix, CultureInfo culture = null)
{
var (queryString, parameters) = sql.ToDapper(parameterPrefix, param, culture);
return cnn.QueryFirstOrDefault<T>(queryString, parameters, transaction, commandTimeout, commandType);
}
/// <inheritdoc cref="SqlMapper.QueryFirstOrDefaultAsync{T}"/>
public static Task<T> QueryFirstOrDefaultAsync<T>(this IDbConnection cnn, FormattableString sql, object? param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string parameterPrefix = DefaultParameterPrefix, CultureInfo culture = null)
{
var (queryString, parameters) = sql.ToDapper(parameterPrefix, param, culture);
return cnn.QueryFirstOrDefaultAsync<T>(queryString, parameters, transaction, commandTimeout, commandType);
}
/// <summary>
/// Converts a FormattableString to a Dapper query and DynamicParameters.
/// </summary>
/// <param name="sql">The FormattableString to convert.</param>
/// <param name="parameterPrefix">the prefix used for each parameter</param>
/// <param name="aditionalParameters">Append aditional parameters using <see cref="DynamicParameters.AddDynamicParams(object)"/></param>
/// <returns>A tuple containing the query string and DynamicParameters.</returns>
public static (string query, DynamicParameters parameters) ToDapper(this FormattableString sql, string parameterPrefix = null, object aditionalParameters = null, CultureInfo culture = null)
{
culture = culture ?? culture ?? CultureInfo.InvariantCulture;
parameterPrefix = string.IsNullOrWhiteSpace(parameterPrefix) ? DefaultParameterPrefix : parameterPrefix;
var dynamicParameters = new DynamicParameters();
for (int i = 0; i < sql.ArgumentCount; i++)
{
var arg = sql.GetArgument(i);
var format = sql.Format;
var index = "{" + i + ":";
var f = format.IndexOf(index);
if (f >= 0)
{
if (arg is IFormattable farg && farg != null)
{
var argumentFormat = format.Substring(f + index.Length);
argumentFormat = argumentFormat.Substring(0, argumentFormat.IndexOf("}"));
arg = farg.ToString(argumentFormat, culture);
}
else
{
arg = arg?.ToString();
}
}
dynamicParameters.Add($"{parameterPrefix}{i}", arg);
}
if (aditionalParameters != null)
{
dynamicParameters.AddDynamicParams(aditionalParameters);
}
var q = new Regex(@"\{(\d+)(:[^}]+)?\}").Replace(sql.Format, match => $"{parameterPrefix}{match.Groups[1].Value}");
return (query: q, parameters: dynamicParameters);
}
#endregion Public Methods
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment