From 02ad65e9110d264150befbe124dd54d655ef89a5 Mon Sep 17 00:00:00 2001 From: Maarten Date: Mon, 24 Oct 2022 09:44:13 +0200 Subject: [PATCH 1/7] Added OleDb Adapter + added custom values for prepend and append parameters Get and Insert methods --- .../SqlMapperExtensions.Async.cs | 69 +++++++++++++- src/Dapper.Contrib/SqlMapperExtensions.cs | 94 +++++++++++++++++-- 2 files changed, 152 insertions(+), 11 deletions(-) diff --git a/src/Dapper.Contrib/SqlMapperExtensions.Async.cs b/src/Dapper.Contrib/SqlMapperExtensions.Async.cs index c93e39a4..f307ea91 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.Async.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.Async.cs @@ -21,21 +21,25 @@ public static partial class SqlMapperExtensions /// Id of the entity to get, must be marked with [Key] attribute /// The transaction to run under, null (the default) if none /// Number of seconds before command execution timeout + /// Prepend paramaters with this tag + /// Append paramaters with this tag /// Entity of T - public static async Task GetAsync(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class + public static async Task GetAsync(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null, string prependTag = "@", string appendTag = "") where T : class { var type = typeof(T); + var idParameter = string.Format("{0}id{1}", prependTag, appendTag); + if (!GetQueries.TryGetValue(type.TypeHandle, out string sql)) { var key = GetSingleKey(nameof(GetAsync)); var name = GetTableName(type); - sql = $"SELECT * FROM {name} WHERE {key.Name} = @id"; + sql = $"SELECT * FROM {name} WHERE {key.Name} = {idParameter}"; GetQueries[type.TypeHandle] = sql; } var dynParams = new DynamicParameters(); - dynParams.Add("@id", id); + dynParams.Add(idParameter, id); if (!type.IsInterface) return (await connection.QueryAsync(sql, dynParams, transaction, commandTimeout).ConfigureAwait(false)).FirstOrDefault(); @@ -135,9 +139,11 @@ private static async Task> GetAllAsyncImpl(IDbConnection conne /// The transaction to run under, null (the default) if none /// Number of seconds before command execution timeout /// The specific ISqlAdapter to use, auto-detected based on connection if null + /// Prepend paramaters with this tag + /// Append paramaters with this tag /// Identity of inserted entity public static Task InsertAsync(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, - int? commandTimeout = null, ISqlAdapter sqlAdapter = null) where T : class + int? commandTimeout = null, ISqlAdapter sqlAdapter = null, string prependTag = "@", string appendTag = "") where T : class { var type = typeof(T); sqlAdapter ??= GetFormatter(connection); @@ -181,7 +187,7 @@ public static Task InsertAsync(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}{2}", prependTag, property.Name, appendTag); if (i < allPropertiesExceptKeyAndComputed.Count - 1) sbParameterList.Append(", "); } @@ -575,3 +581,56 @@ public async Task InsertAsync(IDbConnection connection, IDbTransaction tran return Convert.ToInt32(id); } } + +public partial class OleDbAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var sb = new StringBuilder(); + sb.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2})", tableName, columnList, parameterList); + + // If no primary key then safe to assume a join table with not too much data to return + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) + { + sb.Append(" RETURNING *"); + } + else + { + sb.Append(" RETURNING "); + bool first = true; + foreach (var property in propertyInfos) + { + if (!first) + sb.Append(", "); + first = false; + sb.Append(property.Name); + } + } + + var results = await connection.QueryAsync(sb.ToString(), entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + + // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys + var id = 0; + foreach (var p in propertyInfos) + { + var value = ((IDictionary)results.First())[p.Name.ToLower()]; + p.SetValue(entityToInsert, value, null); + if (id == 0) + id = Convert.ToInt32(value); + } + return id; + } +} diff --git a/src/Dapper.Contrib/SqlMapperExtensions.cs b/src/Dapper.Contrib/SqlMapperExtensions.cs index 9a30e805..d4d23f24 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.cs @@ -9,6 +9,7 @@ using System.Threading; using Dapper; +using System.Data.Common; namespace Dapper.Contrib.Extensions { @@ -166,22 +167,25 @@ private static PropertyInfo GetSingleKey(string method) /// Id of the entity to get, must be marked with [Key] attribute /// The transaction to run under, null (the default) if none /// Number of seconds before command execution timeout + /// Prepend paramaters with this tag + /// Append paramaters with this tag /// Entity of T - public static T Get(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class + public static T Get(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null, string prependTag = "@", string appendTag = "") where T : class { var type = typeof(T); + var idParameter = string.Format("{0}id{1}", prependTag, appendTag); if (!GetQueries.TryGetValue(type.TypeHandle, out string sql)) { var key = GetSingleKey(nameof(Get)); var name = GetTableName(type); - - sql = $"select * from {name} where {key.Name} = @id"; + sql = $"select * from {name} where {key.Name} = {idParameter}"; GetQueries[type.TypeHandle] = sql; } var dynParams = new DynamicParameters(); - dynParams.Add("@id", id); + //sbParameterList.AppendFormat("@{0}", property.Name); + dynParams.Add(idParameter, id); T obj; @@ -316,8 +320,10 @@ private static string GetTableName(Type type) /// Entity to insert, can be list of entities /// The transaction to run under, null (the default) if none /// Number of seconds before command execution timeout + /// Prepend paramaters with this tag + /// Append paramaters with this tag /// Identity of inserted entity, or number of inserted rows if inserting a list - public static long Insert(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null) where T : class + public static long Insert(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null, string prependTag = "@", string appendTag = "") where T : class { var isList = false; @@ -363,7 +369,7 @@ public static long Insert(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}{2}", prependTag, property.Name, appendTag); if (i < allPropertiesExceptKeyAndComputed.Count - 1) sbParameterList.Append(", "); } @@ -1153,3 +1159,79 @@ public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) sb.AppendFormat("{0} = @{1}", columnName, columnName); } } + +/// +/// The OleDb database adapter. +/// +public partial class OleDbAdapter : ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var sb = new StringBuilder(); + sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList); + + // If no primary key then safe to assume a join table with not too much data to return + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) + { + sb.Append(" RETURNING *"); + } + else + { + sb.Append(" RETURNING "); + var first = true; + foreach (var property in propertyInfos) + { + if (!first) + sb.Append(", "); + first = false; + sb.Append(property.Name); + } + } + + var results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout).ToList(); + + // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys + var id = 0; + foreach (var p in propertyInfos) + { + var value = ((IDictionary)results[0])[p.Name.ToLower()]; + p.SetValue(entityToInsert, value, null); + if (id == 0) + id = Convert.ToInt32(value); + } + return id; + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\"", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\" = ?{1}?", columnName, columnName); + } +} From 5adb036e19d1487efd45f7a16f586cab81fe606e Mon Sep 17 00:00:00 2001 From: Maarten Date: Mon, 24 Oct 2022 09:52:06 +0200 Subject: [PATCH 2/7] Small fix for custom OleDb adapter --- src/Dapper.Contrib/SqlMapperExtensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Dapper.Contrib/SqlMapperExtensions.cs b/src/Dapper.Contrib/SqlMapperExtensions.cs index d4d23f24..031ca392 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.cs @@ -62,14 +62,15 @@ public interface ITableNameMapper private static readonly ISqlAdapter DefaultAdapter = new SqlServerAdapter(); private static readonly Dictionary AdapterDictionary - = new Dictionary(6) + = new Dictionary(7) { ["sqlconnection"] = new SqlServerAdapter(), ["sqlceconnection"] = new SqlCeServerAdapter(), ["npgsqlconnection"] = new PostgresAdapter(), ["sqliteconnection"] = new SQLiteAdapter(), ["mysqlconnection"] = new MySqlAdapter(), - ["fbconnection"] = new FbAdapter() + ["fbconnection"] = new FbAdapter(), + ["oledbconnection"] = new OleDbAdapter() }; private static List ComputedPropertiesCache(Type type) From f874dda4d99f6a67aaa1d0d45ad7f593abd72062 Mon Sep 17 00:00:00 2001 From: Maarten Date: Mon, 24 Oct 2022 15:41:23 +0200 Subject: [PATCH 3/7] Some more OleDb fixes for insert method --- Dapper.sln | 2 +- src/Dapper.Contrib/SqlMapperExtensions.cs | 27 +++++++++-------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Dapper.sln b/Dapper.sln index e993c7a4..4aa75f10 100644 --- a/Dapper.sln +++ b/Dapper.sln @@ -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 diff --git a/src/Dapper.Contrib/SqlMapperExtensions.cs b/src/Dapper.Contrib/SqlMapperExtensions.cs index 031ca392..b50f3c7f 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.cs @@ -1185,31 +1185,26 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com // If no primary key then safe to assume a join table with not too much data to return var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) - { - sb.Append(" RETURNING *"); - } - else + + sb.Append(" select @@identity "); + var first = true; + foreach (var property in propertyInfos) { - sb.Append(" RETURNING "); - var first = true; - foreach (var property in propertyInfos) - { - if (!first) - sb.Append(", "); - first = false; - sb.Append(property.Name); - } + if (!first) + sb.Append(", "); + first = false; + sb.Append(property.Name); } + var results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout).ToList(); // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys var id = 0; foreach (var p in propertyInfos) { - var value = ((IDictionary)results[0])[p.Name.ToLower()]; - p.SetValue(entityToInsert, value, null); + var value = ((IDictionary)results[0])[p.Name]; + p.SetValue(entityToInsert, Convert.ChangeType(value, p.PropertyType), null); if (id == 0) id = Convert.ToInt32(value); } From eb669255d826f0fc1764ccc12982a0a9233c857f Mon Sep 17 00:00:00 2001 From: Maarten Date: Tue, 25 Oct 2022 13:59:20 +0200 Subject: [PATCH 4/7] Built in notations for OleDb: no more custom parameters needed --- src/Dapper.Contrib/Adapters.cs | 899 ++++++++++++++++++ .../SqlMapperExtensions.Async.cs | 300 +----- src/Dapper.Contrib/SqlMapperExtensions.cs | 472 +-------- 3 files changed, 911 insertions(+), 760 deletions(-) create mode 100644 src/Dapper.Contrib/Adapters.cs diff --git a/src/Dapper.Contrib/Adapters.cs b/src/Dapper.Contrib/Adapters.cs new file mode 100644 index 00000000..17a9a3c7 --- /dev/null +++ b/src/Dapper.Contrib/Adapters.cs @@ -0,0 +1,899 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Dapper.Contrib +{ + /// + /// The interface for all Dapper.Contrib database operations + /// Implementing this is each provider's model. + /// + public partial interface ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert); + + /// + /// Get column with correct notation. + /// + /// The column name. + string GetColumnWithNotation(string columnName); + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + void AppendColumnName(StringBuilder sb, string columnName); + /// + /// Adds the value of a column. + /// + /// The string builder to append to. + /// The column name. + void AppendColumnValue(StringBuilder sb, string columnName); + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + void AppendColumnNameEqualsValue(StringBuilder sb, string columnName); + } + + /// + /// The SQL Server database adapter. + /// + public partial class SqlServerAdapter : ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"insert into {tableName} ({columnList}) values ({parameterList});select SCOPE_IDENTITY() id"; + var multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout); + + var first = multi.Read().FirstOrDefault(); + if (first == null || first.id == null) return 0; + + var id = (int)first.id; + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) return id; + + var idProperty = propertyInfos[0]; + idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); + + return id; + } + + /// + /// Get column with correct notation. + /// + /// The column name. + public string GetColumnWithNotation(string columnName) + { + return String.Format("@{0}", columnName); + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}]", columnName); + } + /// + /// Adds the value of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("@{0}", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}] = @{1}", columnName, columnName); + } + } + + /// + /// The SQL Server Compact Edition database adapter. + /// + public partial class SqlCeServerAdapter : ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; + connection.Execute(cmd, entityToInsert, transaction, commandTimeout); + var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ToList(); + + if (r[0].id == null) return 0; + var id = (int)r[0].id; + + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) return id; + + var idProperty = propertyInfos[0]; + idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); + + return id; + } + + /// + /// Get column with correct notation. + /// + /// The column name. + public string GetColumnWithNotation(string columnName) + { + return String.Format("@{0}", columnName); + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}]", columnName); + } + /// + /// Adds the value of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("@{0}", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}] = @{1}", columnName, columnName); + } + } + + /// + /// The MySQL database adapter. + /// + public partial class MySqlAdapter : ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; + connection.Execute(cmd, entityToInsert, transaction, commandTimeout); + var r = connection.Query("Select LAST_INSERT_ID() id", transaction: transaction, commandTimeout: commandTimeout); + + var id = r.First().id; + if (id == null) return 0; + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) return Convert.ToInt32(id); + + var idp = propertyInfos[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return Convert.ToInt32(id); + } + + /// + /// Get column with correct notation. + /// + /// The column name. + public string GetColumnWithNotation(string columnName) + { + return String.Format("@{0}", columnName); + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("`{0}`", columnName); + } + /// + /// Adds the value of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("@{0}", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("`{0}` = @{1}", columnName, columnName); + } + } + + /// + /// The Postgres database adapter. + /// + public partial class PostgresAdapter : ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var sb = new StringBuilder(); + sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList); + + // If no primary key then safe to assume a join table with not too much data to return + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) + { + sb.Append(" RETURNING *"); + } + else + { + sb.Append(" RETURNING "); + var first = true; + foreach (var property in propertyInfos) + { + if (!first) + sb.Append(", "); + first = false; + sb.Append(property.Name); + } + } + + var results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout).ToList(); + + // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys + var id = 0; + foreach (var p in propertyInfos) + { + var value = ((IDictionary)results[0])[p.Name.ToLower()]; + p.SetValue(entityToInsert, value, null); + if (id == 0) + id = Convert.ToInt32(value); + } + return id; + } + + /// + /// Get column with correct notation. + /// + /// The column name. + public string GetColumnWithNotation(string columnName) + { + return String.Format("@{0}", columnName); + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\"", columnName); + } + + /// + /// Adds the value of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("@{0}", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName); + } + } + + /// + /// The SQLite database adapter. + /// + public partial class SQLiteAdapter : ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id"; + var multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout); + + var id = (int)multi.Read().First().id; + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) return id; + + var idProperty = propertyInfos[0]; + idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); + + return id; + } + + /// + /// Get column with correct notation. + /// + /// The column name. + public string GetColumnWithNotation(string columnName) + { + return String.Format("@{0}", columnName); + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\"", columnName); + } + + /// + /// Adds the value of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("@{0}", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName); + } + } + + /// + /// The Firebase SQL adapter. + /// + public partial class FbAdapter : ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; + connection.Execute(cmd, entityToInsert, transaction, commandTimeout); + + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + var keyName = propertyInfos[0].Name; + var r = connection.Query($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout); + + var id = r.First().ID; + if (id == null) return 0; + if (propertyInfos.Length == 0) return Convert.ToInt32(id); + + var idp = propertyInfos[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return Convert.ToInt32(id); + } + + /// + /// Get column with correct notation. + /// + /// The column name. + public string GetColumnWithNotation(string columnName) + { + return String.Format("@{0}", columnName); + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("{0}", columnName); + } + + /// + /// Adds the value of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("@{0}", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("{0} = @{1}", columnName, columnName); + } + } + + /// + /// The OleDb database adapter. + /// + public partial class OleDbAdapter : ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var sb = new StringBuilder(); + sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList); + + // If no primary key then safe to assume a join table with not too much data to return + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + + sb.Append(" select @@identity "); + var first = true; + foreach (var property in propertyInfos) + { + if (!first) + sb.Append(", "); + first = false; + sb.Append(property.Name); + } + + + var results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout).ToList(); + + // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys + var id = 0; + foreach (var p in propertyInfos) + { + var value = ((IDictionary)results[0])[p.Name]; + p.SetValue(entityToInsert, Convert.ChangeType(value, p.PropertyType), null); + if (id == 0) + id = Convert.ToInt32(value); + } + return id; + } + + /// + /// Get column with correct notation. + /// + /// The column name. + public string GetColumnWithNotation(string columnName) + { + return String.Format("?{0}?", columnName); + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}]", columnName); + } + + /// + /// Adds the value of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("@{0}", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}] = ?{1}?", columnName, columnName); + } + } + + public partial interface ISqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert); + } + + public partial class SqlServerAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"INSERT INTO {tableName} ({columnList}) values ({parameterList}); SELECT SCOPE_IDENTITY() id"; + var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + + var first = await multi.ReadFirstOrDefaultAsync().ConfigureAwait(false); + if (first == null || first.id == null) return 0; + + var id = (int)first.id; + var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (pi.Length == 0) return id; + + var idp = pi[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return id; + } + } + + public partial class SqlCeServerAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList})"; + await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + var r = (await connection.QueryAsync("SELECT @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false)).ToList(); + + if (r[0] == null || r[0].id == null) return 0; + var id = (int)r[0].id; + + var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (pi.Length == 0) return id; + + var idp = pi[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return id; + } + } + + public partial class MySqlAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList})"; + await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + var r = await connection.QueryAsync("SELECT LAST_INSERT_ID() id", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false); + + var id = r.First().id; + if (id == null) return 0; + var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (pi.Length == 0) return Convert.ToInt32(id); + + var idp = pi[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return Convert.ToInt32(id); + } + } + + public partial class PostgresAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var sb = new StringBuilder(); + sb.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2})", tableName, columnList, parameterList); + + // If no primary key then safe to assume a join table with not too much data to return + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) + { + sb.Append(" RETURNING *"); + } + else + { + sb.Append(" RETURNING "); + bool first = true; + foreach (var property in propertyInfos) + { + if (!first) + sb.Append(", "); + first = false; + sb.Append(property.Name); + } + } + + var results = await connection.QueryAsync(sb.ToString(), entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + + // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys + var id = 0; + foreach (var p in propertyInfos) + { + var value = ((IDictionary)results.First())[p.Name.ToLower()]; + p.SetValue(entityToInsert, value, null); + if (id == 0) + id = Convert.ToInt32(value); + } + return id; + } + } + + public partial class SQLiteAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id"; + var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + + var id = (int)(await multi.ReadFirstAsync().ConfigureAwait(false)).id; + var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (pi.Length == 0) return id; + + var idp = pi[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return id; + } + } + + public partial class FbAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; + await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + var keyName = propertyInfos[0].Name; + var r = await connection.QueryAsync($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false); + + var id = r.First().ID; + if (id == null) return 0; + if (propertyInfos.Length == 0) return Convert.ToInt32(id); + + var idp = propertyInfos[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return Convert.ToInt32(id); + } + } + + public partial class OleDbAdapter + { + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + var sb = new StringBuilder(); + sb.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2})", tableName, columnList, parameterList); + + // If no primary key then safe to assume a join table with not too much data to return + var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) + { + sb.Append(" RETURNING *"); + } + else + { + sb.Append(" RETURNING "); + bool first = true; + foreach (var property in propertyInfos) + { + if (!first) + sb.Append(", "); + first = false; + sb.Append(property.Name); + } + } + + var results = await connection.QueryAsync(sb.ToString(), entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + + // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys + var id = 0; + foreach (var p in propertyInfos) + { + var value = ((IDictionary)results.First())[p.Name.ToLower()]; + p.SetValue(entityToInsert, value, null); + if (id == 0) + id = Convert.ToInt32(value); + } + return id; + } + } + + public class Adapters + { + } +} diff --git a/src/Dapper.Contrib/SqlMapperExtensions.Async.cs b/src/Dapper.Contrib/SqlMapperExtensions.Async.cs index f307ea91..63fdf106 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.Async.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.Async.cs @@ -21,13 +21,13 @@ public static partial class SqlMapperExtensions /// Id of the entity to get, must be marked with [Key] attribute /// The transaction to run under, null (the default) if none /// Number of seconds before command execution timeout - /// Prepend paramaters with this tag - /// Append paramaters with this tag /// Entity of T - public static async Task GetAsync(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null, string prependTag = "@", string appendTag = "") where T : class + public static async Task GetAsync(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class { + var adapter = GetFormatter(connection); + var type = typeof(T); - var idParameter = string.Format("{0}id{1}", prependTag, appendTag); + var idParameter = adapter.GetColumnWithNotation("id"); if (!GetQueries.TryGetValue(type.TypeHandle, out string sql)) { @@ -139,11 +139,9 @@ private static async Task> GetAllAsyncImpl(IDbConnection conne /// The transaction to run under, null (the default) if none /// Number of seconds before command execution timeout /// The specific ISqlAdapter to use, auto-detected based on connection if null - /// Prepend paramaters with this tag - /// Append paramaters with this tag /// Identity of inserted entity public static Task InsertAsync(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, - int? commandTimeout = null, ISqlAdapter sqlAdapter = null, string prependTag = "@", string appendTag = "") where T : class + int? commandTimeout = null, ISqlAdapter sqlAdapter = null) where T : class { var type = typeof(T); sqlAdapter ??= GetFormatter(connection); @@ -187,7 +185,7 @@ public static Task InsertAsync(this IDbConnection connection, T entityTo for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) { var property = allPropertiesExceptKeyAndComputed[i]; - sbParameterList.AppendFormat("{0}{1}{2}", prependTag, property.Name, appendTag); + sqlAdapter.AppendColumnValue(sbParameterList, property.Name); if (i < allPropertiesExceptKeyAndComputed.Count - 1) sbParameterList.Append(", "); } @@ -348,289 +346,3 @@ public static async Task DeleteAllAsync(this IDbConnection connection, } } } - -public partial interface ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert); -} - -public partial class SqlServerAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"INSERT INTO {tableName} ({columnList}) values ({parameterList}); SELECT SCOPE_IDENTITY() id"; - var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); - - var first = await multi.ReadFirstOrDefaultAsync().ConfigureAwait(false); - if (first == null || first.id == null) return 0; - - var id = (int)first.id; - var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (pi.Length == 0) return id; - - var idp = pi[0]; - idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); - - return id; - } -} - -public partial class SqlCeServerAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList})"; - await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); - var r = (await connection.QueryAsync("SELECT @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false)).ToList(); - - if (r[0] == null || r[0].id == null) return 0; - var id = (int)r[0].id; - - var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (pi.Length == 0) return id; - - var idp = pi[0]; - idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); - - return id; - } -} - -public partial class MySqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, - string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList})"; - await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); - var r = await connection.QueryAsync("SELECT LAST_INSERT_ID() id", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false); - - var id = r.First().id; - if (id == null) return 0; - var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (pi.Length == 0) return Convert.ToInt32(id); - - var idp = pi[0]; - idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); - - return Convert.ToInt32(id); - } -} - -public partial class PostgresAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var sb = new StringBuilder(); - sb.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2})", tableName, columnList, parameterList); - - // If no primary key then safe to assume a join table with not too much data to return - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) - { - sb.Append(" RETURNING *"); - } - else - { - sb.Append(" RETURNING "); - bool first = true; - foreach (var property in propertyInfos) - { - if (!first) - sb.Append(", "); - first = false; - sb.Append(property.Name); - } - } - - var results = await connection.QueryAsync(sb.ToString(), entityToInsert, transaction, commandTimeout).ConfigureAwait(false); - - // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys - var id = 0; - foreach (var p in propertyInfos) - { - var value = ((IDictionary)results.First())[p.Name.ToLower()]; - p.SetValue(entityToInsert, value, null); - if (id == 0) - id = Convert.ToInt32(value); - } - return id; - } -} - -public partial class SQLiteAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id"; - var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); - - var id = (int)(await multi.ReadFirstAsync().ConfigureAwait(false)).id; - var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (pi.Length == 0) return id; - - var idp = pi[0]; - idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); - - return id; - } -} - -public partial class FbAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; - await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); - - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - var keyName = propertyInfos[0].Name; - var r = await connection.QueryAsync($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false); - - var id = r.First().ID; - if (id == null) return 0; - if (propertyInfos.Length == 0) return Convert.ToInt32(id); - - var idp = propertyInfos[0]; - idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); - - return Convert.ToInt32(id); - } -} - -public partial class OleDbAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var sb = new StringBuilder(); - sb.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2})", tableName, columnList, parameterList); - - // If no primary key then safe to assume a join table with not too much data to return - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) - { - sb.Append(" RETURNING *"); - } - else - { - sb.Append(" RETURNING "); - bool first = true; - foreach (var property in propertyInfos) - { - if (!first) - sb.Append(", "); - first = false; - sb.Append(property.Name); - } - } - - var results = await connection.QueryAsync(sb.ToString(), entityToInsert, transaction, commandTimeout).ConfigureAwait(false); - - // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys - var id = 0; - foreach (var p in propertyInfos) - { - var value = ((IDictionary)results.First())[p.Name.ToLower()]; - p.SetValue(entityToInsert, value, null); - if (id == 0) - id = Convert.ToInt32(value); - } - return id; - } -} diff --git a/src/Dapper.Contrib/SqlMapperExtensions.cs b/src/Dapper.Contrib/SqlMapperExtensions.cs index b50f3c7f..51ea7c28 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.cs @@ -168,13 +168,13 @@ private static PropertyInfo GetSingleKey(string method) /// Id of the entity to get, must be marked with [Key] attribute /// The transaction to run under, null (the default) if none /// Number of seconds before command execution timeout - /// Prepend paramaters with this tag - /// Append paramaters with this tag /// Entity of T - public static T Get(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null, string prependTag = "@", string appendTag = "") where T : class + public static T Get(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class { + var adapter = GetFormatter(connection); + var type = typeof(T); - var idParameter = string.Format("{0}id{1}", prependTag, appendTag); + var idParameter = adapter.GetColumnWithNotation("id"); if (!GetQueries.TryGetValue(type.TypeHandle, out string sql)) { @@ -321,10 +321,8 @@ private static string GetTableName(Type type) /// Entity to insert, can be list of entities /// The transaction to run under, null (the default) if none /// Number of seconds before command execution timeout - /// Prepend paramaters with this tag - /// Append paramaters with this tag /// Identity of inserted entity, or number of inserted rows if inserting a list - public static long Insert(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null, string prependTag = "@", string appendTag = "") where T : class + public static long Insert(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null) where T : class { var isList = false; @@ -370,7 +368,7 @@ public static long Insert(this IDbConnection connection, T entityToInsert, ID for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) { var property = allPropertiesExceptKeyAndComputed[i]; - sbParameterList.AppendFormat("{0}{1}{2}", prependTag, property.Name, appendTag); + adapter.AppendColumnValue(sbParameterList, property.Name); if (i < allPropertiesExceptKeyAndComputed.Count - 1) sbParameterList.Append(", "); } @@ -773,461 +771,3 @@ public class ComputedAttribute : Attribute { } } - -/// -/// The interface for all Dapper.Contrib database operations -/// Implementing this is each provider's model. -/// -public partial interface ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert); - - /// - /// Adds the name of a column. - /// - /// The string builder to append to. - /// The column name. - void AppendColumnName(StringBuilder sb, string columnName); - /// - /// Adds a column equality to a parameter. - /// - /// The string builder to append to. - /// The column name. - void AppendColumnNameEqualsValue(StringBuilder sb, string columnName); -} - -/// -/// The SQL Server database adapter. -/// -public partial class SqlServerAdapter : ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"insert into {tableName} ({columnList}) values ({parameterList});select SCOPE_IDENTITY() id"; - var multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout); - - var first = multi.Read().FirstOrDefault(); - if (first == null || first.id == null) return 0; - - var id = (int)first.id; - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) return id; - - var idProperty = propertyInfos[0]; - idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); - - return id; - } - - /// - /// Adds the name of a column. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnName(StringBuilder sb, string columnName) - { - sb.AppendFormat("[{0}]", columnName); - } - - /// - /// Adds a column equality to a parameter. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) - { - sb.AppendFormat("[{0}] = @{1}", columnName, columnName); - } -} - -/// -/// The SQL Server Compact Edition database adapter. -/// -public partial class SqlCeServerAdapter : ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; - connection.Execute(cmd, entityToInsert, transaction, commandTimeout); - var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ToList(); - - if (r[0].id == null) return 0; - var id = (int)r[0].id; - - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) return id; - - var idProperty = propertyInfos[0]; - idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); - - return id; - } - - /// - /// Adds the name of a column. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnName(StringBuilder sb, string columnName) - { - sb.AppendFormat("[{0}]", columnName); - } - - /// - /// Adds a column equality to a parameter. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) - { - sb.AppendFormat("[{0}] = @{1}", columnName, columnName); - } -} - -/// -/// The MySQL database adapter. -/// -public partial class MySqlAdapter : ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; - connection.Execute(cmd, entityToInsert, transaction, commandTimeout); - var r = connection.Query("Select LAST_INSERT_ID() id", transaction: transaction, commandTimeout: commandTimeout); - - var id = r.First().id; - if (id == null) return 0; - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) return Convert.ToInt32(id); - - var idp = propertyInfos[0]; - idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); - - return Convert.ToInt32(id); - } - - /// - /// Adds the name of a column. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnName(StringBuilder sb, string columnName) - { - sb.AppendFormat("`{0}`", columnName); - } - - /// - /// Adds a column equality to a parameter. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) - { - sb.AppendFormat("`{0}` = @{1}", columnName, columnName); - } -} - -/// -/// The Postgres database adapter. -/// -public partial class PostgresAdapter : ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var sb = new StringBuilder(); - sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList); - - // If no primary key then safe to assume a join table with not too much data to return - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) - { - sb.Append(" RETURNING *"); - } - else - { - sb.Append(" RETURNING "); - var first = true; - foreach (var property in propertyInfos) - { - if (!first) - sb.Append(", "); - first = false; - sb.Append(property.Name); - } - } - - var results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout).ToList(); - - // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys - var id = 0; - foreach (var p in propertyInfos) - { - var value = ((IDictionary)results[0])[p.Name.ToLower()]; - p.SetValue(entityToInsert, value, null); - if (id == 0) - id = Convert.ToInt32(value); - } - return id; - } - - /// - /// Adds the name of a column. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnName(StringBuilder sb, string columnName) - { - sb.AppendFormat("\"{0}\"", columnName); - } - - /// - /// Adds a column equality to a parameter. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) - { - sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName); - } -} - -/// -/// The SQLite database adapter. -/// -public partial class SQLiteAdapter : ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id"; - var multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout); - - var id = (int)multi.Read().First().id; - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) return id; - - var idProperty = propertyInfos[0]; - idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); - - return id; - } - - /// - /// Adds the name of a column. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnName(StringBuilder sb, string columnName) - { - sb.AppendFormat("\"{0}\"", columnName); - } - - /// - /// Adds a column equality to a parameter. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) - { - sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName); - } -} - -/// -/// The Firebase SQL adapter. -/// -public partial class FbAdapter : ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})"; - connection.Execute(cmd, entityToInsert, transaction, commandTimeout); - - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - var keyName = propertyInfos[0].Name; - var r = connection.Query($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout); - - var id = r.First().ID; - if (id == null) return 0; - if (propertyInfos.Length == 0) return Convert.ToInt32(id); - - var idp = propertyInfos[0]; - idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); - - return Convert.ToInt32(id); - } - - /// - /// Adds the name of a column. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnName(StringBuilder sb, string columnName) - { - sb.AppendFormat("{0}", columnName); - } - - /// - /// Adds a column equality to a parameter. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) - { - sb.AppendFormat("{0} = @{1}", columnName, columnName); - } -} - -/// -/// The OleDb database adapter. -/// -public partial class OleDbAdapter : ISqlAdapter -{ - /// - /// Inserts into the database, returning the Id of the row created. - /// - /// The connection to use. - /// The transaction to use. - /// The command timeout to use. - /// The table to insert into. - /// The columns to set with this insert. - /// The parameters to set for this insert. - /// The key columns in this table. - /// The entity to insert. - /// The Id of the row created. - public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) - { - var sb = new StringBuilder(); - sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList); - - // If no primary key then safe to assume a join table with not too much data to return - var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - - sb.Append(" select @@identity "); - var first = true; - foreach (var property in propertyInfos) - { - if (!first) - sb.Append(", "); - first = false; - sb.Append(property.Name); - } - - - var results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout).ToList(); - - // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys - var id = 0; - foreach (var p in propertyInfos) - { - var value = ((IDictionary)results[0])[p.Name]; - p.SetValue(entityToInsert, Convert.ChangeType(value, p.PropertyType), null); - if (id == 0) - id = Convert.ToInt32(value); - } - return id; - } - - /// - /// Adds the name of a column. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnName(StringBuilder sb, string columnName) - { - sb.AppendFormat("\"{0}\"", columnName); - } - - /// - /// Adds a column equality to a parameter. - /// - /// The string builder to append to. - /// The column name. - public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) - { - sb.AppendFormat("\"{0}\" = ?{1}?", columnName, columnName); - } -} From 831d39e3e4903110ff2083d7b3396be50095d666 Mon Sep 17 00:00:00 2001 From: Maarten Geelen Date: Mon, 3 Apr 2023 13:31:28 +0200 Subject: [PATCH 5/7] Small fixes --- src/Dapper.Contrib/Adapters.cs | 33 ++++++++----------- .../SqlMapperExtensions.Async.cs | 2 +- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/Dapper.Contrib/Adapters.cs b/src/Dapper.Contrib/Adapters.cs index 17a9a3c7..4d384a85 100644 --- a/src/Dapper.Contrib/Adapters.cs +++ b/src/Dapper.Contrib/Adapters.cs @@ -593,7 +593,7 @@ public void AppendColumnName(StringBuilder sb, string columnName) /// The column name. public void AppendColumnValue(StringBuilder sb, string columnName) { - sb.AppendFormat("@{0}", columnName); + sb.AppendFormat("?{0}?", columnName); } /// @@ -857,35 +857,30 @@ public partial class OleDbAdapter public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) { var sb = new StringBuilder(); - sb.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2})", tableName, columnList, parameterList); + sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList); // If no primary key then safe to assume a join table with not too much data to return var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); - if (propertyInfos.Length == 0) - { - sb.Append(" RETURNING *"); - } - else + + sb.Append(" select @@identity "); + var first = true; + foreach (var property in propertyInfos) { - sb.Append(" RETURNING "); - bool first = true; - foreach (var property in propertyInfos) - { - if (!first) - sb.Append(", "); - first = false; - sb.Append(property.Name); - } + if (!first) + sb.Append(", "); + first = false; + sb.Append(property.Name); } - var results = await connection.QueryAsync(sb.ToString(), entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + + var results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout).ToList(); // Return the key by assigning the corresponding property in the object - by product is that it supports compound primary keys var id = 0; foreach (var p in propertyInfos) { - var value = ((IDictionary)results.First())[p.Name.ToLower()]; - p.SetValue(entityToInsert, value, null); + var value = ((IDictionary)results[0])[p.Name]; + p.SetValue(entityToInsert, Convert.ChangeType(value, p.PropertyType), null); if (id == 0) id = Convert.ToInt32(value); } diff --git a/src/Dapper.Contrib/SqlMapperExtensions.Async.cs b/src/Dapper.Contrib/SqlMapperExtensions.Async.cs index 63fdf106..9257378e 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.Async.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.Async.cs @@ -39,7 +39,7 @@ public static async Task GetAsync(this IDbConnection connection, dynamic i } var dynParams = new DynamicParameters(); - dynParams.Add(idParameter, id); + dynParams.Add("id", id); if (!type.IsInterface) return (await connection.QueryAsync(sql, dynParams, transaction, commandTimeout).ConfigureAwait(false)).FirstOrDefault(); From 5b4badfe67087d7b7ddb96578c5777da616887e9 Mon Sep 17 00:00:00 2001 From: Maarten Geelen Date: Mon, 27 May 2024 11:38:08 +0200 Subject: [PATCH 6/7] Small fix for GetColumnWithNotation: Added an extra '?' because Dapper trims the first one for some reason. --- src/Dapper.Contrib/Adapters.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Dapper.Contrib/Adapters.cs b/src/Dapper.Contrib/Adapters.cs index 4d384a85..0cd383f7 100644 --- a/src/Dapper.Contrib/Adapters.cs +++ b/src/Dapper.Contrib/Adapters.cs @@ -568,12 +568,12 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com } /// - /// Get column with correct notation. + /// Get column with correct notation. Extra '?' because Dapper Trims the first '?' /// /// The column name. public string GetColumnWithNotation(string columnName) { - return String.Format("?{0}?", columnName); + return String.Format("??{0}?", columnName); } /// From ebe908a98a53a6035ae7ef83abef95702f7e301a Mon Sep 17 00:00:00 2001 From: Maarten Geelen Date: Wed, 19 Mar 2025 14:54:04 +0100 Subject: [PATCH 7/7] Fix oledb --- src/Dapper.Contrib/Adapters.cs | 4 ++-- src/Dapper.Contrib/SqlMapperExtensions.cs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Dapper.Contrib/Adapters.cs b/src/Dapper.Contrib/Adapters.cs index 0cd383f7..4d384a85 100644 --- a/src/Dapper.Contrib/Adapters.cs +++ b/src/Dapper.Contrib/Adapters.cs @@ -568,12 +568,12 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com } /// - /// Get column with correct notation. Extra '?' because Dapper Trims the first '?' + /// Get column with correct notation. /// /// The column name. public string GetColumnWithNotation(string columnName) { - return String.Format("??{0}?", columnName); + return String.Format("?{0}?", columnName); } /// diff --git a/src/Dapper.Contrib/SqlMapperExtensions.cs b/src/Dapper.Contrib/SqlMapperExtensions.cs index 51ea7c28..17432f95 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.cs @@ -186,7 +186,9 @@ public static T Get(this IDbConnection connection, dynamic id, IDbTransaction var dynParams = new DynamicParameters(); //sbParameterList.AppendFormat("@{0}", property.Name); - dynParams.Add(idParameter, id); + + //Extra '?' because Dapper Trims the first '?' + dynParams.Add(string.Format("?{0}", idParameter), id); T obj;