Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dapper.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
version.json = version.json
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Contrib", "Dapper.Contrib\Dapper.Contrib.csproj", "{4E409F8F-CFBB-4332-8B0A-FD5A283051FD}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Contrib", "src\Dapper.Contrib\Dapper.Contrib.csproj", "{4E409F8F-CFBB-4332-8B0A-FD5A283051FD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Tests.Contrib", "tests\Dapper.Tests.Contrib\Dapper.Tests.Contrib.csproj", "{DAB3C5B7-BCD1-4A5F-BB6B-50D2BB63DB4A}"
EndProject
Expand Down
12 changes: 12 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@ Dapper.Contrib makes use of some optional attributes:
* `[Write(true/false)]` - this property is (not) writeable
* `[Computed]` - this property is computed and should not be part of updates

Custom parameter prefix
-------
By default Dapper.Contrib uses the character `@` as parameter prefix for SQL query and parameters collection. This can be changed throught the `GetParameterPrefixForQuery` and `GetParameterPrefixForParameterCollection` delegates:
Comment thread
jonataspc marked this conversation as resolved.
Outdated

```csharp
// Defines ':' as prefix for SQL query and '?' for parameters collection
SqlMapperExtensions.GetParameterPrefixForQuery = () => ":";
SqlMapperExtensions.GetParameterPrefixForParameterCollection = () => "?";
```

This setting may be useful when using Dapper.Contrib with database providers that use other character as a parameter prefix.

Limitations and caveats
-------

Expand Down
15 changes: 9 additions & 6 deletions src/Dapper.Contrib/SqlMapperExtensions.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ public static async Task<T> GetAsync<T>(this IDbConnection connection, dynamic i
var key = GetSingleKey<T>(nameof(GetAsync));
var name = GetTableName(type);

sql = $"SELECT * FROM {name} WHERE {key.Name} = @id";
sql = $"SELECT * FROM {name} WHERE {key.Name} = {GetParameterPrefixQuery()}id";
GetQueries[type.TypeHandle] = sql;
}

var dynParams = new DynamicParameters();
dynParams.Add("@id", id);
dynParams.Add($"{GetParameterPrefixParams()}id", id);
Comment thread
jonataspc marked this conversation as resolved.

if (!type.IsInterface)
return (await connection.QueryAsync<T>(sql, dynParams, transaction, commandTimeout).ConfigureAwait(false)).FirstOrDefault();
Expand Down Expand Up @@ -168,6 +168,7 @@ public static Task<int> InsertAsync<T>(this IDbConnection connection, T entityTo
var keyProperties = KeyPropertiesCache(type).ToList();
var computedProperties = ComputedPropertiesCache(type);
var allPropertiesExceptKeyAndComputed = allProperties.Except(keyProperties.Union(computedProperties)).ToList();
string parameterPrefix = GetParameterPrefixQuery();

for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{
Expand All @@ -181,7 +182,7 @@ public static Task<int> InsertAsync<T>(this IDbConnection connection, T entityTo
for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{
var property = allPropertiesExceptKeyAndComputed[i];
sbParameterList.AppendFormat("@{0}", property.Name);
sbParameterList.AppendFormat("{0}{1}", parameterPrefix, property.Name);
if (i < allPropertiesExceptKeyAndComputed.Count - 1)
sbParameterList.Append(", ");
}
Expand Down Expand Up @@ -248,19 +249,20 @@ public static async Task<bool> UpdateAsync<T>(this IDbConnection connection, T e
var nonIdProps = allProperties.Except(keyProperties.Union(computedProperties)).ToList();

var adapter = GetFormatter(connection);
string parameterPrefix = GetParameterPrefixQuery();

for (var i = 0; i < nonIdProps.Count; i++)
{
var property = nonIdProps[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name);
adapter.AppendColumnNameEqualsValue(sb, property.Name, parameterPrefix);
if (i < nonIdProps.Count - 1)
sb.Append(", ");
}
sb.Append(" where ");
for (var i = 0; i < keyProperties.Count; i++)
{
var property = keyProperties[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name);
adapter.AppendColumnNameEqualsValue(sb, property.Name, parameterPrefix);
if (i < keyProperties.Count - 1)
sb.Append(" and ");
}
Expand Down Expand Up @@ -313,11 +315,12 @@ public static async Task<bool> DeleteAsync<T>(this IDbConnection connection, T e
sb.AppendFormat("DELETE FROM {0} WHERE ", name);

var adapter = GetFormatter(connection);
string parameterPrefix = GetParameterPrefixQuery();

for (var i = 0; i < allKeyProperties.Count; i++)
{
var property = allKeyProperties[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name);
adapter.AppendColumnNameEqualsValue(sb, property.Name, parameterPrefix);
if (i < allKeyProperties.Count - 1)
sb.Append(" AND ");
}
Expand Down
83 changes: 64 additions & 19 deletions src/Dapper.Contrib/SqlMapperExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ public interface ITableNameMapper
string GetTableName(Type type);
}

/// <summary>
/// Defines a custom parameter prefix.
/// </summary>
/// <returns></returns>
public delegate string GetParameterPrefixDelegate();

/// <summary>
/// The function to get a database type from the given <see cref="IDbConnection"/>.
/// </summary>
Expand Down Expand Up @@ -176,12 +182,12 @@ public static T Get<T>(this IDbConnection connection, dynamic id, IDbTransaction
var key = GetSingleKey<T>(nameof(Get));
var name = GetTableName(type);

sql = $"select * from {name} where {key.Name} = @id";
sql = $"select * from {name} where {key.Name} = {GetParameterPrefixQuery()}id";
GetQueries[type.TypeHandle] = sql;
}

var dynParams = new DynamicParameters();
dynParams.Add("@id", id);
dynParams.Add($"{GetParameterPrefixParams()}id", id);

T obj;

Expand Down Expand Up @@ -350,6 +356,7 @@ public static long Insert<T>(this IDbConnection connection, T entityToInsert, ID
var allPropertiesExceptKeyAndComputed = allProperties.Except(keyProperties.Union(computedProperties)).ToList();

var adapter = GetFormatter(connection);
var parameterPrefix = GetParameterPrefixQuery();

for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{
Expand All @@ -363,7 +370,7 @@ public static long Insert<T>(this IDbConnection connection, T entityToInsert, ID
for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{
var property = allPropertiesExceptKeyAndComputed[i];
sbParameterList.AppendFormat("@{0}", property.Name);
sbParameterList.AppendFormat("{0}{1}", parameterPrefix, property.Name);
if (i < allPropertiesExceptKeyAndComputed.Count - 1)
sbParameterList.Append(", ");
}
Expand Down Expand Up @@ -438,19 +445,20 @@ public static bool Update<T>(this IDbConnection connection, T entityToUpdate, ID
var nonIdProps = allProperties.Except(keyProperties.Union(computedProperties)).ToList();

var adapter = GetFormatter(connection);
string parameterPrefix = GetParameterPrefixQuery();

for (var i = 0; i < nonIdProps.Count; i++)
{
var property = nonIdProps[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
adapter.AppendColumnNameEqualsValue(sb, property.Name, parameterPrefix); //fix for issue #336
if (i < nonIdProps.Count - 1)
sb.Append(", ");
}
sb.Append(" where ");
for (var i = 0; i < keyProperties.Count; i++)
{
var property = keyProperties[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
adapter.AppendColumnNameEqualsValue(sb, property.Name, parameterPrefix); //fix for issue #336
if (i < keyProperties.Count - 1)
sb.Append(" and ");
}
Expand Down Expand Up @@ -503,11 +511,12 @@ public static bool Delete<T>(this IDbConnection connection, T entityToDelete, ID
sb.AppendFormat("delete from {0} where ", name);

var adapter = GetFormatter(connection);
string parameterPrefix = GetParameterPrefixQuery();

for (var i = 0; i < keyProperties.Count; i++)
{
var property = keyProperties[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
adapter.AppendColumnNameEqualsValue(sb, property.Name, parameterPrefix); //fix for issue #336
if (i < keyProperties.Count - 1)
sb.Append(" and ");
}
Expand All @@ -532,6 +541,35 @@ public static bool DeleteAll<T>(this IDbConnection connection, IDbTransaction tr
return deleted > 0;
}

/// <summary>
/// Defines a custom parameter prefix in the query. <inheritdoc cref="_defaultParameterPrefix"/> will be used as default
/// </summary>
#pragma warning disable CA2211 // Non-constant fields should not be visible - I agree with you, but we can't do that until we break the API
public static GetParameterPrefixDelegate GetParameterPrefixForQuery;
#pragma warning restore CA2211 // Non-constant fields should not be visible

/// <summary>
/// Defines a custom parameter prefix in the parameters collection. <inheritdoc cref="_defaultParameterPrefix"/> will be used as default
/// </summary>
#pragma warning disable CA2211 // Non-constant fields should not be visible - I agree with you, but we can't do that until we break the API
public static GetParameterPrefixDelegate GetParameterPrefixForParameterCollection;
#pragma warning restore CA2211 // Non-constant fields should not be visible

/// <summary>
/// '@'
/// </summary>
private const string _defaultParameterPrefix = "@";

private static string GetParameterPrefixQuery()
{
return GetParameterPrefixForQuery?.Invoke() ?? _defaultParameterPrefix;
}

private static string GetParameterPrefixParams()
{
return GetParameterPrefixForParameterCollection?.Invoke() ?? _defaultParameterPrefix;
}

/// <summary>
/// Specifies a custom callback that detects the database type instead of relying on the default strategy (the name of the connection type object).
/// Please note that this callback is global and will be used by all the calls that require a database specific adapter.
Expand Down Expand Up @@ -798,7 +836,8 @@ public partial interface ISqlAdapter
/// </summary>
/// <param name="sb">The string builder to append to.</param>
/// <param name="columnName">The column name.</param>
void AppendColumnNameEqualsValue(StringBuilder sb, string columnName);
/// <param name="parameterPrefix">Parameter prefix.</param>
void AppendColumnNameEqualsValue(StringBuilder sb, string columnName, string parameterPrefix);
}

/// <summary>
Expand Down Expand Up @@ -851,9 +890,10 @@ public void AppendColumnName(StringBuilder sb, string columnName)
/// </summary>
/// <param name="sb">The string builder to append to.</param>
/// <param name="columnName">The column name.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
/// <param name="parameterPrefix">Parameter prefix.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName, string parameterPrefix)
{
sb.AppendFormat("[{0}] = @{1}", columnName, columnName);
sb.AppendFormat("[{0}] = {2}{1}", columnName, columnName, parameterPrefix);
}
}

Expand Down Expand Up @@ -907,9 +947,10 @@ public void AppendColumnName(StringBuilder sb, string columnName)
/// </summary>
/// <param name="sb">The string builder to append to.</param>
/// <param name="columnName">The column name.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
/// <param name="parameterPrefix">Parameter prefix.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName, string parameterPrefix)
{
sb.AppendFormat("[{0}] = @{1}", columnName, columnName);
sb.AppendFormat("[{0}] = {2}{1}", columnName, columnName, parameterPrefix);
}
}

Expand Down Expand Up @@ -962,9 +1003,10 @@ public void AppendColumnName(StringBuilder sb, string columnName)
/// </summary>
/// <param name="sb">The string builder to append to.</param>
/// <param name="columnName">The column name.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
/// <param name="parameterPrefix">Parameter prefix.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName, string parameterPrefix)
{
sb.AppendFormat("`{0}` = @{1}", columnName, columnName);
sb.AppendFormat("`{0}` = {2}{1}", columnName, columnName, parameterPrefix);
}
}

Expand Down Expand Up @@ -1038,9 +1080,10 @@ public void AppendColumnName(StringBuilder sb, string columnName)
/// </summary>
/// <param name="sb">The string builder to append to.</param>
/// <param name="columnName">The column name.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
/// <param name="parameterPrefix">Parameter prefix.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName, string parameterPrefix)
{
sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName);
sb.AppendFormat("\"{0}\" = {2}{1}", columnName, columnName, parameterPrefix);
}
}

Expand Down Expand Up @@ -1091,9 +1134,10 @@ public void AppendColumnName(StringBuilder sb, string columnName)
/// </summary>
/// <param name="sb">The string builder to append to.</param>
/// <param name="columnName">The column name.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
/// <param name="parameterPrefix">Parameter prefix.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName, string parameterPrefix)
{
sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName);
sb.AppendFormat("\"{0}\" = {2}{1}", columnName, columnName, parameterPrefix);
}
}

Expand Down Expand Up @@ -1148,8 +1192,9 @@ public void AppendColumnName(StringBuilder sb, string columnName)
/// </summary>
/// <param name="sb">The string builder to append to.</param>
/// <param name="columnName">The column name.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
/// <param name="parameterPrefix">Parameter prefix.</param>
public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName, string parameterPrefix)
{
sb.AppendFormat("{0} = @{1}", columnName, columnName);
sb.AppendFormat("{0} = {2}{1}", columnName, columnName, parameterPrefix);
}
}
9 changes: 9 additions & 0 deletions tests/Dapper.Tests.Contrib/TestSuite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,15 @@ public void InsertList()
InsertHelper(src => src.ToList());
}

[Fact]
public void InsertListWithCustomParameterPrefix()
{
SqlMapperExtensions.GetParameterPrefixForQuery = () => "@";
SqlMapperExtensions.GetParameterPrefixForParameterCollection = () => "@";

InsertHelper(src => src.ToList());
}

private void InsertHelper<T>(Func<IEnumerable<User>, T> helper)
where T : class
{
Expand Down