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/Adapters.cs b/src/Dapper.Contrib/Adapters.cs new file mode 100644 index 00000000..4d384a85 --- /dev/null +++ b/src/Dapper.Contrib/Adapters.cs @@ -0,0 +1,894 @@ +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(); + + 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; + } + } + + public class Adapters + { + } +} diff --git a/src/Dapper.Contrib/SqlMapperExtensions.Async.cs b/src/Dapper.Contrib/SqlMapperExtensions.Async.cs index c93e39a4..9257378e 100644 --- a/src/Dapper.Contrib/SqlMapperExtensions.Async.cs +++ b/src/Dapper.Contrib/SqlMapperExtensions.Async.cs @@ -24,18 +24,22 @@ public static partial class SqlMapperExtensions /// Entity of T 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 = adapter.GetColumnWithNotation("id"); + 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("id", id); if (!type.IsInterface) return (await connection.QueryAsync(sql, dynParams, transaction, commandTimeout).ConfigureAwait(false)).FirstOrDefault(); @@ -181,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}", property.Name); + sqlAdapter.AppendColumnValue(sbParameterList, property.Name); if (i < allPropertiesExceptKeyAndComputed.Count - 1) sbParameterList.Append(", "); } @@ -342,236 +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); - } -} diff --git a/src/Dapper.Contrib/SqlMapperExtensions.cs b/src/Dapper.Contrib/SqlMapperExtensions.cs index 9a30e805..17432f95 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 { @@ -61,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) @@ -169,19 +171,24 @@ private static PropertyInfo GetSingleKey(string method) /// Entity of T 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 = adapter.GetColumnWithNotation("id"); 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); + + //Extra '?' because Dapper Trims the first '?' + dynParams.Add(string.Format("?{0}", idParameter), id); T obj; @@ -363,7 +370,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); + adapter.AppendColumnValue(sbParameterList, property.Name); if (i < allPropertiesExceptKeyAndComputed.Count - 1) sbParameterList.Append(", "); } @@ -766,390 +773,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); - } -}