Commit f6132344 authored by Nick Craver's avatar Nick Craver

Lots of code cleanup, no functional changes

parent f26967c6
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Dapper; using Dapper;
namespace Dapper.Contrib.Extensions namespace Dapper.Contrib.Extensions
{ {
public static partial class SqlMapperExtensions public static partial class SqlMapperExtensions
...@@ -27,8 +26,7 @@ public static partial class SqlMapperExtensions ...@@ -27,8 +26,7 @@ public static partial class SqlMapperExtensions
public static async Task<T> GetAsync<T>(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class public static async Task<T> GetAsync<T>(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{ {
var type = typeof(T); var type = typeof(T);
string sql; if (!GetQueries.TryGetValue(type.TypeHandle, out string sql))
if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
{ {
var key = GetSingleKey<T>(nameof(GetAsync)); var key = GetSingleKey<T>(nameof(GetAsync));
var name = GetTableName(type); var name = GetTableName(type);
...@@ -77,8 +75,7 @@ public static partial class SqlMapperExtensions ...@@ -77,8 +75,7 @@ public static partial class SqlMapperExtensions
var type = typeof(T); var type = typeof(T);
var cacheType = typeof(List<T>); var cacheType = typeof(List<T>);
string sql; if (!GetQueries.TryGetValue(cacheType.TypeHandle, out string sql))
if (!GetQueries.TryGetValue(cacheType.TypeHandle, out sql))
{ {
GetSingleKey<T>(nameof(GetAll)); GetSingleKey<T>(nameof(GetAll));
var name = GetTableName(type); var name = GetTableName(type);
...@@ -93,6 +90,7 @@ public static partial class SqlMapperExtensions ...@@ -93,6 +90,7 @@ public static partial class SqlMapperExtensions
} }
return GetAllAsyncImpl<T>(connection, transaction, commandTimeout, sql, type); return GetAllAsyncImpl<T>(connection, transaction, commandTimeout, sql, type);
} }
private static async Task<IEnumerable<T>> GetAllAsyncImpl<T>(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string sql, Type type) where T : class private static async Task<IEnumerable<T>> GetAllAsyncImpl<T>(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string sql, Type type) where T : class
{ {
var result = await connection.QueryAsync(sql); var result = await connection.QueryAsync(sql);
...@@ -111,7 +109,6 @@ public static partial class SqlMapperExtensions ...@@ -111,7 +109,6 @@ public static partial class SqlMapperExtensions
return list; return list;
} }
/// <summary> /// <summary>
/// Inserts an entity into table "Ts" asynchronously using .NET 4.5 Task and returns identity id. /// Inserts an entity into table "Ts" asynchronously using .NET 4.5 Task and returns identity id.
/// </summary> /// </summary>
...@@ -125,8 +122,7 @@ public static partial class SqlMapperExtensions ...@@ -125,8 +122,7 @@ public static partial class SqlMapperExtensions
int? commandTimeout = null, ISqlAdapter sqlAdapter = null) where T : class int? commandTimeout = null, ISqlAdapter sqlAdapter = null) where T : class
{ {
var type = typeof(T); var type = typeof(T);
if (sqlAdapter == null) sqlAdapter = sqlAdapter ?? GetFormatter(connection);
sqlAdapter = GetFormatter(connection);
var isList = false; var isList = false;
if (type.IsArray) if (type.IsArray)
...@@ -149,7 +145,7 @@ public static partial class SqlMapperExtensions ...@@ -149,7 +145,7 @@ public static partial class SqlMapperExtensions
for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{ {
var property = allPropertiesExceptKeyAndComputed.ElementAt(i); var property = allPropertiesExceptKeyAndComputed[i];
sqlAdapter.AppendColumnName(sbColumnList, property.Name); sqlAdapter.AppendColumnName(sbColumnList, property.Name);
if (i < allPropertiesExceptKeyAndComputed.Count - 1) if (i < allPropertiesExceptKeyAndComputed.Count - 1)
sbColumnList.Append(", "); sbColumnList.Append(", ");
...@@ -158,7 +154,7 @@ public static partial class SqlMapperExtensions ...@@ -158,7 +154,7 @@ public static partial class SqlMapperExtensions
var sbParameterList = new StringBuilder(null); var sbParameterList = new StringBuilder(null);
for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{ {
var property = allPropertiesExceptKeyAndComputed.ElementAt(i); var property = allPropertiesExceptKeyAndComputed[i];
sbParameterList.AppendFormat("@{0}", property.Name); sbParameterList.AppendFormat("@{0}", property.Name);
if (i < allPropertiesExceptKeyAndComputed.Count - 1) if (i < allPropertiesExceptKeyAndComputed.Count - 1)
sbParameterList.Append(", "); sbParameterList.Append(", ");
...@@ -186,10 +182,9 @@ public static partial class SqlMapperExtensions ...@@ -186,10 +182,9 @@ public static partial class SqlMapperExtensions
/// <returns>true if updated, false if not found or not modified (tracked entities)</returns> /// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
public static async Task<bool> UpdateAsync<T>(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class public static async Task<bool> UpdateAsync<T>(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{ {
var proxy = entityToUpdate as IProxy; if ((entityToUpdate is IProxy proxy) && !proxy.IsDirty)
if (proxy != null)
{ {
if (!proxy.IsDirty) return false; return false;
} }
var type = typeof(T); var type = typeof(T);
...@@ -205,7 +200,7 @@ public static partial class SqlMapperExtensions ...@@ -205,7 +200,7 @@ public static partial class SqlMapperExtensions
var keyProperties = KeyPropertiesCache(type); var keyProperties = KeyPropertiesCache(type);
var explicitKeyProperties = ExplicitKeyPropertiesCache(type); var explicitKeyProperties = ExplicitKeyPropertiesCache(type);
if (!keyProperties.Any() && !explicitKeyProperties.Any()) if (keyProperties.Count == 0 && explicitKeyProperties.Count == 0)
throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property");
var name = GetTableName(type); var name = GetTableName(type);
...@@ -222,7 +217,7 @@ public static partial class SqlMapperExtensions ...@@ -222,7 +217,7 @@ public static partial class SqlMapperExtensions
for (var i = 0; i < nonIdProps.Count; i++) for (var i = 0; i < nonIdProps.Count; i++)
{ {
var property = nonIdProps.ElementAt(i); var property = nonIdProps[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name); adapter.AppendColumnNameEqualsValue(sb, property.Name);
if (i < nonIdProps.Count - 1) if (i < nonIdProps.Count - 1)
sb.AppendFormat(", "); sb.AppendFormat(", ");
...@@ -230,7 +225,7 @@ public static partial class SqlMapperExtensions ...@@ -230,7 +225,7 @@ public static partial class SqlMapperExtensions
sb.Append(" where "); sb.Append(" where ");
for (var i = 0; i < keyProperties.Count; i++) for (var i = 0; i < keyProperties.Count; i++)
{ {
var property = keyProperties.ElementAt(i); var property = keyProperties[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name); adapter.AppendColumnNameEqualsValue(sb, property.Name);
if (i < keyProperties.Count - 1) if (i < keyProperties.Count - 1)
sb.AppendFormat(" and "); sb.AppendFormat(" and ");
...@@ -266,7 +261,7 @@ public static partial class SqlMapperExtensions ...@@ -266,7 +261,7 @@ public static partial class SqlMapperExtensions
var keyProperties = KeyPropertiesCache(type); var keyProperties = KeyPropertiesCache(type);
var explicitKeyProperties = ExplicitKeyPropertiesCache(type); var explicitKeyProperties = ExplicitKeyPropertiesCache(type);
if (!keyProperties.Any() && !explicitKeyProperties.Any()) if (keyProperties.Count == 0 && explicitKeyProperties.Count == 0)
throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property");
var name = GetTableName(type); var name = GetTableName(type);
...@@ -277,7 +272,7 @@ public static partial class SqlMapperExtensions ...@@ -277,7 +272,7 @@ public static partial class SqlMapperExtensions
for (var i = 0; i < keyProperties.Count; i++) for (var i = 0; i < keyProperties.Count; i++)
{ {
var property = keyProperties.ElementAt(i); var property = keyProperties[i];
sb.AppendFormat("{0} = @{1}", property.Name, property.Name); sb.AppendFormat("{0} = @{1}", property.Name, property.Name);
if (i < keyProperties.Count - 1) if (i < keyProperties.Count - 1)
sb.AppendFormat(" AND "); sb.AppendFormat(" AND ");
...@@ -345,9 +340,9 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran ...@@ -345,9 +340,9 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran
var id = (int)first.id; var id = (int)first.id;
var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!pi.Any()) return id; if (pi.Length == 0) return id;
var idp = pi.First(); var idp = pi[0];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
return id; return id;
...@@ -374,13 +369,13 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran ...@@ -374,13 +369,13 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran
await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false);
var r = (await connection.QueryAsync<dynamic>("SELECT @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false)).ToList(); var r = (await connection.QueryAsync<dynamic>("SELECT @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false)).ToList();
if (r.First() == null || r.First().id == null) return 0; if (r[0] == null || r[0].id == null) return 0;
var id = (int)r.First().id; var id = (int)r[0].id;
var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!pi.Any()) return id; if (pi.Length == 0) return id;
var idp = pi.First(); var idp = pi[0];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
return id; return id;
...@@ -411,9 +406,9 @@ public partial class MySqlAdapter ...@@ -411,9 +406,9 @@ public partial class MySqlAdapter
var id = r.First().id; var id = r.First().id;
if (id == null) return 0; if (id == null) return 0;
var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!pi.Any()) return Convert.ToInt32(id); if (pi.Length == 0) return Convert.ToInt32(id);
var idp = pi.First(); var idp = pi[0];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
return Convert.ToInt32(id); return Convert.ToInt32(id);
...@@ -441,8 +436,10 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran ...@@ -441,8 +436,10 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran
// If no primary key then safe to assume a join table with not too much data to return // 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(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!propertyInfos.Any()) if (propertyInfos.Length == 0)
{
sb.Append(" RETURNING *"); sb.Append(" RETURNING *");
}
else else
{ {
sb.Append(" RETURNING "); sb.Append(" RETURNING ");
...@@ -493,9 +490,9 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran ...@@ -493,9 +490,9 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran
var id = (int)multi.Read().First().id; var id = (int)multi.Read().First().id;
var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!pi.Any()) return id; if (pi.Length == 0) return id;
var idp = pi.First(); var idp = pi[0];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
return id; return id;
...@@ -522,14 +519,14 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran ...@@ -522,14 +519,14 @@ public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction tran
await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout); await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout);
var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
var keyName = propertyInfos.First().Name; 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); var r = await connection.QueryAsync($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout);
var id = r.First().ID; var id = r.First().ID;
if (id == null) return 0; if (id == null) return 0;
if (!propertyInfos.Any()) return Convert.ToInt32(id); if (propertyInfos.Length == 0) return Convert.ToInt32(id);
var idp = propertyInfos.First(); var idp = propertyInfos[0];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
return Convert.ToInt32(id); return Convert.ToInt32(id);
......
...@@ -68,18 +68,17 @@ public interface ITableNameMapper ...@@ -68,18 +68,17 @@ public interface ITableNameMapper
private static readonly Dictionary<string, ISqlAdapter> AdapterDictionary private static readonly Dictionary<string, ISqlAdapter> AdapterDictionary
= new Dictionary<string, ISqlAdapter> = new Dictionary<string, ISqlAdapter>
{ {
{"sqlconnection", new SqlServerAdapter()}, ["sqlconnection"] = new SqlServerAdapter(),
{"sqlceconnection", new SqlCeServerAdapter()}, ["sqlceconnection"] = new SqlCeServerAdapter(),
{"npgsqlconnection", new PostgresAdapter()}, ["npgsqlconnection"] = new PostgresAdapter(),
{"sqliteconnection", new SQLiteAdapter()}, ["sqliteconnection"] = new SQLiteAdapter(),
{"mysqlconnection", new MySqlAdapter()}, ["mysqlconnection"] = new MySqlAdapter(),
{"fbconnection", new FbAdapter() } ["fbconnection"] = new FbAdapter()
}; };
private static List<PropertyInfo> ComputedPropertiesCache(Type type) private static List<PropertyInfo> ComputedPropertiesCache(Type type)
{ {
IEnumerable<PropertyInfo> pi; if (ComputedProperties.TryGetValue(type.TypeHandle, out IEnumerable<PropertyInfo> pi))
if (ComputedProperties.TryGetValue(type.TypeHandle, out pi))
{ {
return pi.ToList(); return pi.ToList();
} }
...@@ -92,8 +91,7 @@ private static List<PropertyInfo> ComputedPropertiesCache(Type type) ...@@ -92,8 +91,7 @@ private static List<PropertyInfo> ComputedPropertiesCache(Type type)
private static List<PropertyInfo> ExplicitKeyPropertiesCache(Type type) private static List<PropertyInfo> ExplicitKeyPropertiesCache(Type type)
{ {
IEnumerable<PropertyInfo> pi; if (ExplicitKeyProperties.TryGetValue(type.TypeHandle, out IEnumerable<PropertyInfo> pi))
if (ExplicitKeyProperties.TryGetValue(type.TypeHandle, out pi))
{ {
return pi.ToList(); return pi.ToList();
} }
...@@ -106,18 +104,13 @@ private static List<PropertyInfo> ExplicitKeyPropertiesCache(Type type) ...@@ -106,18 +104,13 @@ private static List<PropertyInfo> ExplicitKeyPropertiesCache(Type type)
private static List<PropertyInfo> KeyPropertiesCache(Type type) private static List<PropertyInfo> KeyPropertiesCache(Type type)
{ {
if (KeyProperties.TryGetValue(type.TypeHandle, out IEnumerable<PropertyInfo> pi))
IEnumerable<PropertyInfo> pi;
if (KeyProperties.TryGetValue(type.TypeHandle, out pi))
{ {
return pi.ToList(); return pi.ToList();
} }
var allProperties = TypePropertiesCache(type); var allProperties = TypePropertiesCache(type);
var keyProperties = allProperties.Where(p => var keyProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute)).ToList();
{
return p.GetCustomAttributes(true).Any(a => a is KeyAttribute);
}).ToList();
if (keyProperties.Count == 0) if (keyProperties.Count == 0)
{ {
...@@ -134,8 +127,7 @@ private static List<PropertyInfo> KeyPropertiesCache(Type type) ...@@ -134,8 +127,7 @@ private static List<PropertyInfo> KeyPropertiesCache(Type type)
private static List<PropertyInfo> TypePropertiesCache(Type type) private static List<PropertyInfo> TypePropertiesCache(Type type)
{ {
IEnumerable<PropertyInfo> pis; if (TypeProperties.TryGetValue(type.TypeHandle, out IEnumerable<PropertyInfo> pis))
if (TypeProperties.TryGetValue(type.TypeHandle, out pis))
{ {
return pis.ToList(); return pis.ToList();
} }
...@@ -165,7 +157,7 @@ private static PropertyInfo GetSingleKey<T>(string method) ...@@ -165,7 +157,7 @@ private static PropertyInfo GetSingleKey<T>(string method)
if (keyCount == 0) if (keyCount == 0)
throw new DataException($"{method}<T> only supports an entity with a [Key] or an [ExplicitKey] property"); throw new DataException($"{method}<T> only supports an entity with a [Key] or an [ExplicitKey] property");
return keys.Any() ? keys.First() : explicitKeys.First(); return keys.Count > 0 ? keys[0] : explicitKeys[0];
} }
/// <summary> /// <summary>
...@@ -184,8 +176,7 @@ private static PropertyInfo GetSingleKey<T>(string method) ...@@ -184,8 +176,7 @@ private static PropertyInfo GetSingleKey<T>(string method)
{ {
var type = typeof(T); var type = typeof(T);
string sql; if (!GetQueries.TryGetValue(type.TypeHandle, out string sql))
if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
{ {
var key = GetSingleKey<T>(nameof(Get)); var key = GetSingleKey<T>(nameof(Get));
var name = GetTableName(type); var name = GetTableName(type);
...@@ -239,8 +230,7 @@ private static PropertyInfo GetSingleKey<T>(string method) ...@@ -239,8 +230,7 @@ private static PropertyInfo GetSingleKey<T>(string method)
var type = typeof(T); var type = typeof(T);
var cacheType = typeof(List<T>); var cacheType = typeof(List<T>);
string sql; if (!GetQueries.TryGetValue(cacheType.TypeHandle, out string sql))
if (!GetQueries.TryGetValue(cacheType.TypeHandle, out sql))
{ {
GetSingleKey<T>(nameof(GetAll)); GetSingleKey<T>(nameof(GetAll));
var name = GetTableName(type); var name = GetTableName(type);
...@@ -274,8 +264,7 @@ private static PropertyInfo GetSingleKey<T>(string method) ...@@ -274,8 +264,7 @@ private static PropertyInfo GetSingleKey<T>(string method)
private static string GetTableName(Type type) private static string GetTableName(Type type)
{ {
string name; if (TypeTableName.TryGetValue(type.TypeHandle, out string name)) return name;
if (TypeTableName.TryGetValue(type.TypeHandle, out name)) return name;
if (TableNameMapper != null) if (TableNameMapper != null)
{ {
...@@ -290,7 +279,9 @@ private static string GetTableName(Type type) ...@@ -290,7 +279,9 @@ private static string GetTableName(Type type)
#endif #endif
.GetCustomAttributes(false).SingleOrDefault(attr => attr.GetType().Name == "TableAttribute") as dynamic; .GetCustomAttributes(false).SingleOrDefault(attr => attr.GetType().Name == "TableAttribute") as dynamic;
if (tableAttr != null) if (tableAttr != null)
{
name = tableAttr.Name; name = tableAttr.Name;
}
else else
{ {
name = type.Name + "s"; name = type.Name + "s";
...@@ -303,7 +294,6 @@ private static string GetTableName(Type type) ...@@ -303,7 +294,6 @@ private static string GetTableName(Type type)
return name; return name;
} }
/// <summary> /// <summary>
/// Inserts an entity into table "Ts" and returns identity id or number if inserted rows if inserting a list. /// Inserts an entity into table "Ts" and returns identity id or number if inserted rows if inserting a list.
/// </summary> /// </summary>
...@@ -340,7 +330,7 @@ private static string GetTableName(Type type) ...@@ -340,7 +330,7 @@ private static string GetTableName(Type type)
for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{ {
var property = allPropertiesExceptKeyAndComputed.ElementAt(i); var property = allPropertiesExceptKeyAndComputed[i];
adapter.AppendColumnName(sbColumnList, property.Name); //fix for issue #336 adapter.AppendColumnName(sbColumnList, property.Name); //fix for issue #336
if (i < allPropertiesExceptKeyAndComputed.Count - 1) if (i < allPropertiesExceptKeyAndComputed.Count - 1)
sbColumnList.Append(", "); sbColumnList.Append(", ");
...@@ -349,7 +339,7 @@ private static string GetTableName(Type type) ...@@ -349,7 +339,7 @@ private static string GetTableName(Type type)
var sbParameterList = new StringBuilder(null); var sbParameterList = new StringBuilder(null);
for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{ {
var property = allPropertiesExceptKeyAndComputed.ElementAt(i); var property = allPropertiesExceptKeyAndComputed[i];
sbParameterList.AppendFormat("@{0}", property.Name); sbParameterList.AppendFormat("@{0}", property.Name);
if (i < allPropertiesExceptKeyAndComputed.Count - 1) if (i < allPropertiesExceptKeyAndComputed.Count - 1)
sbParameterList.Append(", "); sbParameterList.Append(", ");
...@@ -385,10 +375,9 @@ private static string GetTableName(Type type) ...@@ -385,10 +375,9 @@ private static string GetTableName(Type type)
/// <returns>true if updated, false if not found or not modified (tracked entities)</returns> /// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
public static bool Update<T>(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class public static bool Update<T>(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{ {
var proxy = entityToUpdate as IProxy; if (entityToUpdate is IProxy proxy && !proxy.IsDirty)
if (proxy != null)
{ {
if (!proxy.IsDirty) return false; return false;
} }
var type = typeof(T); var type = typeof(T);
...@@ -404,7 +393,7 @@ private static string GetTableName(Type type) ...@@ -404,7 +393,7 @@ private static string GetTableName(Type type)
var keyProperties = KeyPropertiesCache(type).ToList(); //added ToList() due to issue #418, must work on a list copy var keyProperties = KeyPropertiesCache(type).ToList(); //added ToList() due to issue #418, must work on a list copy
var explicitKeyProperties = ExplicitKeyPropertiesCache(type); var explicitKeyProperties = ExplicitKeyPropertiesCache(type);
if (!keyProperties.Any() && !explicitKeyProperties.Any()) if (keyProperties.Count == 0 && explicitKeyProperties.Count == 0)
throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property");
var name = GetTableName(type); var name = GetTableName(type);
...@@ -421,7 +410,7 @@ private static string GetTableName(Type type) ...@@ -421,7 +410,7 @@ private static string GetTableName(Type type)
for (var i = 0; i < nonIdProps.Count; i++) for (var i = 0; i < nonIdProps.Count; i++)
{ {
var property = nonIdProps.ElementAt(i); var property = nonIdProps[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336 adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
if (i < nonIdProps.Count - 1) if (i < nonIdProps.Count - 1)
sb.AppendFormat(", "); sb.AppendFormat(", ");
...@@ -429,7 +418,7 @@ private static string GetTableName(Type type) ...@@ -429,7 +418,7 @@ private static string GetTableName(Type type)
sb.Append(" where "); sb.Append(" where ");
for (var i = 0; i < keyProperties.Count; i++) for (var i = 0; i < keyProperties.Count; i++)
{ {
var property = keyProperties.ElementAt(i); var property = keyProperties[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336 adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
if (i < keyProperties.Count - 1) if (i < keyProperties.Count - 1)
sb.AppendFormat(" and "); sb.AppendFormat(" and ");
...@@ -465,7 +454,7 @@ private static string GetTableName(Type type) ...@@ -465,7 +454,7 @@ private static string GetTableName(Type type)
var keyProperties = KeyPropertiesCache(type).ToList(); //added ToList() due to issue #418, must work on a list copy var keyProperties = KeyPropertiesCache(type).ToList(); //added ToList() due to issue #418, must work on a list copy
var explicitKeyProperties = ExplicitKeyPropertiesCache(type); var explicitKeyProperties = ExplicitKeyPropertiesCache(type);
if (!keyProperties.Any() && !explicitKeyProperties.Any()) if (keyProperties.Count == 0 && explicitKeyProperties.Count == 0)
throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property");
var name = GetTableName(type); var name = GetTableName(type);
...@@ -478,7 +467,7 @@ private static string GetTableName(Type type) ...@@ -478,7 +467,7 @@ private static string GetTableName(Type type)
for (var i = 0; i < keyProperties.Count; i++) for (var i = 0; i < keyProperties.Count; i++)
{ {
var property = keyProperties.ElementAt(i); var property = keyProperties[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336 adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
if (i < keyProperties.Count - 1) if (i < keyProperties.Count - 1)
sb.AppendFormat(" and "); sb.AppendFormat(" and ");
...@@ -520,7 +509,7 @@ private static ISqlAdapter GetFormatter(IDbConnection connection) ...@@ -520,7 +509,7 @@ private static ISqlAdapter GetFormatter(IDbConnection connection)
: AdapterDictionary[name]; : AdapterDictionary[name];
} }
static class ProxyGenerator private static class ProxyGenerator
{ {
private static readonly Dictionary<Type, Type> TypeCache = new Dictionary<Type, Type>(); private static readonly Dictionary<Type, Type> TypeCache = new Dictionary<Type, Type>();
...@@ -537,8 +526,7 @@ public static T GetInterfaceProxy<T>() ...@@ -537,8 +526,7 @@ public static T GetInterfaceProxy<T>()
{ {
Type typeOfT = typeof(T); Type typeOfT = typeof(T);
Type k; if (TypeCache.TryGetValue(typeOfT, out Type k))
if (TypeCache.TryGetValue(typeOfT, out k))
{ {
return (T)Activator.CreateInstance(k); return (T)Activator.CreateInstance(k);
} }
...@@ -572,7 +560,6 @@ public static T GetInterfaceProxy<T>() ...@@ -572,7 +560,6 @@ public static T GetInterfaceProxy<T>()
return (T)Activator.CreateInstance(generatedType); return (T)Activator.CreateInstance(generatedType);
} }
private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder) private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
{ {
var propType = typeof(bool); var propType = typeof(bool);
...@@ -623,8 +610,9 @@ private static void CreateProperty<T>(TypeBuilder typeBuilder, string propertyNa ...@@ -623,8 +610,9 @@ private static void CreateProperty<T>(TypeBuilder typeBuilder, string propertyNa
propType, propType,
new[] { propType }); new[] { propType });
const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.Virtual | const MethodAttributes getSetAttr = MethodAttributes.Public
MethodAttributes.HideBySig; | MethodAttributes.Virtual
| MethodAttributes.HideBySig;
// Define the "get" and "set" accessor methods // Define the "get" and "set" accessor methods
var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName, var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName,
...@@ -799,9 +787,9 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -799,9 +787,9 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
var id = (int)first.id; var id = (int)first.id;
var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!propertyInfos.Any()) return id; if (propertyInfos.Length == 0) return id;
var idProperty = propertyInfos.First(); var idProperty = propertyInfos[0];
idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null);
return id; return id;
...@@ -851,13 +839,13 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -851,13 +839,13 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
connection.Execute(cmd, entityToInsert, transaction, commandTimeout); connection.Execute(cmd, entityToInsert, transaction, commandTimeout);
var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ToList(); var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ToList();
if (r.First().id == null) return 0; if (r[0].id == null) return 0;
var id = (int) r.First().id; var id = (int) r[0].id;
var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!propertyInfos.Any()) return id; if (propertyInfos.Length == 0) return id;
var idProperty = propertyInfos.First(); var idProperty = propertyInfos[0];
idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null);
return id; return id;
...@@ -910,9 +898,9 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -910,9 +898,9 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
var id = r.First().id; var id = r.First().id;
if (id == null) return 0; if (id == null) return 0;
var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!propertyInfos.Any()) return Convert.ToInt32(id); if (propertyInfos.Length == 0) return Convert.ToInt32(id);
var idp = propertyInfos.First(); var idp = propertyInfos[0];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
return Convert.ToInt32(id); return Convert.ToInt32(id);
...@@ -963,8 +951,10 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -963,8 +951,10 @@ 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 // 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(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!propertyInfos.Any()) if (propertyInfos.Length == 0)
{
sb.Append(" RETURNING *"); sb.Append(" RETURNING *");
}
else else
{ {
sb.Append(" RETURNING "); sb.Append(" RETURNING ");
...@@ -984,7 +974,7 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -984,7 +974,7 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
var id = 0; var id = 0;
foreach (var p in propertyInfos) foreach (var p in propertyInfos)
{ {
var value = ((IDictionary<string, object>)results.First())[p.Name.ToLower()]; var value = ((IDictionary<string, object>)results[0])[p.Name.ToLower()];
p.SetValue(entityToInsert, value, null); p.SetValue(entityToInsert, value, null);
if (id == 0) if (id == 0)
id = Convert.ToInt32(value); id = Convert.ToInt32(value);
...@@ -1037,9 +1027,9 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -1037,9 +1027,9 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
var id = (int)multi.Read().First().id; var id = (int)multi.Read().First().id;
var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (!propertyInfos.Any()) return id; if (propertyInfos.Length == 0) return id;
var idProperty = propertyInfos.First(); var idProperty = propertyInfos[0];
idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null);
return id; return id;
...@@ -1089,14 +1079,14 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -1089,14 +1079,14 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
connection.Execute(cmd, entityToInsert, transaction, commandTimeout); connection.Execute(cmd, entityToInsert, transaction, commandTimeout);
var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
var keyName = propertyInfos.First().Name; 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 r = connection.Query($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout);
var id = r.First().ID; var id = r.First().ID;
if (id == null) return 0; if (id == null) return 0;
if (!propertyInfos.Any()) return Convert.ToInt32(id); if (propertyInfos.Length == 0) return Convert.ToInt32(id);
var idp = propertyInfos.First(); var idp = propertyInfos[0];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
return Convert.ToInt32(id); return Convert.ToInt32(id);
......
...@@ -33,8 +33,7 @@ public override void SetValue(IDbDataParameter parameter, DbGeography value) ...@@ -33,8 +33,7 @@ public override void SetValue(IDbDataParameter parameter, DbGeography value)
parsed = SqlGeography.STGeomFromWKB(new SqlBytes(value.AsBinary()), value.CoordinateSystemId); parsed = SqlGeography.STGeomFromWKB(new SqlBytes(value.AsBinary()), value.CoordinateSystemId);
} }
parameter.Value = parsed ?? DBNull.Value; parameter.Value = parsed ?? DBNull.Value;
var sqlParameter = parameter as SqlParameter; if (parameter is SqlParameter sqlParameter)
if (sqlParameter != null)
{ {
sqlParameter.UdtTypeName = "geography"; sqlParameter.UdtTypeName = "geography";
} }
...@@ -47,9 +46,8 @@ public override void SetValue(IDbDataParameter parameter, DbGeography value) ...@@ -47,9 +46,8 @@ public override void SetValue(IDbDataParameter parameter, DbGeography value)
public override DbGeography Parse(object value) public override DbGeography Parse(object value)
{ {
if (value == null || value is DBNull) return null; if (value == null || value is DBNull) return null;
if (value is SqlGeography) if (value is SqlGeography geo)
{ {
var geo = (SqlGeography)value;
return DbGeography.FromBinary(geo.STAsBinary().Value); return DbGeography.FromBinary(geo.STAsBinary().Value);
} }
return DbGeography.FromText(value.ToString()); return DbGeography.FromText(value.ToString());
......
...@@ -46,9 +46,8 @@ public override void SetValue(IDbDataParameter parameter, DbGeometry value) ...@@ -46,9 +46,8 @@ public override void SetValue(IDbDataParameter parameter, DbGeometry value)
public override DbGeometry Parse(object value) public override DbGeometry Parse(object value)
{ {
if (value == null || value is DBNull) return null; if (value == null || value is DBNull) return null;
if (value is SqlGeometry) if (value is SqlGeometry geo)
{ {
var geo = (SqlGeometry)value;
return DbGeometry.FromBinary(geo.STAsBinary().Value); return DbGeometry.FromBinary(geo.STAsBinary().Value);
} }
return DbGeometry.FromText(value.ToString()); return DbGeometry.FromText(value.ToString());
......
...@@ -131,21 +131,19 @@ public IEnumerable<T> All() ...@@ -131,21 +131,19 @@ public IEnumerable<T> All()
internal static List<string> GetParamNames(object o) internal static List<string> GetParamNames(object o)
{ {
var parameters = o as DynamicParameters; if (o is DynamicParameters parameters)
if (parameters != null)
{ {
return parameters.ParameterNames.ToList(); return parameters.ParameterNames.ToList();
} }
List<string> paramNames; if (!paramNameCache.TryGetValue(o.GetType(), out List<string> paramNames))
if (!paramNameCache.TryGetValue(o.GetType(), out paramNames))
{ {
paramNames = new List<string>(); paramNames = new List<string>();
foreach (var prop in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.GetGetMethod(false) != null)) foreach (var prop in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.GetGetMethod(false) != null))
{ {
var attribs = prop.GetCustomAttributes(typeof(IgnorePropertyAttribute), true); var attribs = prop.GetCustomAttributes(typeof(IgnorePropertyAttribute), true);
var attr = attribs.FirstOrDefault() as IgnorePropertyAttribute; var attr = attribs.FirstOrDefault() as IgnorePropertyAttribute;
if (attr==null || (!attr.Value)) if (attr == null || (!attr.Value))
{ {
paramNames.Add(prop.Name); paramNames.Add(prop.Name);
} }
...@@ -196,10 +194,7 @@ internal void InitDatabase(DbConnection connection, int commandTimeout) ...@@ -196,10 +194,7 @@ internal void InitDatabase(DbConnection connection, int commandTimeout)
{ {
_connection = connection; _connection = connection;
_commandTimeout = commandTimeout; _commandTimeout = commandTimeout;
if (tableConstructor == null) tableConstructor = tableConstructor ?? CreateTableConstructorForTable();
{
tableConstructor = CreateTableConstructorForTable();
}
tableConstructor(this as TDatabase); tableConstructor(this as TDatabase);
} }
...@@ -297,12 +292,10 @@ protected Action<TDatabase> CreateTableConstructor(params Type[] tableTypes) ...@@ -297,12 +292,10 @@ protected Action<TDatabase> CreateTableConstructor(params Type[] tableTypes)
return (Action<TDatabase>)dm.CreateDelegate(typeof(Action<TDatabase>)); return (Action<TDatabase>)dm.CreateDelegate(typeof(Action<TDatabase>));
} }
private static ConcurrentDictionary<Type, string> tableNameMap = new ConcurrentDictionary<Type, string>(); private static readonly ConcurrentDictionary<Type, string> tableNameMap = new ConcurrentDictionary<Type, string>();
private string DetermineTableName<T>(string likelyTableName) private string DetermineTableName<T>(string likelyTableName)
{ {
string name; if (!tableNameMap.TryGetValue(typeof(T), out string name))
if (!tableNameMap.TryGetValue(typeof(T), out name))
{ {
name = likelyTableName; name = likelyTableName;
if (!TableExists(name)) if (!TableExists(name))
...@@ -345,10 +338,8 @@ private bool TableExists(string name) ...@@ -345,10 +338,8 @@ private bool TableExists(string name)
/// <param name="sql">The SQL to execute.</param> /// <param name="sql">The SQL to execute.</param>
/// <param name="param">The parameters to use.</param> /// <param name="param">The parameters to use.</param>
/// <returns>The number of rows affected.</returns> /// <returns>The number of rows affected.</returns>
public int Execute(string sql, dynamic param = null) public int Execute(string sql, dynamic param = null) =>
{ _connection.Execute(sql, param as object, _transaction, _commandTimeout);
return _connection.Execute(sql, param as object, _transaction, _commandTimeout);
}
/// <summary> /// <summary>
/// Queries the current database. /// Queries the current database.
...@@ -358,10 +349,8 @@ public int Execute(string sql, dynamic param = null) ...@@ -358,10 +349,8 @@ public int Execute(string sql, dynamic param = null)
/// <param name="param">The parameters to use.</param> /// <param name="param">The parameters to use.</param>
/// <param name="buffered">Whether to buffer the results.</param> /// <param name="buffered">Whether to buffer the results.</param>
/// <returns>An enumerable of <typeparamref name="T"/> for the rows fetched.</returns> /// <returns>An enumerable of <typeparamref name="T"/> for the rows fetched.</returns>
public IEnumerable<T> Query<T>(string sql, dynamic param = null, bool buffered = true) public IEnumerable<T> Query<T>(string sql, dynamic param = null, bool buffered = true) =>
{ _connection.Query<T>(sql, param as object, _transaction, buffered, _commandTimeout);
return _connection.Query<T>(sql, param as object, _transaction, buffered, _commandTimeout);
}
/// <summary> /// <summary>
/// Queries the current database for a single record. /// Queries the current database for a single record.
...@@ -370,42 +359,32 @@ public IEnumerable<T> Query<T>(string sql, dynamic param = null, bool buffered = ...@@ -370,42 +359,32 @@ public IEnumerable<T> Query<T>(string sql, dynamic param = null, bool buffered =
/// <param name="sql">The SQL to execute.</param> /// <param name="sql">The SQL to execute.</param>
/// <param name="param">The parameters to use.</param> /// <param name="param">The parameters to use.</param>
/// <returns>An enumerable of <typeparamref name="T"/> for the rows fetched.</returns> /// <returns>An enumerable of <typeparamref name="T"/> for the rows fetched.</returns>
public T QueryFirstOrDefault<T>(string sql, dynamic param = null) public T QueryFirstOrDefault<T>(string sql, dynamic param = null) =>
{ _connection.QueryFirstOrDefault<T>(sql, param as object, _transaction, _commandTimeout);
return _connection.QueryFirstOrDefault<T>(sql, param as object, _transaction, _commandTimeout);
}
/// <summary> /// <summary>
/// Perform a multi mapping query with 2 input parameters /// Perform a multi mapping query with 2 input parameters
/// </summary> /// </summary>
public IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(string sql, Func<TFirst, TSecond, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null) public IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(string sql, Func<TFirst, TSecond, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null) =>
{ _connection.Query(sql, map, param as object, transaction, buffered, splitOn, commandTimeout);
return _connection.Query(sql, map, param as object, transaction, buffered, splitOn, commandTimeout);
}
/// <summary> /// <summary>
/// Perform a multi mapping query with 3 input parameters /// Perform a multi mapping query with 3 input parameters
/// </summary> /// </summary>
public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(string sql, Func<TFirst, TSecond, TThird, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null) public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(string sql, Func<TFirst, TSecond, TThird, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null) =>
{ _connection.Query(sql, map, param as object, transaction, buffered, splitOn, commandTimeout);
return _connection.Query(sql, map, param as object, transaction, buffered, splitOn, commandTimeout);
}
/// <summary> /// <summary>
/// Perform a multi mapping query with 4 input parameters /// Perform a multi mapping query with 4 input parameters
/// </summary> /// </summary>
public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null) public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null) =>
{ _connection.Query(sql, map, param as object, transaction, buffered, splitOn, commandTimeout);
return _connection.Query(sql, map, param as object, transaction, buffered, splitOn, commandTimeout);
}
/// <summary> /// <summary>
/// Perform a multi mapping query with 5 input parameters /// Perform a multi mapping query with 5 input parameters
/// </summary> /// </summary>
public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null) public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null) =>
{ _connection.Query(sql, map, param as object, transaction, buffered, splitOn, commandTimeout);
return _connection.Query(sql, map, param as object, transaction, buffered, splitOn, commandTimeout);
}
/// <summary> /// <summary>
/// Return a sequence of dynamic objects with properties matching the columns /// Return a sequence of dynamic objects with properties matching the columns
...@@ -414,18 +393,14 @@ public T QueryFirstOrDefault<T>(string sql, dynamic param = null) ...@@ -414,18 +393,14 @@ public T QueryFirstOrDefault<T>(string sql, dynamic param = null)
/// <param name="param">The parameters to use.</param> /// <param name="param">The parameters to use.</param>
/// <param name="buffered">Whether the results should be buffered in memory.</param> /// <param name="buffered">Whether the results should be buffered in memory.</param>
/// <remarks>Note: each row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks> /// <remarks>Note: each row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks>
public IEnumerable<dynamic> Query(string sql, dynamic param = null, bool buffered = true) public IEnumerable<dynamic> Query(string sql, dynamic param = null, bool buffered = true) =>
{ _connection.Query(sql, param as object, _transaction, buffered);
return _connection.Query(sql, param as object, _transaction, buffered);
}
/// <summary> /// <summary>
/// Execute a command that returns multiple result sets, and access each in turn /// Execute a command that returns multiple result sets, and access each in turn
/// </summary> /// </summary>
public SqlMapper.GridReader QueryMultiple(string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) public SqlMapper.GridReader QueryMultiple(string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
{ SqlMapper.QueryMultiple(_connection, sql, param, transaction, commandTimeout, commandType);
return SqlMapper.QueryMultiple(_connection, sql, param, transaction, commandTimeout, commandType);
}
/// <summary> /// <summary>
/// Disposes the current database, rolling back current transactions. /// Disposes the current database, rolling back current transactions.
......
...@@ -84,15 +84,15 @@ private static DynamicParameters Diff(T original, T current) ...@@ -84,15 +84,15 @@ private static DynamicParameters Diff(T original, T current)
return dm; return dm;
} }
static List<PropertyInfo> RelevantProperties() private static List<PropertyInfo> RelevantProperties()
{ {
return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(p => .Where(p =>
p.GetSetMethod(true) != null && p.GetSetMethod(true) != null
p.GetGetMethod(true) != null && && p.GetGetMethod(true) != null
(p.PropertyType == typeof(string) || && (p.PropertyType == typeof(string)
p.PropertyType.IsValueType() || || p.PropertyType.IsValueType()
(p.PropertyType.IsGenericType() && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))) || (p.PropertyType.IsGenericType() && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
).ToList(); ).ToList();
} }
...@@ -187,7 +187,6 @@ private static bool AreEqual<U>(U first, U second) ...@@ -187,7 +187,6 @@ private static bool AreEqual<U>(U first, U second)
return (Func<T, T, List<Change>>)dm.CreateDelegate(typeof(Func<T, T, List<Change>>)); return (Func<T, T, List<Change>>)dm.CreateDelegate(typeof(Func<T, T, List<Change>>));
} }
// adapted from https://stackoverflow.com/a/966466/17174 // adapted from https://stackoverflow.com/a/966466/17174
private static Func<T, T> GenerateCloner() private static Func<T, T> GenerateCloner()
{ {
......
...@@ -9,18 +9,16 @@ public class SqlBuilder ...@@ -9,18 +9,16 @@ public class SqlBuilder
private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>(); private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>();
private int _seq; private int _seq;
class Clause private class Clause
{ {
public string Sql { get; set; } public string Sql { get; set; }
public object Parameters { get; set; } public object Parameters { get; set; }
public bool IsInclusive { get; set; } public bool IsInclusive { get; set; }
} }
class Clauses : List<Clause> private class Clauses : List<Clause>
{ {
private readonly string _joiner; private readonly string _joiner, _prefix, _postfix;
private readonly string _prefix;
private readonly string _postfix;
public Clauses(string joiner, string prefix = "", string postfix = "") public Clauses(string joiner, string prefix = "", string postfix = "")
{ {
...@@ -66,11 +64,11 @@ public Template(SqlBuilder builder, string sql, dynamic parameters) ...@@ -66,11 +64,11 @@ public Template(SqlBuilder builder, string sql, dynamic parameters)
private static readonly Regex _regex = new Regex(@"\/\*\*.+?\*\*\/", RegexOptions.Compiled | RegexOptions.Multiline); private static readonly Regex _regex = new Regex(@"\/\*\*.+?\*\*\/", RegexOptions.Compiled | RegexOptions.Multiline);
void ResolveSql() private void ResolveSql()
{ {
if (_dataSeq != _builder._seq) if (_dataSeq != _builder._seq)
{ {
DynamicParameters p = new DynamicParameters(_initParams); var p = new DynamicParameters(_initParams);
rawSql = _sql; rawSql = _sql;
...@@ -87,100 +85,69 @@ void ResolveSql() ...@@ -87,100 +85,69 @@ void ResolveSql()
} }
} }
string rawSql; private string rawSql;
object parameters; private object parameters;
public string RawSql { get { ResolveSql(); return rawSql; } } public string RawSql
public object Parameters { get { ResolveSql(); return parameters; } } {
get { ResolveSql(); return rawSql; }
} }
public Template AddTemplate(string sql, dynamic parameters = null) public object Parameters
{ {
return new Template(this, sql, parameters); get { ResolveSql(); return parameters; }
}
} }
protected void AddClause(string name, string sql, object parameters, string joiner, string prefix = "", string postfix = "", bool isInclusive = false) public Template AddTemplate(string sql, dynamic parameters = null) =>
new Template(this, sql, parameters);
protected SqlBuilder AddClause(string name, string sql, object parameters, string joiner, string prefix = "", string postfix = "", bool isInclusive = false)
{ {
Clauses clauses; if (!_data.TryGetValue(name, out Clauses clauses))
if (!_data.TryGetValue(name, out clauses))
{ {
clauses = new Clauses(joiner, prefix, postfix); clauses = new Clauses(joiner, prefix, postfix);
_data[name] = clauses; _data[name] = clauses;
} }
clauses.Add(new Clause { Sql = sql, Parameters = parameters, IsInclusive = isInclusive }); clauses.Add(new Clause { Sql = sql, Parameters = parameters, IsInclusive = isInclusive });
_seq++; _seq++;
return this;
} }
public SqlBuilder Intersect(string sql, dynamic parameters = null) public SqlBuilder Intersect(string sql, dynamic parameters = null) =>
{
AddClause("intersect", sql, parameters, "\nINTERSECT\n ", "\n ", "\n", false); AddClause("intersect", sql, parameters, "\nINTERSECT\n ", "\n ", "\n", false);
return this;
}
public SqlBuilder InnerJoin(string sql, dynamic parameters = null) public SqlBuilder InnerJoin(string sql, dynamic parameters = null) =>
{
AddClause("innerjoin", sql, parameters, "\nINNER JOIN ", "\nINNER JOIN ", "\n", false); AddClause("innerjoin", sql, parameters, "\nINNER JOIN ", "\nINNER JOIN ", "\n", false);
return this;
}
public SqlBuilder LeftJoin(string sql, dynamic parameters = null) public SqlBuilder LeftJoin(string sql, dynamic parameters = null) =>
{
AddClause("leftjoin", sql, parameters, "\nLEFT JOIN ", "\nLEFT JOIN ", "\n", false); AddClause("leftjoin", sql, parameters, "\nLEFT JOIN ", "\nLEFT JOIN ", "\n", false);
return this;
}
public SqlBuilder RightJoin(string sql, dynamic parameters = null) public SqlBuilder RightJoin(string sql, dynamic parameters = null) =>
{
AddClause("rightjoin", sql, parameters, "\nRIGHT JOIN ", "\nRIGHT JOIN ", "\n", false); AddClause("rightjoin", sql, parameters, "\nRIGHT JOIN ", "\nRIGHT JOIN ", "\n", false);
return this;
}
public SqlBuilder Where(string sql, dynamic parameters = null) public SqlBuilder Where(string sql, dynamic parameters = null) =>
{
AddClause("where", sql, parameters, " AND ", "WHERE ", "\n", false); AddClause("where", sql, parameters, " AND ", "WHERE ", "\n", false);
return this;
}
public SqlBuilder OrWhere(string sql, dynamic parameters = null) public SqlBuilder OrWhere(string sql, dynamic parameters = null) =>
{
AddClause("where", sql, parameters, " OR ", "WHERE ", "\n", true); AddClause("where", sql, parameters, " OR ", "WHERE ", "\n", true);
return this;
}
public SqlBuilder OrderBy(string sql, dynamic parameters = null) public SqlBuilder OrderBy(string sql, dynamic parameters = null) =>
{
AddClause("orderby", sql, parameters, " , ", "ORDER BY ", "\n", false); AddClause("orderby", sql, parameters, " , ", "ORDER BY ", "\n", false);
return this;
}
public SqlBuilder Select(string sql, dynamic parameters = null) public SqlBuilder Select(string sql, dynamic parameters = null) =>
{
AddClause("select", sql, parameters, " , ", "", "\n", false); AddClause("select", sql, parameters, " , ", "", "\n", false);
return this;
}
public SqlBuilder AddParameters(dynamic parameters) public SqlBuilder AddParameters(dynamic parameters) =>
{
AddClause("--parameters", "", parameters, "", "", "", false); AddClause("--parameters", "", parameters, "", "", "", false);
return this;
}
public SqlBuilder Join(string sql, dynamic parameters = null) public SqlBuilder Join(string sql, dynamic parameters = null) =>
{
AddClause("join", sql, parameters, "\nJOIN ", "\nJOIN ", "\n", false); AddClause("join", sql, parameters, "\nJOIN ", "\nJOIN ", "\n", false);
return this;
}
public SqlBuilder GroupBy(string sql, dynamic parameters = null) public SqlBuilder GroupBy(string sql, dynamic parameters = null) =>
{
AddClause("groupby", sql, parameters, " , ", "\nGROUP BY ", "\n", false); AddClause("groupby", sql, parameters, " , ", "\nGROUP BY ", "\n", false);
return this;
}
public SqlBuilder Having(string sql, dynamic parameters = null) public SqlBuilder Having(string sql, dynamic parameters = null) =>
{
AddClause("having", sql, parameters, "\nAND ", "HAVING ", "\n", false); AddClause("having", sql, parameters, "\nAND ", "HAVING ", "\n", false);
return this;
}
} }
} }
...@@ -227,7 +227,7 @@ public void NullDateTime() ...@@ -227,7 +227,7 @@ public void NullDateTime()
connection.Insert(new Stuff { Name = "First item" }); connection.Insert(new Stuff { Name = "First item" });
connection.Insert(new Stuff { Name = "Second item", Created = DateTime.Now }); connection.Insert(new Stuff { Name = "Second item", Created = DateTime.Now });
var stuff = connection.Query<Stuff>("select * from Stuff").ToList(); var stuff = connection.Query<Stuff>("select * from Stuff").ToList();
stuff.First().Created.IsNull(); stuff[0].Created.IsNull();
stuff.Last().Created.IsNotNull(); stuff.Last().Created.IsNotNull();
} }
} }
......
...@@ -68,6 +68,7 @@ public static List<dynamic> ToExpandoList(this IDataReader rdr) ...@@ -68,6 +68,7 @@ public static List<dynamic> ToExpandoList(this IDataReader rdr)
} }
return result; return result;
} }
public static dynamic RecordToExpando(this IDataReader rdr) public static dynamic RecordToExpando(this IDataReader rdr)
{ {
dynamic e = new ExpandoObject(); dynamic e = new ExpandoObject();
...@@ -112,9 +113,9 @@ public static dynamic ToExpando(this object o) ...@@ -112,9 +113,9 @@ public static dynamic ToExpando(this object o)
/// </summary> /// </summary>
public class DynamicModel public class DynamicModel
{ {
DbProviderFactory _factory; private readonly DbProviderFactory _factory;
#pragma warning disable 0649 #pragma warning disable 0649
string _connectionString; private string _connectionString;
#pragma warning restore 0649 #pragma warning restore 0649
public DynamicModel(string connectionStringName = "", string tableName = "", string primaryKeyField = "") public DynamicModel(string connectionStringName = "", string tableName = "", string primaryKeyField = "")
...@@ -149,20 +150,20 @@ public virtual IEnumerable<dynamic> Query(string sql, params object[] args) ...@@ -149,20 +150,20 @@ public virtual IEnumerable<dynamic> Query(string sql, params object[] args)
var rdr = CreateCommand(sql, conn, args).ExecuteReader(); var rdr = CreateCommand(sql, conn, args).ExecuteReader();
while (rdr.Read()) while (rdr.Read())
{ {
yield return rdr.RecordToExpando(); ; yield return rdr.RecordToExpando();
} }
} }
} }
public virtual IEnumerable<dynamic> Query(string sql, DbConnection connection, params object[] args) public virtual IEnumerable<dynamic> Query(string sql, DbConnection connection, params object[] args)
{ {
using (var rdr = CreateCommand(sql, connection, args).ExecuteReader()) using (var rdr = CreateCommand(sql, connection, args).ExecuteReader())
{ {
while (rdr.Read()) while (rdr.Read())
{ {
yield return rdr.RecordToExpando(); ; yield return rdr.RecordToExpando();
} }
} }
} }
/// <summary> /// <summary>
/// Returns a single result /// Returns a single result
...@@ -179,7 +180,7 @@ public virtual object Scalar(string sql, params object[] args) ...@@ -179,7 +180,7 @@ public virtual object Scalar(string sql, params object[] args)
/// <summary> /// <summary>
/// Creates a DBCommand that you can use for loving your database. /// Creates a DBCommand that you can use for loving your database.
/// </summary> /// </summary>
DbCommand CreateCommand(string sql, DbConnection conn, params object[] args) private DbCommand CreateCommand(string sql, DbConnection conn, params object[] args)
{ {
var result = _factory.CreateCommand(); var result = _factory.CreateCommand();
result.Connection = conn; result.Connection = conn;
...@@ -230,6 +231,7 @@ public virtual int Save(params object[] things) ...@@ -230,6 +231,7 @@ public virtual int Save(params object[] things)
var commands = BuildCommands(things); var commands = BuildCommands(things);
return Execute(commands); return Execute(commands);
} }
public virtual int Execute(DbCommand command) public virtual int Execute(DbCommand command)
{ {
return Execute(new DbCommand[] { command }); return Execute(new DbCommand[] { command });
...@@ -255,6 +257,7 @@ public virtual int Execute(IEnumerable<DbCommand> commands) ...@@ -255,6 +257,7 @@ public virtual int Execute(IEnumerable<DbCommand> commands)
} }
return result; return result;
} }
public virtual string PrimaryKeyField { get; set; } public virtual string PrimaryKeyField { get; set; }
/// <summary> /// <summary>
/// Conventionally introspects the object passed in for a field that /// Conventionally introspects the object passed in for a field that
...@@ -270,10 +273,10 @@ public virtual bool HasPrimaryKey(object o) ...@@ -270,10 +273,10 @@ public virtual bool HasPrimaryKey(object o)
/// </summary> /// </summary>
public virtual object GetPrimaryKey(object o) public virtual object GetPrimaryKey(object o)
{ {
object result = null; o.ToDictionary().TryGetValue(PrimaryKeyField, out object result);
o.ToDictionary().TryGetValue(PrimaryKeyField, out result);
return result; return result;
} }
public virtual string TableName { get; set; } public virtual string TableName { get; set; }
/// <summary> /// <summary>
/// Creates a command for use with transactions - internal stuff mostly, but here for you to play with /// Creates a command for use with transactions - internal stuff mostly, but here for you to play with
...@@ -285,7 +288,7 @@ public virtual DbCommand CreateInsertCommand(object o) ...@@ -285,7 +288,7 @@ public virtual DbCommand CreateInsertCommand(object o)
var settings = (IDictionary<string, object>)expando; var settings = (IDictionary<string, object>)expando;
var sbKeys = new StringBuilder(); var sbKeys = new StringBuilder();
var sbVals = new StringBuilder(); var sbVals = new StringBuilder();
var stub = "INSERT INTO {0} ({1}) \r\n VALUES ({2})"; const string stub = "INSERT INTO {0} ({1}) \r\n VALUES ({2})";
result = CreateCommand(stub, null); result = CreateCommand(stub, null);
int counter = 0; int counter = 0;
foreach (var item in settings) foreach (var item in settings)
...@@ -299,10 +302,13 @@ public virtual DbCommand CreateInsertCommand(object o) ...@@ -299,10 +302,13 @@ public virtual DbCommand CreateInsertCommand(object o)
{ {
var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 1); var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 1);
var vals = sbVals.ToString().Substring(0, sbVals.Length - 1); var vals = sbVals.ToString().Substring(0, sbVals.Length - 1);
var sql = string.Format(stub, TableName, keys, vals); result.CommandText = string.Format(stub, TableName, keys, vals);
result.CommandText = sql;
} }
else throw new InvalidOperationException("Can't parse this object to the database - there are no properties set"); else
{
throw new InvalidOperationException("Can't parse this object to the database - there are no properties set");
}
return result; return result;
} }
/// <summary> /// <summary>
...@@ -313,7 +319,7 @@ public virtual DbCommand CreateUpdateCommand(object o, object key) ...@@ -313,7 +319,7 @@ public virtual DbCommand CreateUpdateCommand(object o, object key)
var expando = o.ToExpando(); var expando = o.ToExpando();
var settings = (IDictionary<string, object>)expando; var settings = (IDictionary<string, object>)expando;
var sbKeys = new StringBuilder(); var sbKeys = new StringBuilder();
var stub = "UPDATE {0} SET {1} WHERE {2} = @{3}"; const string stub = "UPDATE {0} SET {1} WHERE {2} = @{3}";
var args = new List<object>(); var args = new List<object>();
var result = CreateCommand(stub, null); var result = CreateCommand(stub, null);
int counter = 0; int counter = 0;
...@@ -335,7 +341,11 @@ public virtual DbCommand CreateUpdateCommand(object o, object key) ...@@ -335,7 +341,11 @@ public virtual DbCommand CreateUpdateCommand(object o, object key)
var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 4); var keys = sbKeys.ToString().Substring(0, sbKeys.Length - 4);
result.CommandText = string.Format(stub, TableName, keys, PrimaryKeyField, counter); result.CommandText = string.Format(stub, TableName, keys, PrimaryKeyField, counter);
} }
else throw new InvalidOperationException("No parsable object was sent in - could not divine any name/value pairs"); else
{
throw new InvalidOperationException("No parsable object was sent in - could not divine any name/value pairs");
}
return result; return result;
} }
/// <summary> /// <summary>
...@@ -420,7 +430,7 @@ public virtual dynamic Paged(string where = "", string orderBy = "", string colu ...@@ -420,7 +430,7 @@ public virtual dynamic Paged(string where = "", string orderBy = "", string colu
} }
var sql = string.Format("SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {2}) AS Row, {0} FROM {3} {4}) AS Paged ", columns, pageSize, orderBy, TableName, where); var sql = string.Format("SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {2}) AS Row, {0} FROM {3} {4}) AS Paged ", columns, pageSize, orderBy, TableName, where);
var pageStart = (currentPage - 1) * pageSize; var pageStart = (currentPage - 1) * pageSize;
sql += string.Format(" WHERE Row >={0} AND Row <={1}", pageStart, (pageStart + pageSize)); sql += string.Format(" WHERE Row >={0} AND Row <={1}", pageStart, pageStart + pageSize);
countSQL += where; countSQL += where;
result.TotalRecords = Scalar(countSQL, args); result.TotalRecords = Scalar(countSQL, args);
result.TotalPages = result.TotalRecords / pageSize; result.TotalPages = result.TotalRecords / pageSize;
......
...@@ -50,6 +50,7 @@ public void Add(Action<int> iteration, string name) ...@@ -50,6 +50,7 @@ public void Add(Action<int> iteration, string name)
{ {
Add(new Test(iteration, name)); Add(new Test(iteration, name));
} }
public void AddAsync(Func<int, Task> iterationAsync, string name) public void AddAsync(Func<int, Task> iterationAsync, string name)
{ {
Add(new Test(iterationAsync, name)); Add(new Test(iterationAsync, name));
...@@ -156,7 +157,6 @@ public async Task RunAsync(int iterations) ...@@ -156,7 +157,6 @@ public async Task RunAsync(int iterations)
tests.Add(id => mapperConnection.Query<Post>("select * from Posts where Id = @Id", new { Id = id }, buffered: false).First(), "Dapper: Query (non-buffered)"); tests.Add(id => mapperConnection.Query<Post>("select * from Posts where Id = @Id", new { Id = id }, buffered: false).First(), "Dapper: Query (non-buffered)");
tests.Add(id => mapperConnection.QueryFirstOrDefault<Post>("select * from Posts where Id = @Id", new { Id = id }), "Dapper: QueryFirstOrDefault"); tests.Add(id => mapperConnection.QueryFirstOrDefault<Post>("select * from Posts where Id = @Id", new { Id = id }), "Dapper: QueryFirstOrDefault");
var mapperConnection2 = GetOpenConnection(); var mapperConnection2 = GetOpenConnection();
tests.Add(id => mapperConnection2.Query("select * from Posts where Id = @Id", new { Id = id }, buffered: true).First(), "Dapper: Dynamic Query (buffered)"); tests.Add(id => mapperConnection2.Query("select * from Posts where Id = @Id", new { Id = id }, buffered: true).First(), "Dapper: Dynamic Query (buffered)");
tests.Add(id => mapperConnection2.Query("select * from Posts where Id = @Id", new { Id = id }, buffered: false).First(), "Dapper: Dynamic Query (non-buffered)"); tests.Add(id => mapperConnection2.Query("select * from Posts where Id = @Id", new { Id = id }, buffered: false).First(), "Dapper: Dynamic Query (non-buffered)");
...@@ -291,10 +291,12 @@ public async Task RunAsync(int iterations) ...@@ -291,10 +291,12 @@ public async Task RunAsync(int iterations)
}, "ServiceStack.OrmLite"); }, "ServiceStack.OrmLite");
// Hand Coded // Hand Coded
var postCommand = new SqlCommand(); var postCommand = new SqlCommand()
postCommand.Connection = connection; {
postCommand.CommandText = @"select Id, [Text], [CreationDate], LastChangeDate, Connection = connection,
Counter1,Counter2,Counter3,Counter4,Counter5,Counter6,Counter7,Counter8,Counter9 from Posts where Id = @Id"; CommandText = @"select Id, [Text], [CreationDate], LastChangeDate,
Counter1,Counter2,Counter3,Counter4,Counter5,Counter6,Counter7,Counter8,Counter9 from Posts where Id = @Id"
};
var idParam = postCommand.Parameters.Add("@Id", SqlDbType.Int); var idParam = postCommand.Parameters.Add("@Id", SqlDbType.Int);
tests.Add(id => tests.Add(id =>
...@@ -337,7 +339,6 @@ public async Task RunAsync(int iterations) ...@@ -337,7 +339,6 @@ public async Task RunAsync(int iterations)
//var db1 = new DbManager(GetOpenConnection()); //var db1 = new DbManager(GetOpenConnection());
//tests.Add(id => db1.SetCommand("select * from Posts where Id = @id", db1.Parameter("id", id)).ExecuteList<Post>(), "BLToolkit"); //tests.Add(id => db1.SetCommand("select * from Posts where Id = @id", db1.Parameter("id", id)).ExecuteList<Post>(), "BLToolkit");
#if !COREFX #if !COREFX
var table = new DataTable var table = new DataTable
{ {
......
...@@ -48,7 +48,8 @@ public TableName(string tableName) ...@@ -48,7 +48,8 @@ public TableName(string tableName)
{ {
Value = tableName; Value = tableName;
} }
public string Value { get; private set; }
public string Value { get; }
} }
// Specific the primary key of a poco class // Specific the primary key of a poco class
...@@ -60,7 +61,7 @@ public PrimaryKey(string primaryKey) ...@@ -60,7 +61,7 @@ public PrimaryKey(string primaryKey)
Value = primaryKey; Value = primaryKey;
} }
public string Value { get; private set; } public string Value { get; }
} }
// Results from paged request // Results from paged request
...@@ -102,7 +103,7 @@ public Database(string connectionString, string providerName) ...@@ -102,7 +103,7 @@ public Database(string connectionString, string providerName)
public Database(string connectionStringName) public Database(string connectionStringName)
{ {
// Use first? // Use first?
if (connectionStringName == "") if (connectionStringName == string.Empty)
connectionStringName = ConfigurationManager.ConnectionStrings[0].Name; connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
// Work out connection string and provider name // Work out connection string and provider name
...@@ -123,6 +124,8 @@ public Database(string connectionStringName) ...@@ -123,6 +124,8 @@ public Database(string connectionStringName)
CommonConstruct(); CommonConstruct();
} }
private
// Common initialization // Common initialization
void CommonConstruct() void CommonConstruct()
{ {
...@@ -134,7 +137,7 @@ void CommonConstruct() ...@@ -134,7 +137,7 @@ void CommonConstruct()
if (_providerName != null) if (_providerName != null)
_factory = DbProviderFactories.GetFactory(_providerName); _factory = DbProviderFactories.GetFactory(_providerName);
if (_connectionString != null && _connectionString.IndexOf("Allow User Variables=true") >= 0 && IsMySql()) if (_connectionString?.IndexOf("Allow User Variables=true") >= 0 && IsMySql())
_paramPrefix = "?"; _paramPrefix = "?";
} }
...@@ -146,8 +149,8 @@ public void Dispose() ...@@ -146,8 +149,8 @@ public void Dispose()
} }
// Who are we talking too? // Who are we talking too?
bool IsMySql() { return string.Compare(_providerName, "MySql.Data.MySqlClient", true) == 0; } private bool IsMySql() { return string.Compare(_providerName, "MySql.Data.MySqlClient", true) == 0; }
bool IsSqlServer() { return string.Compare(_providerName, "System.Data.SqlClient", true) == 0; } private bool IsSqlServer() { return string.Compare(_providerName, "System.Data.SqlClient", true) == 0; }
// Open a connection (can be nested) // Open a connection (can be nested)
public void OpenSharedConnection() public void OpenSharedConnection()
...@@ -173,13 +176,7 @@ public void CloseSharedConnection() ...@@ -173,13 +176,7 @@ public void CloseSharedConnection()
} }
// Helper to create a transaction scope // Helper to create a transaction scope
public Transaction Transaction public Transaction Transaction => new Transaction(this);
{
get
{
return new Transaction(this);
}
}
// Use by derived repo generated by T4 templates // Use by derived repo generated by T4 templates
public virtual void OnBeginTransaction() { } public virtual void OnBeginTransaction() { }
...@@ -199,9 +196,10 @@ public void BeginTransaction() ...@@ -199,9 +196,10 @@ public void BeginTransaction()
_transactionCancelled = false; _transactionCancelled = false;
OnBeginTransaction(); OnBeginTransaction();
} }
} }
private
// Internal helper to cleanup transaction stuff // Internal helper to cleanup transaction stuff
void CleanupTransaction() void CleanupTransaction()
{ {
...@@ -234,15 +232,14 @@ public void CompleteTransaction() ...@@ -234,15 +232,14 @@ public void CompleteTransaction()
} }
// Helper to handle named parameters from object properties // Helper to handle named parameters from object properties
static Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled); private static readonly Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest) public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest)
{ {
return rxParams.Replace(_sql, m => return rxParams.Replace(_sql, m =>
{ {
string param = m.Value.Substring(1); string param = m.Value.Substring(1);
int paramIndex; if (int.TryParse(param, out int paramIndex))
if (int.TryParse(param, out paramIndex))
{ {
// Numbered parameter // Numbered parameter
if (paramIndex < 0 || paramIndex >= args_src.Length) if (paramIndex < 0 || paramIndex >= args_src.Length)
...@@ -274,7 +271,7 @@ public static string ProcessParams(string _sql, object[] args_src, List<object> ...@@ -274,7 +271,7 @@ public static string ProcessParams(string _sql, object[] args_src, List<object>
} }
// Add a parameter to a DB command // Add a parameter to a DB command
static void AddParam(DbCommand cmd, object item, string ParameterPrefix) private static void AddParam(DbCommand cmd, object item, string ParameterPrefix)
{ {
var p = cmd.CreateParameter(); var p = cmd.CreateParameter();
p.ParameterName = string.Format("{0}{1}", ParameterPrefix, cmd.Parameters.Count); p.ParameterName = string.Format("{0}{1}", ParameterPrefix, cmd.Parameters.Count);
...@@ -437,8 +434,9 @@ public T ExecuteScalar<T>(Sql sql) ...@@ -437,8 +434,9 @@ public T ExecuteScalar<T>(Sql sql)
return ExecuteScalar<T>(sql.SQL, sql.Arguments); return ExecuteScalar<T>(sql.SQL, sql.Arguments);
} }
Regex rxSelect = new Regex(@"^\s*SELECT\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline); private readonly Regex rxSelect = new Regex(@"^\s*SELECT\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string AddSelectClause<T>(string sql)
private string AddSelectClause<T>(string sql)
{ {
// Already present? // Already present?
if (rxSelect.IsMatch(sql)) if (rxSelect.IsMatch(sql))
...@@ -571,11 +569,10 @@ public T SingleOrDefault<T>(string sql, params object[] args) where T : new() ...@@ -571,11 +569,10 @@ public T SingleOrDefault<T>(string sql, params object[] args) where T : new()
} }
} }
// Warning: scary regex follows // Warning: scary regex follows
static Regex rxColumns = new Regex(@"^\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", private static readonly Regex rxColumns = new Regex(@"^\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b",
RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled); RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", private static readonly Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*",
RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled); RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy) public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
{ {
...@@ -611,10 +608,7 @@ public Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[] ...@@ -611,10 +608,7 @@ public Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[]
// Add auto select clause // Add auto select clause
if (EnableAutoSelect) if (EnableAutoSelect)
sql = AddSelectClause<T>(sql); sql = AddSelectClause<T>(sql);
if (!SplitSqlForPaging(sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy))
// Split the SQL into the bits we need
string sqlCount, sqlSelectRemoved, sqlOrderBy;
if (!SplitSqlForPaging(sql, out sqlCount, out sqlSelectRemoved, out sqlOrderBy))
throw new Exception("Unable to parse SQL statement for paged query"); throw new Exception("Unable to parse SQL statement for paged query");
// Setup the paged result // Setup the paged result
...@@ -626,7 +620,6 @@ public Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[] ...@@ -626,7 +620,6 @@ public Page<T> Page<T>(long page, long itemsPerPage, string sql, params object[]
if ((result.TotalItems % itemsPerPage) != 0) if ((result.TotalItems % itemsPerPage) != 0)
result.TotalPages++; result.TotalPages++;
// Build the SQL for the actual final result // Build the SQL for the actual final result
string sqlPage; string sqlPage;
if (IsSqlServer()) if (IsSqlServer())
...@@ -710,7 +703,6 @@ public IEnumerable<T> Query<T>(Sql sql) where T : new() ...@@ -710,7 +703,6 @@ public IEnumerable<T> Query<T>(Sql sql) where T : new()
return Query<T>(sql.SQL, sql.Arguments); return Query<T>(sql.SQL, sql.Arguments);
} }
public T Single<T>(string sql, params object[] args) where T : new() public T Single<T>(string sql, params object[] args) where T : new()
{ {
T val = SingleOrDefault<T>(sql, args); T val = SingleOrDefault<T>(sql, args);
...@@ -719,6 +711,7 @@ public T Single<T>(string sql, params object[] args) where T : new() ...@@ -719,6 +711,7 @@ public T Single<T>(string sql, params object[] args) where T : new()
else else
throw new InvalidOperationException("The sequence contains no elements"); throw new InvalidOperationException("The sequence contains no elements");
} }
public T First<T>(string sql, params object[] args) where T : new() public T First<T>(string sql, params object[] args) where T : new()
{ {
T val = FirstOrDefault<T>(sql, args); T val = FirstOrDefault<T>(sql, args);
...@@ -732,14 +725,17 @@ public T Single<T>(Sql sql) where T : new() ...@@ -732,14 +725,17 @@ public T Single<T>(Sql sql) where T : new()
{ {
return Single<T>(sql.SQL, sql.Arguments); return Single<T>(sql.SQL, sql.Arguments);
} }
public T SingleOrDefault<T>(Sql sql) where T : new() public T SingleOrDefault<T>(Sql sql) where T : new()
{ {
return SingleOrDefault<T>(sql.SQL, sql.Arguments); return SingleOrDefault<T>(sql.SQL, sql.Arguments);
} }
public T FirstOrDefault<T>(Sql sql) where T : new() public T FirstOrDefault<T>(Sql sql) where T : new()
{ {
return FirstOrDefault<T>(sql.SQL, sql.Arguments); return FirstOrDefault<T>(sql.SQL, sql.Arguments);
} }
public T First<T>(Sql sql) where T : new() public T First<T>(Sql sql) where T : new()
{ {
return First<T>(sql.SQL, sql.Arguments); return First<T>(sql.SQL, sql.Arguments);
...@@ -787,8 +783,7 @@ public object Insert(string tableName, string primaryKeyName, object poco) ...@@ -787,8 +783,7 @@ public object Insert(string tableName, string primaryKeyName, object poco)
// Assign the ID back to the primary key property // Assign the ID back to the primary key property
if (primaryKeyName != null) if (primaryKeyName != null)
{ {
PocoColumn pc; if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc))
if (pd.Columns.TryGetValue(primaryKeyName, out pc))
{ {
pc.PropertyInfo.SetValue(poco, Convert.ChangeType(id, pc.PropertyInfo.PropertyType), null); pc.PropertyInfo.SetValue(poco, Convert.ChangeType(id, pc.PropertyInfo.PropertyType), null);
} }
...@@ -834,8 +829,7 @@ public int Update(string tableName, string primaryKeyName, object poco, object p ...@@ -834,8 +829,7 @@ public int Update(string tableName, string primaryKeyName, object poco, object p
// Don't update the primary key, but grab the value if we don't have it // Don't update the primary key, but grab the value if we don't have it
if (i.Key == primaryKeyName) if (i.Key == primaryKeyName)
{ {
if (primaryKeyValue == null) primaryKeyValue = primaryKeyValue ?? i.Value.PropertyInfo.GetValue(poco, null);
primaryKeyValue = i.Value.PropertyInfo.GetValue(poco, null);
continue; continue;
} }
...@@ -919,8 +913,7 @@ public int Delete(string tableName, string primaryKeyName, object poco, object p ...@@ -919,8 +913,7 @@ public int Delete(string tableName, string primaryKeyName, object poco, object p
if (primaryKeyValue == null) if (primaryKeyValue == null)
{ {
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
PocoColumn pc; if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc))
if (pd.Columns.TryGetValue(primaryKeyName, out pc))
{ {
primaryKeyValue = pc.PropertyInfo.GetValue(poco, null); primaryKeyValue = pc.PropertyInfo.GetValue(poco, null);
} }
...@@ -955,8 +948,7 @@ public bool IsNew(string primaryKeyName, object poco) ...@@ -955,8 +948,7 @@ public bool IsNew(string primaryKeyName, object poco)
// If primary key value not specified, pick it up from the object // If primary key value not specified, pick it up from the object
var pd = PocoData.ForType(poco.GetType()); var pd = PocoData.ForType(poco.GetType());
PropertyInfo pi; PropertyInfo pi;
PocoColumn pc; if (pd.Columns.TryGetValue(primaryKeyName, out PocoColumn pc))
if (pd.Columns.TryGetValue(primaryKeyName, out pc))
{ {
pi = pc.PropertyInfo; pi = pc.PropertyInfo;
} }
...@@ -1020,8 +1012,8 @@ public void Save(object poco) ...@@ -1020,8 +1012,8 @@ public void Save(object poco)
Save(pd.TableName, pd.PrimaryKey, poco); Save(pd.TableName, pd.PrimaryKey, poco);
} }
public string LastSQL { get { return _lastSql; } } public string LastSQL => _lastSql;
public object[] LastArgs { get { return _lastArgs; } } public object[] LastArgs => _lastArgs;
public string LastCommand public string LastCommand
{ {
get get
...@@ -1042,11 +1034,7 @@ public string LastCommand ...@@ -1042,11 +1034,7 @@ public string LastCommand
} }
} }
public static IMapper Mapper public static IMapper Mapper { get; set; }
{
get;
set;
}
internal class PocoColumn internal class PocoColumn
{ {
...@@ -1054,14 +1042,14 @@ internal class PocoColumn ...@@ -1054,14 +1042,14 @@ internal class PocoColumn
public PropertyInfo PropertyInfo; public PropertyInfo PropertyInfo;
public bool ResultColumn; public bool ResultColumn;
} }
internal class PocoData internal class PocoData
{ {
public static PocoData ForType(Type t) public static PocoData ForType(Type t)
{ {
lock (m_PocoData) lock (m_PocoData)
{ {
PocoData pd; if (!m_PocoData.TryGetValue(t, out PocoData pd))
if (!m_PocoData.TryGetValue(t, out pd))
{ {
pd = new PocoData(t); pd = new PocoData(t);
m_PocoData.Add(t, pd); m_PocoData.Add(t, pd);
...@@ -1081,8 +1069,7 @@ public PocoData(Type t) ...@@ -1081,8 +1069,7 @@ public PocoData(Type t)
var tempPrimaryKey = a.Length == 0 ? "ID" : (a[0] as PrimaryKey).Value; var tempPrimaryKey = a.Length == 0 ? "ID" : (a[0] as PrimaryKey).Value;
// Call column mapper // Call column mapper
if (Database.Mapper != null) Database.Mapper?.GetTableInfo(t, ref tempTableName, ref tempPrimaryKey);
Database.Mapper.GetTableInfo(t, ref tempTableName, ref tempPrimaryKey);
TableName = tempTableName; TableName = tempTableName;
PrimaryKey = tempPrimaryKey; PrimaryKey = tempPrimaryKey;
...@@ -1104,8 +1091,10 @@ public PocoData(Type t) ...@@ -1104,8 +1091,10 @@ public PocoData(Type t)
continue; continue;
} }
var pc = new PocoColumn(); var pc = new PocoColumn()
pc.PropertyInfo = pi; {
PropertyInfo = pi
};
// Work out the DB column name // Work out the DB column name
if (ColAttrs.Length > 0) if (ColAttrs.Length > 0)
...@@ -1118,7 +1107,7 @@ public PocoData(Type t) ...@@ -1118,7 +1107,7 @@ public PocoData(Type t)
if (pc.ColumnName == null) if (pc.ColumnName == null)
{ {
pc.ColumnName = pi.Name; pc.ColumnName = pi.Name;
if (Database.Mapper != null && !Database.Mapper.MapPropertyToColumn(pi, ref pc.ColumnName, ref pc.ResultColumn)) if (Mapper?.MapPropertyToColumn(pi, ref pc.ColumnName, ref pc.ResultColumn) == false)
continue; continue;
} }
...@@ -1136,8 +1125,7 @@ public PocoData(Type t) ...@@ -1136,8 +1125,7 @@ public PocoData(Type t)
lock (PocoFactories) lock (PocoFactories)
{ {
// Have we already created it? // Have we already created it?
object factory; if (PocoFactories.TryGetValue(key, out object factory))
if (PocoFactories.TryGetValue(key, out factory))
return factory as Func<IDataReader, T>; return factory as Func<IDataReader, T>;
lock (m_Converters) lock (m_Converters)
...@@ -1157,8 +1145,7 @@ public PocoData(Type t) ...@@ -1157,8 +1145,7 @@ public PocoData(Type t)
for (int i = 0; i < r.FieldCount; i++) for (int i = 0; i < r.FieldCount; i++)
{ {
// Get the PocoColumn for this db column, ignore if not known // Get the PocoColumn for this db column, ignore if not known
PocoColumn pc; if (!Columns.TryGetValue(r.GetName(i), out PocoColumn pc))
if (!Columns.TryGetValue(r.GetName(i), out pc))
continue; continue;
// Get the source type for this column // Get the source type for this column
...@@ -1180,19 +1167,19 @@ public PocoData(Type t) ...@@ -1180,19 +1167,19 @@ public PocoData(Type t)
// Get converter from the mapper // Get converter from the mapper
if (Database.Mapper != null) if (Database.Mapper != null)
{ {
converter = Database.Mapper.GetValueConverter(pc.PropertyInfo, srcType); converter = Mapper.GetValueConverter(pc.PropertyInfo, srcType);
} }
// Standard DateTime->Utc mapper // Standard DateTime->Utc mapper
if (ForceDateTimesToUtc && converter == null && srcType == typeof(DateTime) && (dstType == typeof(DateTime) || dstType == typeof(DateTime?))) if (ForceDateTimesToUtc && converter == null && srcType == typeof(DateTime) && (dstType == typeof(DateTime) || dstType == typeof(DateTime?)))
{ {
converter = delegate(object src) { return new DateTime(((DateTime)src).Ticks, DateTimeKind.Utc); }; converter = (object src) => new DateTime(((DateTime)src).Ticks, DateTimeKind.Utc);
} }
// Forced type conversion // Forced type conversion
if (converter == null && !dstType.IsAssignableFrom(srcType)) if (converter == null && !dstType.IsAssignableFrom(srcType))
{ {
converter = delegate(object src) { return Convert.ChangeType(src, dstType, null); }; converter = (object src) => Convert.ChangeType(src, dstType, null);
} }
// Fast // Fast
...@@ -1263,28 +1250,27 @@ public PocoData(Type t) ...@@ -1263,28 +1250,27 @@ public PocoData(Type t)
} }
} }
private static readonly Dictionary<Type, PocoData> m_PocoData = new Dictionary<Type, PocoData>();
private static readonly List<Func<object, object>> m_Converters = new List<Func<object, object>>();
static Dictionary<Type, PocoData> m_PocoData = new Dictionary<Type, PocoData>(); private static readonly MethodInfo fnGetValue = typeof(IDataRecord).GetMethod("GetValue", new Type[] { typeof(int) });
static List<Func<object, object>> m_Converters = new List<Func<object, object>>(); private static readonly MethodInfo fnIsDBNull = typeof(IDataRecord).GetMethod("IsDBNull");
private static readonly FieldInfo fldConverters = typeof(PocoData).GetField("m_Converters", BindingFlags.Static | BindingFlags.GetField | BindingFlags.NonPublic);
private static readonly MethodInfo fnListGetItem = typeof(List<Func<object, object>>).GetProperty("Item").GetGetMethod();
private static readonly MethodInfo fnInvoke = typeof(Func<object, object>).GetMethod("Invoke");
static MethodInfo fnGetValue = typeof(IDataRecord).GetMethod("GetValue", new Type[] { typeof(int) }); public string TableName { get; }
static MethodInfo fnIsDBNull = typeof(IDataRecord).GetMethod("IsDBNull"); public string PrimaryKey { get; }
static FieldInfo fldConverters = typeof(PocoData).GetField("m_Converters", BindingFlags.Static | BindingFlags.GetField | BindingFlags.NonPublic); public string QueryColumns { get; }
static MethodInfo fnListGetItem = typeof(List<Func<object, object>>).GetProperty("Item").GetGetMethod(); public Dictionary<string, PocoColumn> Columns { get; }
static MethodInfo fnInvoke = typeof(Func<object, object>).GetMethod("Invoke");
public string TableName { get; private set; } private readonly Dictionary<string, object> PocoFactories = new Dictionary<string, object>();
public string PrimaryKey { get; private set; }
public string QueryColumns { get; private set; }
public Dictionary<string, PocoColumn> Columns { get; private set; }
Dictionary<string, object> PocoFactories = new Dictionary<string, object>();
} }
// ShareableConnection represents either a shared connection used by a transaction, // ShareableConnection represents either a shared connection used by a transaction,
// or a one-off connection if not in a transaction. // or a one-off connection if not in a transaction.
// Non-shared connections are disposed // Non-shared connections are disposed
class ShareableConnection : IDisposable private class ShareableConnection : IDisposable
{ {
public ShareableConnection(Database db) public ShareableConnection(Database db)
{ {
...@@ -1292,15 +1278,9 @@ public ShareableConnection(Database db) ...@@ -1292,15 +1278,9 @@ public ShareableConnection(Database db)
_db.OpenSharedConnection(); _db.OpenSharedConnection();
} }
public DbConnection Connection public DbConnection Connection => _db._sharedConnection;
{
get
{
return _db._sharedConnection;
}
}
Database _db; private readonly Database _db;
public void Dispose() public void Dispose()
{ {
...@@ -1308,19 +1288,18 @@ public void Dispose() ...@@ -1308,19 +1288,18 @@ public void Dispose()
} }
} }
// Member variables // Member variables
string _connectionString; private readonly string _connectionString;
string _providerName; private readonly string _providerName;
DbProviderFactory _factory; private DbProviderFactory _factory;
DbConnection _sharedConnection; private DbConnection _sharedConnection;
DbTransaction _transaction; private DbTransaction _transaction;
int _sharedConnectionDepth; private int _sharedConnectionDepth;
int _transactionDepth; private int _transactionDepth;
bool _transactionCancelled; private bool _transactionCancelled;
string _lastSql; private string _lastSql;
object[] _lastArgs; private object[] _lastArgs;
string _paramPrefix = "@"; private string _paramPrefix = "@";
} }
// Transaction object helps maintain transaction depth counts // Transaction object helps maintain transaction depth counts
...@@ -1340,11 +1319,10 @@ public void Complete() ...@@ -1340,11 +1319,10 @@ public void Complete()
public void Dispose() public void Dispose()
{ {
if (_db != null) _db?.AbortTransaction();
_db.AbortTransaction();
} }
Database _db; private Database _db;
} }
// Simple helper class for building SQL statments // Simple helper class for building SQL statments
...@@ -1360,13 +1338,13 @@ public Sql(string sql, params object[] args) ...@@ -1360,13 +1338,13 @@ public Sql(string sql, params object[] args)
_args = args; _args = args;
} }
string _sql; private readonly string _sql;
object[] _args; private readonly object[] _args;
Sql _rhs; private Sql _rhs;
string _sqlFinal; private string _sqlFinal;
object[] _argsFinal; private object[] _argsFinal;
void Build() private void Build()
{ {
// already built? // already built?
if (_sqlFinal != null) if (_sqlFinal != null)
...@@ -1433,9 +1411,9 @@ public Sql From(params object[] args) ...@@ -1433,9 +1411,9 @@ public Sql From(params object[] args)
return Append(new Sql("FROM " + String.Join(", ", (from x in args select x.ToString()).ToArray()))); return Append(new Sql("FROM " + String.Join(", ", (from x in args select x.ToString()).ToArray())));
} }
static bool Is(Sql sql, string sqltype) private static bool Is(Sql sql, string sqltype)
{ {
return sql != null && sql._sql != null && sql._sql.StartsWith(sqltype, StringComparison.InvariantCultureIgnoreCase); return sql?._sql != null && sql._sql.StartsWith(sqltype, StringComparison.InvariantCultureIgnoreCase);
} }
public void Build(StringBuilder sb, List<object> args, Sql lhs) public void Build(StringBuilder sb, List<object> args, Sql lhs)
...@@ -1459,8 +1437,7 @@ public void Build(StringBuilder sb, List<object> args, Sql lhs) ...@@ -1459,8 +1437,7 @@ public void Build(StringBuilder sb, List<object> args, Sql lhs)
} }
// Now do rhs // Now do rhs
if (_rhs != null) _rhs?.Build(sb, args, this);
_rhs.Build(sb, args, this);
} }
} }
} }
......
...@@ -12,7 +12,7 @@ namespace Dapper.Tests ...@@ -12,7 +12,7 @@ namespace Dapper.Tests
public class Tests : TestBase public class Tests : TestBase
{ {
private SqlConnection _marsConnection; private SqlConnection _marsConnection;
private SqlConnection marsConnection => _marsConnection ?? (_marsConnection = GetOpenConnection(true)); private SqlConnection MarsConnection => _marsConnection ?? (_marsConnection = GetOpenConnection(true));
[Fact] [Fact]
public async Task TestBasicStringUsageAsync() public async Task TestBasicStringUsageAsync()
...@@ -108,7 +108,7 @@ public async Task TestExecuteAsync() ...@@ -108,7 +108,7 @@ public async Task TestExecuteAsync()
} }
[Fact] [Fact]
public void TestExecuteClosedConnAsync() public void TestExecuteClosedConnAsyncInner()
{ {
var query = connection.ExecuteAsync("declare @foo table(id int not null); insert @foo values(@id);", new { id = 1 }); var query = connection.ExecuteAsync("declare @foo table(id int not null); insert @foo values(@id);", new { id = 1 });
var val = query.Result; var val = query.Result;
...@@ -323,15 +323,15 @@ public async Task LiteralInAsync() ...@@ -323,15 +323,15 @@ public async Task LiteralInAsync()
public async Task RunSequentialVersusParallelAsync() public async Task RunSequentialVersusParallelAsync()
{ {
var ids = Enumerable.Range(1, 20000).Select(id => new { id }).ToArray(); var ids = Enumerable.Range(1, 20000).Select(id => new { id }).ToArray();
await marsConnection.ExecuteAsync(new CommandDefinition("select @id", ids.Take(5), flags: CommandFlags.None)).ConfigureAwait(false); await MarsConnection.ExecuteAsync(new CommandDefinition("select @id", ids.Take(5), flags: CommandFlags.None)).ConfigureAwait(false);
var watch = Stopwatch.StartNew(); var watch = Stopwatch.StartNew();
await marsConnection.ExecuteAsync(new CommandDefinition("select @id", ids, flags: CommandFlags.None)).ConfigureAwait(false); await MarsConnection.ExecuteAsync(new CommandDefinition("select @id", ids, flags: CommandFlags.None)).ConfigureAwait(false);
watch.Stop(); watch.Stop();
Console.WriteLine("No pipeline: {0}ms", watch.ElapsedMilliseconds); Console.WriteLine("No pipeline: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew(); watch = Stopwatch.StartNew();
await marsConnection.ExecuteAsync(new CommandDefinition("select @id", ids, flags: CommandFlags.Pipelined)).ConfigureAwait(false); await MarsConnection.ExecuteAsync(new CommandDefinition("select @id", ids, flags: CommandFlags.Pipelined)).ConfigureAwait(false);
watch.Stop(); watch.Stop();
Console.WriteLine("Pipeline: {0}ms", watch.ElapsedMilliseconds); Console.WriteLine("Pipeline: {0}ms", watch.ElapsedMilliseconds);
} }
...@@ -340,15 +340,15 @@ public async Task RunSequentialVersusParallelAsync() ...@@ -340,15 +340,15 @@ public async Task RunSequentialVersusParallelAsync()
public void RunSequentialVersusParallelSync() public void RunSequentialVersusParallelSync()
{ {
var ids = Enumerable.Range(1, 20000).Select(id => new { id }).ToArray(); var ids = Enumerable.Range(1, 20000).Select(id => new { id }).ToArray();
marsConnection.Execute(new CommandDefinition("select @id", ids.Take(5), flags: CommandFlags.None)); MarsConnection.Execute(new CommandDefinition("select @id", ids.Take(5), flags: CommandFlags.None));
var watch = Stopwatch.StartNew(); var watch = Stopwatch.StartNew();
marsConnection.Execute(new CommandDefinition("select @id", ids, flags: CommandFlags.None)); MarsConnection.Execute(new CommandDefinition("select @id", ids, flags: CommandFlags.None));
watch.Stop(); watch.Stop();
Console.WriteLine("No pipeline: {0}ms", watch.ElapsedMilliseconds); Console.WriteLine("No pipeline: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew(); watch = Stopwatch.StartNew();
marsConnection.Execute(new CommandDefinition("select @id", ids, flags: CommandFlags.Pipelined)); MarsConnection.Execute(new CommandDefinition("select @id", ids, flags: CommandFlags.Pipelined));
watch.Stop(); watch.Stop();
Console.WriteLine("Pipeline: {0}ms", watch.ElapsedMilliseconds); Console.WriteLine("Pipeline: {0}ms", watch.ElapsedMilliseconds);
} }
...@@ -365,7 +365,7 @@ public void AssertNoCacheWorksForQueryMultiple() ...@@ -365,7 +365,7 @@ public void AssertNoCacheWorksForQueryMultiple()
int c, d; int c, d;
SqlMapper.PurgeQueryCache(); SqlMapper.PurgeQueryCache();
int before = SqlMapper.GetCachedSQLCount(); int before = SqlMapper.GetCachedSQLCount();
using (var multi = marsConnection.QueryMultiple(cmdDef)) using (var multi = MarsConnection.QueryMultiple(cmdDef))
{ {
c = multi.Read<int>().Single(); c = multi.Read<int>().Single();
d = multi.Read<int>().Single(); d = multi.Read<int>().Single();
...@@ -387,7 +387,7 @@ public async Task TypeBasedViaTypeAsync() ...@@ -387,7 +387,7 @@ public async Task TypeBasedViaTypeAsync()
{ {
Type type = Common.GetSomeType(); Type type = Common.GetSomeType();
dynamic actual = (await marsConnection.QueryAsync(type, "select @A as [A], @B as [B]", new { A = 123, B = "abc" }).ConfigureAwait(false)).FirstOrDefault(); dynamic actual = (await MarsConnection.QueryAsync(type, "select @A as [A], @B as [B]", new { A = 123, B = "abc" }).ConfigureAwait(false)).FirstOrDefault();
((object)actual).GetType().IsEqualTo(type); ((object)actual).GetType().IsEqualTo(type);
int a = actual.A; int a = actual.A;
string b = actual.B; string b = actual.B;
...@@ -400,7 +400,7 @@ public async Task TypeBasedViaTypeAsyncFirstOrDefault() ...@@ -400,7 +400,7 @@ public async Task TypeBasedViaTypeAsyncFirstOrDefault()
{ {
Type type = Common.GetSomeType(); Type type = Common.GetSomeType();
dynamic actual = await marsConnection.QueryFirstOrDefaultAsync(type, "select @A as [A], @B as [B]", new { A = 123, B = "abc" }).ConfigureAwait(false); dynamic actual = await MarsConnection.QueryFirstOrDefaultAsync(type, "select @A as [A], @B as [B]", new { A = 123, B = "abc" }).ConfigureAwait(false);
((object)actual).GetType().IsEqualTo(type); ((object)actual).GetType().IsEqualTo(type);
int a = actual.A; int a = actual.A;
string b = actual.B; string b = actual.B;
...@@ -715,7 +715,7 @@ public async Task TestMultiMapArbitraryMapsAsync() ...@@ -715,7 +715,7 @@ public async Task TestMultiMapArbitraryMapsAsync()
var data = (await connection.QueryAsync<ReviewBoard>(sql, types, mapper).ConfigureAwait(false)).ToList(); var data = (await connection.QueryAsync<ReviewBoard>(sql, types, mapper).ConfigureAwait(false)).ToList();
var p = data.First(); var p = data[0];
p.Id.IsEqualTo(1); p.Id.IsEqualTo(1);
p.Name.IsEqualTo("Review Board 1"); p.Name.IsEqualTo("Review Board 1");
p.User1.Id.IsEqualTo(1); p.User1.Id.IsEqualTo(1);
......
...@@ -88,7 +88,7 @@ private class _ExplicitConstructors ...@@ -88,7 +88,7 @@ private class _ExplicitConstructors
public int Field { get; set; } public int Field { get; set; }
public int Field_1 { get; set; } public int Field_1 { get; set; }
private bool WentThroughProperConstructor; private readonly bool WentThroughProperConstructor;
public _ExplicitConstructors() { } public _ExplicitConstructors() { }
......
...@@ -15,7 +15,7 @@ public FactUnlessCoreCLRAttribute(string url) ...@@ -15,7 +15,7 @@ public FactUnlessCoreCLRAttribute(string url)
this.Url = url; this.Url = url;
} }
public string Url { get; private set; } public string Url { get; }
} }
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
......
...@@ -85,8 +85,7 @@ public void Dispose() ...@@ -85,8 +85,7 @@ public void Dispose()
public bool QueueMessage(IMessageSinkMessage message) public bool QueueMessage(IMessageSinkMessage message)
{ {
var testFailed = message as ITestFailed; if (message is ITestFailed testFailed)
if (testFailed != null)
{ {
var exceptionType = testFailed.ExceptionTypes.FirstOrDefault(); var exceptionType = testFailed.ExceptionTypes.FirstOrDefault();
if (exceptionType == typeof(SkipTestException).FullName) if (exceptionType == typeof(SkipTestException).FullName)
......
...@@ -15,8 +15,7 @@ public void ParentChildIdentityAssociations() ...@@ -15,8 +15,7 @@ public void ParentChildIdentityAssociations()
var parents = connection.Query<Parent, Child, Parent>(@"select 1 as [Id], 1 as [Id] union all select 1,2 union all select 2,3 union all select 1,4 union all select 3,5", var parents = connection.Query<Parent, Child, Parent>(@"select 1 as [Id], 1 as [Id] union all select 1,2 union all select 2,3 union all select 1,4 union all select 3,5",
(parent, child) => (parent, child) =>
{ {
Parent found; if (!lookup.TryGetValue(parent.Id, out Parent found))
if (!lookup.TryGetValue(parent.Id, out found))
{ {
lookup.Add(parent.Id, found = parent); lookup.Add(parent.Id, found = parent);
} }
...@@ -63,7 +62,7 @@ public void TestMultiMap() ...@@ -63,7 +62,7 @@ public void TestMultiMap()
Order by p.Id"; Order by p.Id";
var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }).ToList(); var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }).ToList();
var p = data.First(); var p = data[0];
p.Content.IsEqualTo("Sams Post1"); p.Content.IsEqualTo("Sams Post1");
p.Id.IsEqualTo(1); p.Id.IsEqualTo(1);
...@@ -210,7 +209,7 @@ public void TestMultiMapDynamic() ...@@ -210,7 +209,7 @@ public void TestMultiMapDynamic()
Order by p.Id"; Order by p.Id";
var data = connection.Query<dynamic, dynamic, dynamic>(sql, (post, user) => { post.Owner = user; return post; }).ToList(); var data = connection.Query<dynamic, dynamic, dynamic>(sql, (post, user) => { post.Owner = user; return post; }).ToList();
var p = data.First(); var p = data[0];
// hairy extension method support for dynamics // hairy extension method support for dynamics
((string)p.Content).IsEqualTo("Sams Post1"); ((string)p.Content).IsEqualTo("Sams Post1");
...@@ -436,7 +435,7 @@ public void TestMultiMapArbitraryMaps() ...@@ -436,7 +435,7 @@ public void TestMultiMapArbitraryMaps()
var data = connection.Query<ReviewBoard>(sql, types, mapper).ToList(); var data = connection.Query<ReviewBoard>(sql, types, mapper).ToList();
var p = data.First(); var p = data[0];
p.Id.IsEqualTo(1); p.Id.IsEqualTo(1);
p.Name.IsEqualTo("Review Board 1"); p.Name.IsEqualTo("Review Board 1");
p.User1.Id.IsEqualTo(1); p.User1.Id.IsEqualTo(1);
...@@ -495,7 +494,7 @@ public void TestMultiMapGridReader() ...@@ -495,7 +494,7 @@ public void TestMultiMapGridReader()
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
var data = grid.Read<Post, User, Post>((post, user) => { post.Owner = user; return post; }).ToList(); var data = grid.Read<Post, User, Post>((post, user) => { post.Owner = user; return post; }).ToList();
var p = data.First(); var p = data[0];
p.Content.IsEqualTo("Sams Post1"); p.Content.IsEqualTo("Sams Post1");
p.Id.IsEqualTo(1); p.Id.IsEqualTo(1);
......
...@@ -482,7 +482,7 @@ public void SO29596645_TvpProperty() ...@@ -482,7 +482,7 @@ public void SO29596645_TvpProperty()
private class SO29596645_RuleTableValuedParameters : SqlMapper.IDynamicParameters private class SO29596645_RuleTableValuedParameters : SqlMapper.IDynamicParameters
{ {
private string parameterName; private readonly string parameterName;
public SO29596645_RuleTableValuedParameters(string parameterName) public SO29596645_RuleTableValuedParameters(string parameterName)
{ {
...@@ -506,7 +506,7 @@ public void AddParameters(IDbCommand command, SqlMapper.Identity identity) ...@@ -506,7 +506,7 @@ public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
private class SO29596645_OrganisationDTO private class SO29596645_OrganisationDTO
{ {
public SO29596645_RuleTableValuedParameters Rules { get; private set; } public SO29596645_RuleTableValuedParameters Rules { get; }
public SO29596645_OrganisationDTO() public SO29596645_OrganisationDTO()
{ {
...@@ -1074,11 +1074,13 @@ public class MultipleParametersWithIndexerDeclaringType ...@@ -1074,11 +1074,13 @@ public class MultipleParametersWithIndexerDeclaringType
get { return null; } get { return null; }
set { } set { }
} }
public object this[object field, int index] public object this[object field, int index]
{ {
get { return null; } get { return null; }
set { } set { }
} }
public int B { get; set; } public int B { get; set; }
} }
......
...@@ -13,9 +13,11 @@ public class MySQLTests : TestBase ...@@ -13,9 +13,11 @@ public class MySQLTests : TestBase
string cs = IsAppVeyor string cs = IsAppVeyor
? "Server=localhost;Database=test;Uid=root;Pwd=Password12!;" ? "Server=localhost;Database=test;Uid=root;Pwd=Password12!;"
: "Server=localhost;Database=tests;Uid=test;Pwd=pass;"; : "Server=localhost;Database=tests;Uid=test;Pwd=pass;";
var csb = new MySql.Data.MySqlClient.MySqlConnectionStringBuilder(cs); var csb = new MySql.Data.MySqlClient.MySqlConnectionStringBuilder(cs)
csb.AllowZeroDateTime = allowZeroDatetime; {
csb.ConvertZeroDateTime = convertZeroDatetime; AllowZeroDateTime = allowZeroDatetime,
ConvertZeroDateTime = convertZeroDatetime
};
var conn = new MySql.Data.MySqlClient.MySqlConnection(csb.ConnectionString); var conn = new MySql.Data.MySqlClient.MySqlConnection(csb.ConnectionString);
if (open) conn.Open(); if (open) conn.Open();
return conn; return conn;
......
...@@ -30,7 +30,7 @@ public void MultiRSSqlCE() ...@@ -30,7 +30,7 @@ public void MultiRSSqlCE()
cnn.Execute("insert Authors values(1,'sam')"); cnn.Execute("insert Authors values(1,'sam')");
var data = cnn.Query<PostCE, AuthorCE, PostCE>(@"select * from Posts p left join Authors a on a.ID = p.AuthorID", (post, author) => { post.Author = author; return post; }).ToList(); var data = cnn.Query<PostCE, AuthorCE, PostCE>(@"select * from Posts p left join Authors a on a.ID = p.AuthorID", (post, author) => { post.Author = author; return post; }).ToList();
var firstPost = data.First(); var firstPost = data[0];
firstPost.Title.IsEqualTo("title"); firstPost.Title.IsEqualTo("title");
firstPost.Author.Name.IsEqualTo("sam"); firstPost.Author.Name.IsEqualTo("sam");
data[1].Author.IsNull(); data[1].Author.IsNull();
......
...@@ -105,8 +105,8 @@ public void TestReadDynamicWithGridReader() ...@@ -105,8 +105,8 @@ public void TestReadDynamicWithGridReader()
users.Count.IsEqualTo(2); users.Count.IsEqualTo(2);
posts.Count.IsEqualTo(3); posts.Count.IsEqualTo(3);
((int)users.First().Id).IsEqualTo(2); ((int)users[0].Id).IsEqualTo(2);
((int)posts.First().Id).IsEqualTo(3); ((int)posts[0].Id).IsEqualTo(3);
} }
finally finally
{ {
......
...@@ -34,7 +34,6 @@ public void TupleReturnValue_Works_ByPosition() ...@@ -34,7 +34,6 @@ public void TupleReturnValue_Works_ByPosition()
val.name.IsEqualTo("Fred"); val.name.IsEqualTo("Fred");
} }
[Fact] [Fact]
public void TupleReturnValue_TooManyColumns_Ignored() public void TupleReturnValue_TooManyColumns_Ignored()
{ {
...@@ -43,7 +42,6 @@ public void TupleReturnValue_TooManyColumns_Ignored() ...@@ -43,7 +42,6 @@ public void TupleReturnValue_TooManyColumns_Ignored()
val.name.IsEqualTo("Fred"); val.name.IsEqualTo("Fred");
} }
[Fact] [Fact]
public void TupleReturnValue_TooFewColumns_Unmapped() public void TupleReturnValue_TooFewColumns_Unmapped()
{ {
...@@ -61,6 +59,5 @@ public void TupleReturnValue_Works_NamesIgnored() ...@@ -61,6 +59,5 @@ public void TupleReturnValue_Works_NamesIgnored()
val.id.IsEqualTo(42); val.id.IsEqualTo(42);
val.name.IsEqualTo("Fred"); val.name.IsEqualTo("Fred");
} }
} }
} }
...@@ -135,8 +135,7 @@ private static Action<IDbCommand> GetInit(Type commandType) ...@@ -135,8 +135,7 @@ private static Action<IDbCommand> GetInit(Type commandType)
{ {
if (commandType == null) if (commandType == null)
return null; // GIGO return null; // GIGO
Action<IDbCommand> action; if (SqlMapper.Link<Type, Action<IDbCommand>>.TryGet(commandInitCache, commandType, out Action<IDbCommand> action))
if (SqlMapper.Link<Type, Action<IDbCommand>>.TryGet(commandInitCache, commandType, out action))
{ {
return action; return action;
} }
...@@ -176,12 +175,11 @@ private static Action<IDbCommand> GetInit(Type commandType) ...@@ -176,12 +175,11 @@ private static Action<IDbCommand> GetInit(Type commandType)
private static MethodInfo GetBasicPropertySetter(Type declaringType, string name, Type expectedType) private static MethodInfo GetBasicPropertySetter(Type declaringType, string name, Type expectedType)
{ {
var prop = declaringType.GetProperty(name, BindingFlags.Public | BindingFlags.Instance); var prop = declaringType.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
if (prop != null && prop.CanWrite && prop.PropertyType == expectedType && prop.GetIndexParameters().Length == 0) if (prop?.CanWrite == true && prop.PropertyType == expectedType && prop.GetIndexParameters().Length == 0)
{ {
return prop.GetSetMethod(); return prop.GetSetMethod();
} }
return null; return null;
} }
} }
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
namespace Dapper namespace Dapper
{ {
/// <summary> /// <summary>
/// Additional state flags that control command behaviour /// Additional state flags that control command behaviour
/// </summary> /// </summary>
...@@ -26,5 +25,4 @@ public enum CommandFlags ...@@ -26,5 +25,4 @@ public enum CommandFlags
/// </summary> /// </summary>
NoCache = 4, NoCache = 4,
} }
} }
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
namespace Dapper namespace Dapper
{ {
/// <summary> /// <summary>
/// Implements custom property mapping by user provided criteria (usually presence of some custom attribute with column to member mapping) /// Implements custom property mapping by user provided criteria (usually presence of some custom attribute with column to member mapping)
/// </summary> /// </summary>
...@@ -19,14 +18,8 @@ public sealed class CustomPropertyTypeMap : SqlMapper.ITypeMap ...@@ -19,14 +18,8 @@ public sealed class CustomPropertyTypeMap : SqlMapper.ITypeMap
/// <param name="propertySelector">Property selector based on target type and DataReader column name</param> /// <param name="propertySelector">Property selector based on target type and DataReader column name</param>
public CustomPropertyTypeMap(Type type, Func<Type, string, PropertyInfo> propertySelector) public CustomPropertyTypeMap(Type type, Func<Type, string, PropertyInfo> propertySelector)
{ {
if (type == null) _type = type ?? throw new ArgumentNullException(nameof(type));
throw new ArgumentNullException(nameof(type)); _propertySelector = propertySelector ?? throw new ArgumentNullException(nameof(propertySelector));
if (propertySelector == null)
throw new ArgumentNullException(nameof(propertySelector));
_type = type;
_propertySelector = propertySelector;
} }
/// <summary> /// <summary>
...@@ -35,19 +28,14 @@ public CustomPropertyTypeMap(Type type, Func<Type, string, PropertyInfo> propert ...@@ -35,19 +28,14 @@ public CustomPropertyTypeMap(Type type, Func<Type, string, PropertyInfo> propert
/// <param name="names">DataReader column names</param> /// <param name="names">DataReader column names</param>
/// <param name="types">DataReader column types</param> /// <param name="types">DataReader column types</param>
/// <returns>Default constructor</returns> /// <returns>Default constructor</returns>
public ConstructorInfo FindConstructor(string[] names, Type[] types) public ConstructorInfo FindConstructor(string[] names, Type[] types) =>
{ _type.GetConstructor(new Type[0]);
return _type.GetConstructor(new Type[0]);
}
/// <summary> /// <summary>
/// Always returns null /// Always returns null
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ConstructorInfo FindExplicitConstructor() public ConstructorInfo FindExplicitConstructor() => null;
{
return null;
}
/// <summary> /// <summary>
/// Not implemented as far as default constructor used for all cases /// Not implemented as far as default constructor used for all cases
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#if !COREFX #if !COREFX
namespace Dapper namespace Dapper
{ {
sealed class DataTableHandler : SqlMapper.ITypeHandler internal sealed class DataTableHandler : SqlMapper.ITypeHandler
{ {
public object Parse(Type destinationType, object value) public object Parse(Type destinationType, object value)
{ {
......
...@@ -27,7 +27,7 @@ public DefaultTypeMap(Type type) ...@@ -27,7 +27,7 @@ public DefaultTypeMap(Type type)
_type = type; _type = type;
} }
#if COREFX #if COREFX
static bool IsParameterMatch(ParameterInfo[] x, ParameterInfo[] y) private static bool IsParameterMatch(ParameterInfo[] x, ParameterInfo[] y)
{ {
if (ReferenceEquals(x, y)) return true; if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false; if (x == null || y == null) return false;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace Dapper namespace Dapper
{ {
partial class DynamicParameters public partial class DynamicParameters
{ {
// The type here is used to differentiate the cache by type via generics // The type here is used to differentiate the cache by type via generics
// ReSharper disable once UnusedTypeParameter // ReSharper disable once UnusedTypeParameter
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
namespace Dapper namespace Dapper
{ {
partial class DynamicParameters public partial class DynamicParameters
{ {
sealed class ParamInfo private sealed class ParamInfo
{ {
public string Name { get; set; } public string Name { get; set; }
public object Value { get; set; } public object Value { get; set; }
......
...@@ -12,27 +12,18 @@ ...@@ -12,27 +12,18 @@
namespace Dapper namespace Dapper
{ {
/// <summary> /// <summary>
/// A bag of parameters that can be passed to the Dapper Query and Execute methods /// A bag of parameters that can be passed to the Dapper Query and Execute methods
/// </summary> /// </summary>
public partial class DynamicParameters : SqlMapper.IDynamicParameters, SqlMapper.IParameterLookup, SqlMapper.IParameterCallbacks public partial class DynamicParameters : SqlMapper.IDynamicParameters, SqlMapper.IParameterLookup, SqlMapper.IParameterCallbacks
{ {
internal const DbType EnumerableMultiParameter = (DbType)(-1); internal const DbType EnumerableMultiParameter = (DbType)(-1);
static Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>(); private static readonly Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>();
private readonly Dictionary<string, ParamInfo> parameters = new Dictionary<string, ParamInfo>();
Dictionary<string, ParamInfo> parameters = new Dictionary<string, ParamInfo>(); private List<object> templates;
List<object> templates;
object SqlMapper.IParameterLookup.this[string name]
{
get
{
ParamInfo param;
return parameters.TryGetValue(name, out param) ? param.Value : null;
}
}
object SqlMapper.IParameterLookup.this[string name] =>
parameters.TryGetValue(name, out ParamInfo param) ? param.Value : null;
/// <summary> /// <summary>
/// construct a dynamic parameter bag /// construct a dynamic parameter bag
...@@ -135,7 +126,7 @@ public void Add(string name, object value, DbType? dbType, ParameterDirection? d ...@@ -135,7 +126,7 @@ public void Add(string name, object value, DbType? dbType, ParameterDirection? d
}; };
} }
static string Clean(string name) private static string Clean(string name)
{ {
if (!string.IsNullOrEmpty(name)) if (!string.IsNullOrEmpty(name))
{ {
...@@ -249,7 +240,6 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity) ...@@ -249,7 +240,6 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
} }
else else
{ {
bool add = !command.Parameters.Contains(name); bool add = !command.Parameters.Contains(name);
IDbDataParameter p; IDbDataParameter p;
if (add) if (add)
...@@ -307,7 +297,6 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity) ...@@ -307,7 +297,6 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
/// </summary> /// </summary>
public IEnumerable<string> ParameterNames => parameters.Select(p => p.Key); public IEnumerable<string> ParameterNames => parameters.Select(p => p.Key);
/// <summary> /// <summary>
/// Get the value of a parameter /// Get the value of a parameter
/// </summary> /// </summary>
...@@ -349,18 +338,21 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -349,18 +338,21 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
// Is it even a MemberExpression? // Is it even a MemberExpression?
var lastMemberAccess = expression.Body as MemberExpression; var lastMemberAccess = expression.Body as MemberExpression;
if (lastMemberAccess == null || if (lastMemberAccess == null
(!(lastMemberAccess.Member is PropertyInfo) && || (!(lastMemberAccess.Member is PropertyInfo)
!(lastMemberAccess.Member is FieldInfo))) && !(lastMemberAccess.Member is FieldInfo)))
{ {
if (expression.Body.NodeType == ExpressionType.Convert && if (expression.Body.NodeType == ExpressionType.Convert
expression.Body.Type == typeof(object) && && expression.Body.Type == typeof(object)
((UnaryExpression)expression.Body).Operand is MemberExpression) && ((UnaryExpression)expression.Body).Operand is MemberExpression)
{ {
// It's got to be unboxed // It's got to be unboxed
lastMemberAccess = (MemberExpression)((UnaryExpression)expression.Body).Operand; lastMemberAccess = (MemberExpression)((UnaryExpression)expression.Body).Operand;
} }
else @throw(); else
{
@throw();
}
} }
// Does the chain consist of MemberExpressions leading to a ParameterExpression of type T? // Does the chain consist of MemberExpressions leading to a ParameterExpression of type T?
...@@ -379,14 +371,13 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -379,14 +371,13 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
var constant = diving?.Expression as ParameterExpression; var constant = diving?.Expression as ParameterExpression;
diving = diving?.Expression as MemberExpression; diving = diving?.Expression as MemberExpression;
if (constant != null && if (constant != null && constant.Type == typeof(T))
constant.Type == typeof(T))
{ {
break; break;
} }
else if (diving == null || else if (diving == null
(!(diving.Member is PropertyInfo) && || (!(diving.Member is PropertyInfo)
!(diving.Member is FieldInfo))) && !(diving.Member is FieldInfo)))
{ {
@throw(); @throw();
} }
...@@ -422,7 +413,7 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -422,7 +413,7 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
} }
else // Else it must be a field! else // Else it must be a field!
{ {
il.Emit(OpCodes.Ldfld, ((FieldInfo)member)); // [Member{i}] il.Emit(OpCodes.Ldfld, (FieldInfo)member); // [Member{i}]
} }
} }
...@@ -441,7 +432,7 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -441,7 +432,7 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
} }
else else
{ {
il.Emit(OpCodes.Stfld, ((FieldInfo)lastMember)); // SET il.Emit(OpCodes.Stfld, (FieldInfo)lastMember); // SET
} }
il.Emit(OpCodes.Ret); // GO il.Emit(OpCodes.Ret); // GO
...@@ -457,11 +448,10 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -457,11 +448,10 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
(outputCallbacks ?? (outputCallbacks = new List<Action>())).Add(() => (outputCallbacks ?? (outputCallbacks = new List<Action>())).Add(() =>
{ {
// Finally, prep the parameter and attach the callback to it // Finally, prep the parameter and attach the callback to it
ParamInfo parameter;
var targetMemberType = lastMemberAccess?.Type; var targetMemberType = lastMemberAccess?.Type;
int sizeToSet = (!size.HasValue && targetMemberType == typeof(string)) ? DbString.DefaultLength : size ?? 0; int sizeToSet = (!size.HasValue && targetMemberType == typeof(string)) ? DbString.DefaultLength : size ?? 0;
if (parameters.TryGetValue(dynamicParamName, out parameter)) if (parameters.TryGetValue(dynamicParamName, out ParamInfo parameter))
{ {
parameter.ParameterDirection = parameter.AttachedParam.Direction = ParameterDirection.InputOutput; parameter.ParameterDirection = parameter.AttachedParam.Direction = ParameterDirection.InputOutput;
...@@ -472,10 +462,9 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -472,10 +462,9 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
} }
else else
{ {
SqlMapper.ITypeHandler handler;
dbType = (!dbType.HasValue) dbType = (!dbType.HasValue)
#pragma warning disable 618 #pragma warning disable 618
? SqlMapper.LookupDbType(targetMemberType, targetMemberType?.Name, true, out handler) ? SqlMapper.LookupDbType(targetMemberType, targetMemberType?.Name, true, out SqlMapper.ITypeHandler handler)
#pragma warning restore 618 #pragma warning restore 618
: dbType; : dbType;
...@@ -496,7 +485,7 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -496,7 +485,7 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
void SqlMapper.IParameterCallbacks.OnCompleted() void SqlMapper.IParameterCallbacks.OnCompleted()
{ {
foreach (var param in (from p in parameters select p.Value)) foreach (var param in from p in parameters select p.Value)
{ {
param.OutputCallback?.Invoke(param.OutputTarget, this); param.OutputCallback?.Invoke(param.OutputTarget, this);
} }
......
...@@ -6,7 +6,7 @@ namespace Dapper ...@@ -6,7 +6,7 @@ namespace Dapper
/// <summary> /// <summary>
/// Handles variances in features per DBMS /// Handles variances in features per DBMS
/// </summary> /// </summary>
class FeatureSupport internal class FeatureSupport
{ {
private static readonly FeatureSupport private static readonly FeatureSupport
Default = new FeatureSupport(false), Default = new FeatureSupport(false),
...@@ -21,6 +21,7 @@ public static FeatureSupport Get(IDbConnection connection) ...@@ -21,6 +21,7 @@ public static FeatureSupport Get(IDbConnection connection)
if (string.Equals(name, "npgsqlconnection", StringComparison.OrdinalIgnoreCase)) return Postgres; if (string.Equals(name, "npgsqlconnection", StringComparison.OrdinalIgnoreCase)) return Postgres;
return Default; return Default;
} }
private FeatureSupport(bool arrays) private FeatureSupport(bool arrays)
{ {
Arrays = arrays; Arrays = arrays;
......
...@@ -6,7 +6,7 @@ namespace Dapper ...@@ -6,7 +6,7 @@ namespace Dapper
/// <summary> /// <summary>
/// Represents simple member map for one of target parameter or property or field to source DataReader column /// Represents simple member map for one of target parameter or property or field to source DataReader column
/// </summary> /// </summary>
sealed class SimpleMemberMap : SqlMapper.IMemberMap internal sealed class SimpleMemberMap : SqlMapper.IMemberMap
{ {
/// <summary> /// <summary>
/// Creates instance for simple property mapping /// Creates instance for simple property mapping
...@@ -15,14 +15,8 @@ sealed class SimpleMemberMap : SqlMapper.IMemberMap ...@@ -15,14 +15,8 @@ sealed class SimpleMemberMap : SqlMapper.IMemberMap
/// <param name="property">Target property</param> /// <param name="property">Target property</param>
public SimpleMemberMap(string columnName, PropertyInfo property) public SimpleMemberMap(string columnName, PropertyInfo property)
{ {
if (columnName == null) ColumnName = columnName ?? throw new ArgumentNullException(nameof(columnName));
throw new ArgumentNullException(nameof(columnName)); Property = property ?? throw new ArgumentNullException(nameof(property));
if (property == null)
throw new ArgumentNullException(nameof(property));
ColumnName = columnName;
Property = property;
} }
/// <summary> /// <summary>
...@@ -32,14 +26,8 @@ public SimpleMemberMap(string columnName, PropertyInfo property) ...@@ -32,14 +26,8 @@ public SimpleMemberMap(string columnName, PropertyInfo property)
/// <param name="field">Target property</param> /// <param name="field">Target property</param>
public SimpleMemberMap(string columnName, FieldInfo field) public SimpleMemberMap(string columnName, FieldInfo field)
{ {
if (columnName == null) ColumnName = columnName ?? throw new ArgumentNullException(nameof(columnName));
throw new ArgumentNullException(nameof(columnName)); Field = field ?? throw new ArgumentNullException(nameof(field));
if (field == null)
throw new ArgumentNullException(nameof(field));
ColumnName = columnName;
Field = field;
} }
/// <summary> /// <summary>
...@@ -49,14 +37,8 @@ public SimpleMemberMap(string columnName, FieldInfo field) ...@@ -49,14 +37,8 @@ public SimpleMemberMap(string columnName, FieldInfo field)
/// <param name="parameter">Target constructor parameter</param> /// <param name="parameter">Target constructor parameter</param>
public SimpleMemberMap(string columnName, ParameterInfo parameter) public SimpleMemberMap(string columnName, ParameterInfo parameter)
{ {
if (columnName == null) ColumnName = columnName ?? throw new ArgumentNullException(nameof(columnName));
throw new ArgumentNullException(nameof(columnName)); Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter));
if (parameter == null)
throw new ArgumentNullException(nameof(parameter));
ColumnName = columnName;
Parameter = parameter;
} }
/// <summary> /// <summary>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#if !COREFX #if !COREFX
namespace Dapper namespace Dapper
{ {
sealed class SqlDataRecordHandler : SqlMapper.ITypeHandler internal sealed class SqlDataRecordHandler : SqlMapper.ITypeHandler
{ {
public object Parse(Type destinationType, object value) public object Parse(Type destinationType, object value)
{ {
......
...@@ -8,7 +8,7 @@ namespace Dapper ...@@ -8,7 +8,7 @@ namespace Dapper
/// <summary> /// <summary>
/// Used to pass a IEnumerable&lt;SqlDataRecord&gt; as a SqlDataRecordListTVPParameter /// Used to pass a IEnumerable&lt;SqlDataRecord&gt; as a SqlDataRecordListTVPParameter
/// </summary> /// </summary>
sealed class SqlDataRecordListTVPParameter : SqlMapper.ICustomQueryParameter internal sealed class SqlDataRecordListTVPParameter : SqlMapper.ICustomQueryParameter
{ {
private readonly IEnumerable<Microsoft.SqlServer.Server.SqlDataRecord> data; private readonly IEnumerable<Microsoft.SqlServer.Server.SqlDataRecord> data;
private readonly string typeName; private readonly string typeName;
...@@ -20,7 +20,9 @@ public SqlDataRecordListTVPParameter(IEnumerable<Microsoft.SqlServer.Server.SqlD ...@@ -20,7 +20,9 @@ public SqlDataRecordListTVPParameter(IEnumerable<Microsoft.SqlServer.Server.SqlD
this.data = data; this.data = data;
this.typeName = typeName; this.typeName = typeName;
} }
static readonly Action<System.Data.SqlClient.SqlParameter, string> setTypeName;
private static readonly Action<System.Data.SqlClient.SqlParameter, string> setTypeName;
static SqlDataRecordListTVPParameter() static SqlDataRecordListTVPParameter()
{ {
var prop = typeof(System.Data.SqlClient.SqlParameter).GetProperty(nameof(System.Data.SqlClient.SqlParameter.TypeName), BindingFlags.Instance | BindingFlags.Public); var prop = typeof(System.Data.SqlClient.SqlParameter).GetProperty(nameof(System.Data.SqlClient.SqlParameter.TypeName), BindingFlags.Instance | BindingFlags.Public);
...@@ -30,6 +32,7 @@ static SqlDataRecordListTVPParameter() ...@@ -30,6 +32,7 @@ static SqlDataRecordListTVPParameter()
Delegate.CreateDelegate(typeof(Action<System.Data.SqlClient.SqlParameter, string>), prop.GetSetMethod()); Delegate.CreateDelegate(typeof(Action<System.Data.SqlClient.SqlParameter, string>), prop.GetSetMethod());
} }
} }
void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string name) void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string name)
{ {
var param = command.CreateParameter(); var param = command.CreateParameter();
...@@ -37,11 +40,11 @@ void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string nam ...@@ -37,11 +40,11 @@ void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string nam
Set(param, data, typeName); Set(param, data, typeName);
command.Parameters.Add(param); command.Parameters.Add(param);
} }
internal static void Set(IDbDataParameter parameter, IEnumerable<Microsoft.SqlServer.Server.SqlDataRecord> data, string typeName) internal static void Set(IDbDataParameter parameter, IEnumerable<Microsoft.SqlServer.Server.SqlDataRecord> data, string typeName)
{ {
parameter.Value = (object)data ?? DBNull.Value; parameter.Value = (object)data ?? DBNull.Value;
var sqlParam = parameter as System.Data.SqlClient.SqlParameter; if (parameter is System.Data.SqlClient.SqlParameter sqlParam)
if (sqlParam != null)
{ {
sqlParam.SqlDbType = SqlDbType.Structured; sqlParam.SqlDbType = SqlDbType.Structured;
sqlParam.TypeName = typeName; sqlParam.TypeName = typeName;
......
...@@ -224,6 +224,7 @@ private static Task<DbDataReader> ExecuteReaderWithFlagsFallbackAsync(DbCommand ...@@ -224,6 +224,7 @@ private static Task<DbDataReader> ExecuteReaderWithFlagsFallbackAsync(DbCommand
} }
return task; return task;
} }
private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command) private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command)
{ {
object param = command.Parameters; object param = command.Parameters;
...@@ -282,10 +283,10 @@ private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, ...@@ -282,10 +283,10 @@ private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn,
{ {
using (reader) { } // dispose if non-null using (reader) { } // dispose if non-null
if (wasClosed) cnn.Close(); if (wasClosed) cnn.Close();
} }
} }
} }
private static async Task<T> QueryRowAsync<T>(this IDbConnection cnn, Row row, Type effectiveType, CommandDefinition command) private static async Task<T> QueryRowAsync<T>(this IDbConnection cnn, Row row, Type effectiveType, CommandDefinition command)
{ {
object param = command.Parameters; object param = command.Parameters;
...@@ -379,6 +380,7 @@ public AsyncExecState(DbCommand command, Task<int> task) ...@@ -379,6 +380,7 @@ public AsyncExecState(DbCommand command, Task<int> task)
Task = task; Task = task;
} }
} }
private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandDefinition command, IEnumerable multiExec) private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandDefinition command, IEnumerable multiExec)
{ {
bool isFirst = true; bool isFirst = true;
...@@ -472,6 +474,7 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD ...@@ -472,6 +474,7 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD
} }
return total; return total;
} }
private static async Task<int> ExecuteImplAsync(IDbConnection cnn, CommandDefinition command, object param) private static async Task<int> ExecuteImplAsync(IDbConnection cnn, CommandDefinition command, object param)
{ {
var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param?.GetType(), null);
...@@ -785,10 +788,10 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, ...@@ -785,10 +788,10 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
if (reader != null) if (reader != null)
{ {
if (!reader.IsClosed) if (!reader.IsClosed)
try {
{ cmd.Cancel(); } try { cmd.Cancel(); }
catch catch { /* don't spoil the existing exception */ }
{ /* don't spoil the existing exception */ } }
reader.Dispose(); reader.Dispose();
} }
cmd?.Dispose(); cmd?.Dispose();
...@@ -797,7 +800,6 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, ...@@ -797,7 +800,6 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
} }
} }
/// <summary> /// <summary>
/// Execute parameterized SQL and return an <see cref="IDataReader"/> /// Execute parameterized SQL and return an <see cref="IDataReader"/>
/// </summary> /// </summary>
...@@ -859,7 +861,6 @@ private static async Task<IDataReader> ExecuteReaderImplAsync(IDbConnection cnn, ...@@ -859,7 +861,6 @@ private static async Task<IDataReader> ExecuteReaderImplAsync(IDbConnection cnn,
} }
} }
/// <summary> /// <summary>
/// Execute parameterized SQL that selects a single value /// Execute parameterized SQL that selects a single value
/// </summary> /// </summary>
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
class CacheInfo private class CacheInfo
{ {
public DeserializerState Deserializer { get; set; } public DeserializerState Deserializer { get; set; }
public Func<IDataReader, object>[] OtherDeserializers { get; set; } public Func<IDataReader, object>[] OtherDeserializers { get; set; }
......
...@@ -5,27 +5,27 @@ ...@@ -5,27 +5,27 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
private sealed class DapperRow private sealed class DapperRow
: System.Dynamic.IDynamicMetaObjectProvider : System.Dynamic.IDynamicMetaObjectProvider
, IDictionary<string, object> , IDictionary<string, object>
{ {
readonly DapperTable table; private readonly DapperTable table;
object[] values; private object[] values;
public DapperRow(DapperTable table, object[] values) public DapperRow(DapperTable table, object[] values)
{ {
if (table == null) throw new ArgumentNullException(nameof(table)); this.table = table ?? throw new ArgumentNullException(nameof(table));
if (values == null) throw new ArgumentNullException(nameof(values)); this.values = values ?? throw new ArgumentNullException(nameof(values));
this.table = table;
this.values = values;
} }
private sealed class DeadValue private sealed class DeadValue
{ {
public static readonly DeadValue Default = new DeadValue(); public static readonly DeadValue Default = new DeadValue();
private DeadValue() { } private DeadValue() { }
} }
int ICollection<KeyValuePair<string, object>>.Count int ICollection<KeyValuePair<string, object>>.Count
{ {
get get
...@@ -117,8 +117,7 @@ IEnumerator IEnumerable.GetEnumerator() ...@@ -117,8 +117,7 @@ IEnumerator IEnumerable.GetEnumerator()
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item) bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)
{ {
object value; return TryGetValue(item.Key, out object value) && Equals(value, item.Value);
return TryGetValue(item.Key, out value) && Equals(value, item.Value);
} }
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
...@@ -162,7 +161,7 @@ IEnumerator IEnumerable.GetEnumerator() ...@@ -162,7 +161,7 @@ IEnumerator IEnumerable.GetEnumerator()
object IDictionary<string, object>.this[string key] object IDictionary<string, object>.this[string key]
{ {
get { object val; TryGetValue(key, out val); return val; } get { TryGetValue(key, out object val); return val; }
set { SetValue(key, value, false); } set { SetValue(key, value, false); }
} }
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
using System.Reflection; using System.Reflection;
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
sealed class DapperRowMetaObject : System.Dynamic.DynamicMetaObject private sealed class DapperRowMetaObject : System.Dynamic.DynamicMetaObject
{ {
static readonly MethodInfo getValueMethod = typeof(IDictionary<string, object>).GetProperty("Item").GetGetMethod(); private static readonly MethodInfo getValueMethod = typeof(IDictionary<string, object>).GetProperty("Item").GetGetMethod();
static readonly MethodInfo setValueMethod = typeof(DapperRow).GetMethod("SetValue", new Type[] { typeof(string), typeof(object) }); private static readonly MethodInfo setValueMethod = typeof(DapperRow).GetMethod("SetValue", new Type[] { typeof(string), typeof(object) });
public DapperRowMetaObject( public DapperRowMetaObject(
System.Linq.Expressions.Expression expression, System.Linq.Expressions.Expression expression,
...@@ -27,7 +27,7 @@ object value ...@@ -27,7 +27,7 @@ object value
{ {
} }
System.Dynamic.DynamicMetaObject CallMethod( private System.Dynamic.DynamicMetaObject CallMethod(
MethodInfo method, MethodInfo method,
System.Linq.Expressions.Expression[] parameters System.Linq.Expressions.Expression[] parameters
) )
......
...@@ -3,19 +3,18 @@ ...@@ -3,19 +3,18 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
private sealed class DapperTable private sealed class DapperTable
{ {
string[] fieldNames; private string[] fieldNames;
readonly Dictionary<string, int> fieldNameLookup; private readonly Dictionary<string, int> fieldNameLookup;
internal string[] FieldNames => fieldNames; internal string[] FieldNames => fieldNames;
public DapperTable(string[] fieldNames) public DapperTable(string[] fieldNames)
{ {
if (fieldNames == null) throw new ArgumentNullException(nameof(fieldNames)); this.fieldNames = fieldNames ?? throw new ArgumentNullException(nameof(fieldNames));
this.fieldNames = fieldNames;
fieldNameLookup = new Dictionary<string, int>(fieldNames.Length, StringComparer.Ordinal); fieldNameLookup = new Dictionary<string, int>(fieldNames.Length, StringComparer.Ordinal);
// if there are dups, we want the **first** key to be the "winner" - so iterate backwards // if there are dups, we want the **first** key to be the "winner" - so iterate backwards
...@@ -28,9 +27,9 @@ public DapperTable(string[] fieldNames) ...@@ -28,9 +27,9 @@ public DapperTable(string[] fieldNames)
internal int IndexOfName(string name) internal int IndexOfName(string name)
{ {
int result; return (name != null && fieldNameLookup.TryGetValue(name, out int result)) ? result : -1;
return (name != null && fieldNameLookup.TryGetValue(name, out result)) ? result : -1;
} }
internal int AddField(string name) internal int AddField(string name)
{ {
if (name == null) throw new ArgumentNullException(nameof(name)); if (name == null) throw new ArgumentNullException(nameof(name));
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
struct DeserializerState private struct DeserializerState
{ {
public readonly int Hash; public readonly int Hash;
public readonly Func<IDataReader, object> Func; public readonly Func<IDataReader, object> Func;
......
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Dummy type for excluding from multi-map /// Dummy type for excluding from multi-map
/// </summary> /// </summary>
class DontMap { } private class DontMap { }
} }
} }
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
partial class GridReader public partial class GridReader
{ {
CancellationToken cancel; private readonly CancellationToken cancel;
internal GridReader(IDbCommand command, IDataReader reader, Identity identity, DynamicParameters dynamicParams, bool addToCache, CancellationToken cancel) internal GridReader(IDbCommand command, IDataReader reader, Identity identity, DynamicParameters dynamicParams, bool addToCache, CancellationToken cancel)
: this(command, reader, identity, dynamicParams, addToCache) : this(command, reader, identity, dynamicParams, addToCache)
{ {
...@@ -37,6 +37,7 @@ public Task<dynamic> ReadFirstAsync() ...@@ -37,6 +37,7 @@ public Task<dynamic> ReadFirstAsync()
{ {
return ReadRowAsyncImpl<dynamic>(typeof(DapperRow), Row.First); return ReadRowAsyncImpl<dynamic>(typeof(DapperRow), Row.First);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results, returned as a dynamic object /// Read an individual row of the next grid of results, returned as a dynamic object
/// </summary> /// </summary>
...@@ -45,6 +46,7 @@ public Task<dynamic> ReadFirstOrDefaultAsync() ...@@ -45,6 +46,7 @@ public Task<dynamic> ReadFirstOrDefaultAsync()
{ {
return ReadRowAsyncImpl<dynamic>(typeof(DapperRow), Row.FirstOrDefault); return ReadRowAsyncImpl<dynamic>(typeof(DapperRow), Row.FirstOrDefault);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results, returned as a dynamic object /// Read an individual row of the next grid of results, returned as a dynamic object
/// </summary> /// </summary>
...@@ -53,6 +55,7 @@ public Task<dynamic> ReadSingleAsync() ...@@ -53,6 +55,7 @@ public Task<dynamic> ReadSingleAsync()
{ {
return ReadRowAsyncImpl<dynamic>(typeof(DapperRow), Row.Single); return ReadRowAsyncImpl<dynamic>(typeof(DapperRow), Row.Single);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results, returned as a dynamic object /// Read an individual row of the next grid of results, returned as a dynamic object
/// </summary> /// </summary>
...@@ -79,6 +82,7 @@ public Task<object> ReadFirstAsync(Type type) ...@@ -79,6 +82,7 @@ public Task<object> ReadFirstAsync(Type type)
if (type == null) throw new ArgumentNullException(nameof(type)); if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRowAsyncImpl<object>(type, Row.First); return ReadRowAsyncImpl<object>(type, Row.First);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -87,6 +91,7 @@ public Task<object> ReadFirstOrDefaultAsync(Type type) ...@@ -87,6 +91,7 @@ public Task<object> ReadFirstOrDefaultAsync(Type type)
if (type == null) throw new ArgumentNullException(nameof(type)); if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRowAsyncImpl<object>(type, Row.FirstOrDefault); return ReadRowAsyncImpl<object>(type, Row.FirstOrDefault);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -95,6 +100,7 @@ public Task<object> ReadSingleAsync(Type type) ...@@ -95,6 +100,7 @@ public Task<object> ReadSingleAsync(Type type)
if (type == null) throw new ArgumentNullException(nameof(type)); if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRowAsyncImpl<object>(type, Row.Single); return ReadRowAsyncImpl<object>(type, Row.Single);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -119,6 +125,7 @@ public Task<T> ReadFirstAsync<T>() ...@@ -119,6 +125,7 @@ public Task<T> ReadFirstAsync<T>()
{ {
return ReadRowAsyncImpl<T>(typeof(T), Row.First); return ReadRowAsyncImpl<T>(typeof(T), Row.First);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -126,6 +133,7 @@ public Task<T> ReadFirstOrDefaultAsync<T>() ...@@ -126,6 +133,7 @@ public Task<T> ReadFirstOrDefaultAsync<T>()
{ {
return ReadRowAsyncImpl<T>(typeof(T), Row.FirstOrDefault); return ReadRowAsyncImpl<T>(typeof(T), Row.FirstOrDefault);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -133,6 +141,7 @@ public Task<T> ReadSingleAsync<T>() ...@@ -133,6 +141,7 @@ public Task<T> ReadSingleAsync<T>()
{ {
return ReadRowAsyncImpl<T>(typeof(T), Row.Single); return ReadRowAsyncImpl<T>(typeof(T), Row.Single);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -189,8 +198,7 @@ private Task<IEnumerable<T>> ReadAsyncImpl<T>(Type type, bool buffered) ...@@ -189,8 +198,7 @@ private Task<IEnumerable<T>> ReadAsyncImpl<T>(Type type, bool buffered)
private Task<T> ReadRowAsyncImpl<T>(Type type, Row row) private Task<T> ReadRowAsyncImpl<T>(Type type, Row row)
{ {
var dbReader = reader as DbDataReader; if (reader is DbDataReader dbReader) return ReadRowAsyncImplViaDbReader<T>(dbReader, type, row);
if (dbReader != null) return ReadRowAsyncImplViaDbReader<T>(dbReader, type, row);
// no async API available; use non-async and fake it // no async API available; use non-async and fake it
return Task.FromResult<T>(ReadRow<T>(type, row)); return Task.FromResult<T>(ReadRow<T>(type, row));
...@@ -232,7 +240,7 @@ private async Task<IEnumerable<T>> ReadBufferedAsync<T>(int index, Func<IDataRea ...@@ -232,7 +240,7 @@ private async Task<IEnumerable<T>> ReadBufferedAsync<T>(int index, Func<IDataRea
try try
{ {
var reader = (DbDataReader)this.reader; var reader = (DbDataReader)this.reader;
List<T> buffer = new List<T>(); var buffer = new List<T>();
while (index == gridIndex && await reader.ReadAsync(cancel).ConfigureAwait(false)) while (index == gridIndex && await reader.ReadAsync(cancel).ConfigureAwait(false))
{ {
buffer.Add((T)deserializer(reader)); buffer.Add((T)deserializer(reader));
...@@ -248,7 +256,6 @@ private async Task<IEnumerable<T>> ReadBufferedAsync<T>(int index, Func<IDataRea ...@@ -248,7 +256,6 @@ private async Task<IEnumerable<T>> ReadBufferedAsync<T>(int index, Func<IDataRea
} }
} }
} }
} }
} }
#endif #endif
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
using System.Globalization; using System.Globalization;
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// The grid reader provides interfaces for reading multiple result sets from a Dapper query /// The grid reader provides interfaces for reading multiple result sets from a Dapper query
...@@ -13,8 +13,8 @@ partial class SqlMapper ...@@ -13,8 +13,8 @@ partial class SqlMapper
public partial class GridReader : IDisposable public partial class GridReader : IDisposable
{ {
private IDataReader reader; private IDataReader reader;
private Identity identity; private readonly Identity identity;
private bool addToCache; private readonly bool addToCache;
internal GridReader(IDbCommand command, IDataReader reader, Identity identity, IParameterCallbacks callbacks, bool addToCache) internal GridReader(IDbCommand command, IDataReader reader, Identity identity, IParameterCallbacks callbacks, bool addToCache)
{ {
...@@ -29,80 +29,66 @@ internal GridReader(IDbCommand command, IDataReader reader, Identity identity, I ...@@ -29,80 +29,66 @@ internal GridReader(IDbCommand command, IDataReader reader, Identity identity, I
/// Read the next grid of results, returned as a dynamic object /// Read the next grid of results, returned as a dynamic object
/// </summary> /// </summary>
/// <remarks>Note: each row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks> /// <remarks>Note: each row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks>
public IEnumerable<dynamic> Read(bool buffered = true) public IEnumerable<dynamic> Read(bool buffered = true) =>
{ ReadImpl<dynamic>(typeof(DapperRow), buffered);
return ReadImpl<dynamic>(typeof(DapperRow), buffered);
}
/// <summary> /// <summary>
/// Read an individual row of the next grid of results, returned as a dynamic object /// Read an individual row of the next grid of results, returned as a dynamic object
/// </summary> /// </summary>
/// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks> /// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks>
public dynamic ReadFirst() public dynamic ReadFirst() =>
{ ReadRow<dynamic>(typeof(DapperRow), Row.First);
return ReadRow<dynamic>(typeof(DapperRow), Row.First);
}
/// <summary> /// <summary>
/// Read an individual row of the next grid of results, returned as a dynamic object /// Read an individual row of the next grid of results, returned as a dynamic object
/// </summary> /// </summary>
/// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks> /// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks>
public dynamic ReadFirstOrDefault() public dynamic ReadFirstOrDefault() =>
{ ReadRow<dynamic>(typeof(DapperRow), Row.FirstOrDefault);
return ReadRow<dynamic>(typeof(DapperRow), Row.FirstOrDefault);
}
/// <summary> /// <summary>
/// Read an individual row of the next grid of results, returned as a dynamic object /// Read an individual row of the next grid of results, returned as a dynamic object
/// </summary> /// </summary>
/// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks> /// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks>
public dynamic ReadSingle() public dynamic ReadSingle() =>
{ ReadRow<dynamic>(typeof(DapperRow), Row.Single);
return ReadRow<dynamic>(typeof(DapperRow), Row.Single);
}
/// <summary> /// <summary>
/// Read an individual row of the next grid of results, returned as a dynamic object /// Read an individual row of the next grid of results, returned as a dynamic object
/// </summary> /// </summary>
/// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks> /// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks>
public dynamic ReadSingleOrDefault() public dynamic ReadSingleOrDefault() =>
{ ReadRow<dynamic>(typeof(DapperRow), Row.SingleOrDefault);
return ReadRow<dynamic>(typeof(DapperRow), Row.SingleOrDefault);
}
/// <summary> /// <summary>
/// Read the next grid of results /// Read the next grid of results
/// </summary> /// </summary>
public IEnumerable<T> Read<T>(bool buffered = true) public IEnumerable<T> Read<T>(bool buffered = true) =>
{ ReadImpl<T>(typeof(T), buffered);
return ReadImpl<T>(typeof(T), buffered);
}
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
public T ReadFirst<T>() public T ReadFirst<T>() =>
{ ReadRow<T>(typeof(T), Row.First);
return ReadRow<T>(typeof(T), Row.First);
}
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
public T ReadFirstOrDefault<T>() public T ReadFirstOrDefault<T>() =>
{ ReadRow<T>(typeof(T), Row.FirstOrDefault);
return ReadRow<T>(typeof(T), Row.FirstOrDefault);
}
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
public T ReadSingle<T>() public T ReadSingle<T>() =>
{ ReadRow<T>(typeof(T), Row.Single);
return ReadRow<T>(typeof(T), Row.Single);
}
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
public T ReadSingleOrDefault<T>() public T ReadSingleOrDefault<T>() =>
{ ReadRow<T>(typeof(T), Row.SingleOrDefault);
return ReadRow<T>(typeof(T), Row.SingleOrDefault);
}
/// <summary> /// <summary>
/// Read the next grid of results /// Read the next grid of results
...@@ -121,6 +107,7 @@ public object ReadFirst(Type type) ...@@ -121,6 +107,7 @@ public object ReadFirst(Type type)
if (type == null) throw new ArgumentNullException(nameof(type)); if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRow<object>(type, Row.First); return ReadRow<object>(type, Row.First);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -129,6 +116,7 @@ public object ReadFirstOrDefault(Type type) ...@@ -129,6 +116,7 @@ public object ReadFirstOrDefault(Type type)
if (type == null) throw new ArgumentNullException(nameof(type)); if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRow<object>(type, Row.FirstOrDefault); return ReadRow<object>(type, Row.FirstOrDefault);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -137,6 +125,7 @@ public object ReadSingle(Type type) ...@@ -137,6 +125,7 @@ public object ReadSingle(Type type)
if (type == null) throw new ArgumentNullException(nameof(type)); if (type == null) throw new ArgumentNullException(nameof(type));
return ReadRow<object>(type, Row.Single); return ReadRow<object>(type, Row.Single);
} }
/// <summary> /// <summary>
/// Read an individual row of the next grid of results /// Read an individual row of the next grid of results
/// </summary> /// </summary>
...@@ -203,7 +192,6 @@ private T ReadRow<T>(Type type, Row row) ...@@ -203,7 +192,6 @@ private T ReadRow<T>(Type type, Row row)
return result; return result;
} }
private IEnumerable<TReturn> MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(Delegate func, string splitOn) private IEnumerable<TReturn> MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(Delegate func, string splitOn)
{ {
var identity = this.identity.ForGrid(typeof(TReturn), new Type[] { var identity = this.identity.ForGrid(typeof(TReturn), new Type[] {
...@@ -282,6 +270,7 @@ private IEnumerable<TReturn> MultiReadInternal<TReturn>(Type[] types, Func<objec ...@@ -282,6 +270,7 @@ private IEnumerable<TReturn> MultiReadInternal<TReturn>(Type[] types, Func<objec
var result = MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, DontMap, DontMap, TReturn>(func, splitOn); var result = MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, DontMap, DontMap, TReturn>(func, splitOn);
return buffered ? result.ToList() : result; return buffered ? result.ToList() : result;
} }
/// <summary> /// <summary>
/// Read multiple objects from a single record set on the grid /// Read multiple objects from a single record set on the grid
/// </summary> /// </summary>
...@@ -290,6 +279,7 @@ private IEnumerable<TReturn> MultiReadInternal<TReturn>(Type[] types, Func<objec ...@@ -290,6 +279,7 @@ private IEnumerable<TReturn> MultiReadInternal<TReturn>(Type[] types, Func<objec
var result = MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, DontMap, TReturn>(func, splitOn); var result = MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, DontMap, TReturn>(func, splitOn);
return buffered ? result.ToList() : result; return buffered ? result.ToList() : result;
} }
/// <summary> /// <summary>
/// Read multiple objects from a single record set on the grid /// Read multiple objects from a single record set on the grid
/// </summary> /// </summary>
...@@ -331,8 +321,9 @@ private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, object> dese ...@@ -331,8 +321,9 @@ private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, object> dese
} }
} }
} }
private int gridIndex, readCount; private int gridIndex, readCount;
private IParameterCallbacks callbacks; private readonly IParameterCallbacks callbacks;
/// <summary> /// <summary>
/// Has the underlying reader been consumed? /// Has the underlying reader been consumed?
...@@ -362,6 +353,7 @@ private void NextResult() ...@@ -362,6 +353,7 @@ private void NextResult()
Dispose(); Dispose();
} }
} }
/// <summary> /// <summary>
/// Dispose the grid, closing and disposing both the underlying reader and command. /// Dispose the grid, closing and disposing both the underlying reader and command.
/// </summary> /// </summary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Implement this interface to pass an arbitrary db specific parameter to Dapper /// Implement this interface to pass an arbitrary db specific parameter to Dapper
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Parses a data reader to a sequence of data of the supplied type. Used for deserializing a reader without a connection, etc. /// Parses a data reader to a sequence of data of the supplied type. Used for deserializing a reader without a connection, etc.
...@@ -122,7 +122,7 @@ public static IEnumerable<dynamic> Parse(this IDataReader reader) ...@@ -122,7 +122,7 @@ public static IEnumerable<dynamic> Parse(this IDataReader reader)
public static Func<IDataReader, T> GetRowParser<T>(this IDataReader reader, Type concreteType = null, public static Func<IDataReader, T> GetRowParser<T>(this IDataReader reader, Type concreteType = null,
int startIndex = 0, int length = -1, bool returnNullIfFirstMissing = false) int startIndex = 0, int length = -1, bool returnNullIfFirstMissing = false)
{ {
if (concreteType == null) concreteType = typeof(T); concreteType = concreteType ?? typeof(T);
var func = GetDeserializer(concreteType, reader, startIndex, length, returnNullIfFirstMissing); var func = GetDeserializer(concreteType, reader, startIndex, length, returnNullIfFirstMissing);
if (concreteType.IsValueType()) if (concreteType.IsValueType())
{ {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Implement this interface to pass an arbitrary db specific set of parameters to Dapper /// Implement this interface to pass an arbitrary db specific set of parameters to Dapper
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Implements this interface to provide custom member mapping /// Implements this interface to provide custom member mapping
......
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Extends IDynamicParameters with facilities for executing callbacks after commands have completed /// Extends IDynamicParameters with facilities for executing callbacks after commands have completed
......
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Extends IDynamicParameters providing by-name lookup of parameter values /// Extends IDynamicParameters providing by-name lookup of parameter values
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Implement this interface to perform custom type-based parameter handling and value parsing /// Implement this interface to perform custom type-based parameter handling and value parsing
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Implement this interface to change default mapping of reader columns to type members /// Implement this interface to change default mapping of reader columns to type members
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Identity of a cached query in Dapper, used for extensibility /// Identity of a cached query in Dapper, used for extensibility
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), /// This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example),
...@@ -25,14 +25,14 @@ public static bool TryGet(Link<TKey, TValue> link, TKey key, out TValue value) ...@@ -25,14 +25,14 @@ public static bool TryGet(Link<TKey, TValue> link, TKey key, out TValue value)
value = default(TValue); value = default(TValue);
return false; return false;
} }
public static bool TryAdd(ref Link<TKey, TValue> head, TKey key, ref TValue value) public static bool TryAdd(ref Link<TKey, TValue> head, TKey key, ref TValue value)
{ {
bool tryAgain; bool tryAgain;
do do
{ {
var snapshot = Interlocked.CompareExchange(ref head, null, null); var snapshot = Interlocked.CompareExchange(ref head, null, null);
TValue found; if (TryGet(snapshot, key, out TValue found))
if (TryGet(snapshot, key, out found))
{ // existing match; report the existing value instead { // existing match; report the existing value instead
value = found; value = found;
return false; return false;
...@@ -43,12 +43,14 @@ public static bool TryAdd(ref Link<TKey, TValue> head, TKey key, ref TValue valu ...@@ -43,12 +43,14 @@ public static bool TryAdd(ref Link<TKey, TValue> head, TKey key, ref TValue valu
} while (tryAgain); } while (tryAgain);
return true; return true;
} }
private Link(TKey key, TValue value, Link<TKey, TValue> tail) private Link(TKey key, TValue value, Link<TKey, TValue> tail)
{ {
Key = key; Key = key;
Value = value; Value = value;
Tail = tail; Tail = tail;
} }
public TKey Key { get; } public TKey Key { get; }
public TValue Value { get; } public TValue Value { get; }
public Link<TKey, TValue> Tail { get; } public Link<TKey, TValue> Tail { get; }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Represents a placeholder for a value that should be replaced as a literal value in the resulting sql /// Represents a placeholder for a value that should be replaced as a literal value in the resulting sql
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Permits specifying certain SqlMapper values globally. /// Permits specifying certain SqlMapper values globally.
...@@ -11,7 +11,7 @@ partial class SqlMapper ...@@ -11,7 +11,7 @@ partial class SqlMapper
public static class Settings public static class Settings
{ {
// disable single result by default; prevents errors AFTER the select being detected properly // disable single result by default; prevents errors AFTER the select being detected properly
const CommandBehavior DefaultAllowedCommandBehaviors = ~CommandBehavior.SingleResult; private const CommandBehavior DefaultAllowedCommandBehaviors = ~CommandBehavior.SingleResult;
internal static CommandBehavior AllowedCommandBehaviors { get; private set; } = DefaultAllowedCommandBehaviors; internal static CommandBehavior AllowedCommandBehaviors { get; private set; } = DefaultAllowedCommandBehaviors;
private static void SetAllowedCommandBehaviors(CommandBehavior behavior, bool enabled) private static void SetAllowedCommandBehaviors(CommandBehavior behavior, bool enabled)
{ {
...@@ -36,6 +36,7 @@ public static bool UseSingleRowOptimization ...@@ -36,6 +36,7 @@ public static bool UseSingleRowOptimization
get { return (AllowedCommandBehaviors & CommandBehavior.SingleRow) != 0; } get { return (AllowedCommandBehaviors & CommandBehavior.SingleRow) != 0; }
set { SetAllowedCommandBehaviors(CommandBehavior.SingleRow, value); } set { SetAllowedCommandBehaviors(CommandBehavior.SingleRow, value); }
} }
internal static bool DisableCommandBehaviorOptimizations(CommandBehavior behavior, Exception ex) internal static bool DisableCommandBehaviorOptimizations(CommandBehavior behavior, Exception ex)
{ {
if (AllowedCommandBehaviors == DefaultAllowedCommandBehaviors if (AllowedCommandBehaviors == DefaultAllowedCommandBehaviors
...@@ -75,7 +76,6 @@ public static void SetDefaults() ...@@ -75,7 +76,6 @@ public static void SetDefaults()
/// </summary> /// </summary>
public static bool ApplyNullValues { get; set; } public static bool ApplyNullValues { get; set; }
/// <summary> /// <summary>
/// Should list expansions be padded with null-valued parameters, to prevent query-plan saturation? For example, /// Should list expansions be padded with null-valued parameters, to prevent query-plan saturation? For example,
/// an 'in @foo' expansion with 7, 8 or 9 values will be sent as a list of 10 values, with 3, 2 or 1 of them null. /// an 'in @foo' expansion with 7, 8 or 9 values will be sent as a list of 10 values, with 3, 2 or 1 of them null.
......
...@@ -6,16 +6,16 @@ ...@@ -6,16 +6,16 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
private class TypeDeserializerCache private class TypeDeserializerCache
{ {
private TypeDeserializerCache(Type type) private TypeDeserializerCache(Type type)
{ {
this.type = type; this.type = type;
} }
static readonly Hashtable byType = new Hashtable();
private static readonly Hashtable byType = new Hashtable();
private readonly Type type; private readonly Type type;
internal static void Purge(Type type) internal static void Purge(Type type)
{ {
...@@ -24,6 +24,7 @@ internal static void Purge(Type type) ...@@ -24,6 +24,7 @@ internal static void Purge(Type type)
byType.Remove(type); byType.Remove(type);
} }
} }
internal static void Purge() internal static void Purge()
{ {
lock (byType) lock (byType)
...@@ -48,8 +49,10 @@ internal static void Purge() ...@@ -48,8 +49,10 @@ internal static void Purge()
} }
return found.GetReader(reader, startBound, length, returnNullIfFirstMissing); return found.GetReader(reader, startBound, length, returnNullIfFirstMissing);
} }
private Dictionary<DeserializerKey, Func<IDataReader, object>> readers = new Dictionary<DeserializerKey, Func<IDataReader, object>>();
struct DeserializerKey : IEquatable<DeserializerKey> private readonly Dictionary<DeserializerKey, Func<IDataReader, object>> readers = new Dictionary<DeserializerKey, Func<IDataReader, object>>();
private struct DeserializerKey : IEquatable<DeserializerKey>
{ {
private readonly int startBound, length; private readonly int startBound, length;
private readonly bool returnNullIfFirstMissing; private readonly bool returnNullIfFirstMissing;
...@@ -85,10 +88,8 @@ public DeserializerKey(int hashCode, int startBound, int length, bool returnNull ...@@ -85,10 +88,8 @@ public DeserializerKey(int hashCode, int startBound, int length, bool returnNull
} }
} }
public override int GetHashCode() public override int GetHashCode() => hashCode;
{
return hashCode;
}
public override string ToString() public override string ToString()
{ // only used in the debugger { // only used in the debugger
if (names != null) if (names != null)
...@@ -108,24 +109,26 @@ public override string ToString() ...@@ -108,24 +109,26 @@ public override string ToString()
} }
return base.ToString(); return base.ToString();
} }
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return obj is DeserializerKey && Equals((DeserializerKey)obj); return obj is DeserializerKey && Equals((DeserializerKey)obj);
} }
public bool Equals(DeserializerKey other) public bool Equals(DeserializerKey other)
{ {
if (this.hashCode != other.hashCode if (hashCode != other.hashCode
|| this.startBound != other.startBound || startBound != other.startBound
|| this.length != other.length || length != other.length
|| this.returnNullIfFirstMissing != other.returnNullIfFirstMissing) || returnNullIfFirstMissing != other.returnNullIfFirstMissing)
{ {
return false; // clearly different return false; // clearly different
} }
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
if ((this.names?[i] ?? this.reader?.GetName(startBound + i)) != (other.names?[i] ?? other.reader?.GetName(startBound + i)) if ((names?[i] ?? reader?.GetName(startBound + i)) != (other.names?[i] ?? other.reader?.GetName(startBound + i))
|| ||
(this.types?[i] ?? this.reader?.GetFieldType(startBound + i)) != (other.types?[i] ?? other.reader?.GetFieldType(startBound + i)) (types?[i] ?? reader?.GetFieldType(startBound + i)) != (other.types?[i] ?? other.reader?.GetFieldType(startBound + i))
) )
{ {
return false; // different column name or type return false; // different column name or type
...@@ -134,6 +137,7 @@ public bool Equals(DeserializerKey other) ...@@ -134,6 +137,7 @@ public bool Equals(DeserializerKey other)
return true; return true;
} }
} }
private Func<IDataReader, object> GetReader(IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing) private Func<IDataReader, object> GetReader(IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
{ {
if (length < 0) length = reader.FieldCount - startBound; if (length < 0) length = reader.FieldCount - startBound;
...@@ -155,6 +159,5 @@ public bool Equals(DeserializerKey other) ...@@ -155,6 +159,5 @@ public bool Equals(DeserializerKey other)
} }
} }
} }
} }
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Base-class for simple type-handlers /// Base-class for simple type-handlers
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
/// <summary> /// <summary>
/// Not intended for direct usage /// Not intended for direct usage
......
...@@ -25,13 +25,12 @@ ...@@ -25,13 +25,12 @@
namespace Dapper namespace Dapper
{ {
/// <summary> /// <summary>
/// Dapper, a light weight object mapper for ADO.NET /// Dapper, a light weight object mapper for ADO.NET
/// </summary> /// </summary>
public static partial class SqlMapper public static partial class SqlMapper
{ {
static int GetColumnHash(IDataReader reader, int startBound = 0, int length = -1) private static int GetColumnHash(IDataReader reader, int startBound = 0, int length = -1)
{ {
unchecked unchecked
{ {
...@@ -40,13 +39,12 @@ static int GetColumnHash(IDataReader reader, int startBound = 0, int length = -1 ...@@ -40,13 +39,12 @@ static int GetColumnHash(IDataReader reader, int startBound = 0, int length = -1
for (int i = startBound; i < max; i++) for (int i = startBound; i < max; i++)
{ {
object tmp = reader.GetName(i); object tmp = reader.GetName(i);
hash = -79 * ((hash * 31) + (tmp?.GetHashCode() ?? 0)) + (reader.GetFieldType(i)?.GetHashCode() ?? 0); hash = (-79 * ((hash * 31) + (tmp?.GetHashCode() ?? 0))) + (reader.GetFieldType(i)?.GetHashCode() ?? 0);
} }
return hash; return hash;
} }
} }
/// <summary> /// <summary>
/// Called if the query cache is purged via PurgeQueryCache /// Called if the query cache is purged via PurgeQueryCache
/// </summary> /// </summary>
...@@ -57,7 +55,7 @@ private static void OnQueryCachePurged() ...@@ -57,7 +55,7 @@ private static void OnQueryCachePurged()
handler?.Invoke(null, EventArgs.Empty); handler?.Invoke(null, EventArgs.Empty);
} }
static readonly System.Collections.Concurrent.ConcurrentDictionary<Identity, CacheInfo> _queryCache = new System.Collections.Concurrent.ConcurrentDictionary<Identity, CacheInfo>(); private static readonly System.Collections.Concurrent.ConcurrentDictionary<Identity, CacheInfo> _queryCache = new System.Collections.Concurrent.ConcurrentDictionary<Identity, CacheInfo>();
private static void SetQueryCache(Identity key, CacheInfo value) private static void SetQueryCache(Identity key, CacheInfo value)
{ {
if (Interlocked.Increment(ref collect) == COLLECT_PER_ITEMS) if (Interlocked.Increment(ref collect) == COLLECT_PER_ITEMS)
...@@ -75,8 +73,7 @@ private static void CollectCacheGarbage() ...@@ -75,8 +73,7 @@ private static void CollectCacheGarbage()
{ {
if (pair.Value.GetHitCount() <= COLLECT_HIT_COUNT_MIN) if (pair.Value.GetHitCount() <= COLLECT_HIT_COUNT_MIN)
{ {
CacheInfo cache; _queryCache.TryRemove(pair.Key, out CacheInfo cache);
_queryCache.TryRemove(pair.Key, out cache);
} }
} }
} }
...@@ -114,9 +111,8 @@ private static void PurgeQueryCacheByType(Type type) ...@@ -114,9 +111,8 @@ private static void PurgeQueryCacheByType(Type type)
{ {
foreach (var entry in _queryCache) foreach (var entry in _queryCache)
{ {
CacheInfo cache;
if (entry.Key.type == type) if (entry.Key.type == type)
_queryCache.TryRemove(entry.Key, out cache); _queryCache.TryRemove(entry.Key, out CacheInfo cache);
} }
TypeDeserializerCache.Purge(type); TypeDeserializerCache.Purge(type);
} }
...@@ -138,8 +134,9 @@ public static int GetCachedSQLCount() ...@@ -138,8 +134,9 @@ public static int GetCachedSQLCount()
public static IEnumerable<Tuple<string, string, int>> GetCachedSQL(int ignoreHitCountAbove = int.MaxValue) public static IEnumerable<Tuple<string, string, int>> GetCachedSQL(int ignoreHitCountAbove = int.MaxValue)
{ {
var data = _queryCache.Select(pair => Tuple.Create(pair.Key.connectionString, pair.Key.sql, pair.Value.GetHitCount())); var data = _queryCache.Select(pair => Tuple.Create(pair.Key.connectionString, pair.Key.sql, pair.Value.GetHitCount()));
if (ignoreHitCountAbove < int.MaxValue) data = data.Where(tuple => tuple.Item3 <= ignoreHitCountAbove); return (ignoreHitCountAbove < int.MaxValue)
return data; ? data.Where(tuple => tuple.Item3 <= ignoreHitCountAbove)
: data;
} }
/// <summary> /// <summary>
...@@ -151,8 +148,7 @@ public static int GetCachedSQLCount() ...@@ -151,8 +148,7 @@ public static int GetCachedSQLCount()
var counts = new Dictionary<int, int>(); var counts = new Dictionary<int, int>();
foreach (var key in _queryCache.Keys) foreach (var key in _queryCache.Keys)
{ {
int count; if (!counts.TryGetValue(key.hashCode, out int count))
if (!counts.TryGetValue(key.hashCode, out count))
{ {
counts.Add(key.hashCode, 1); counts.Add(key.hashCode, 1);
} }
...@@ -164,11 +160,9 @@ public static int GetCachedSQLCount() ...@@ -164,11 +160,9 @@ public static int GetCachedSQLCount()
return from pair in counts return from pair in counts
where pair.Value > 1 where pair.Value > 1
select Tuple.Create(pair.Key, pair.Value); select Tuple.Create(pair.Key, pair.Value);
} }
private static Dictionary<Type, DbType> typeMap;
static Dictionary<Type, DbType> typeMap;
static SqlMapper() static SqlMapper()
{ {
...@@ -218,10 +212,8 @@ static SqlMapper() ...@@ -218,10 +212,8 @@ static SqlMapper()
/// <summary> /// <summary>
/// Clear the registered type handlers /// Clear the registered type handlers
/// </summary> /// </summary>
public static void ResetTypeHandlers() public static void ResetTypeHandlers() => ResetTypeHandlers(true);
{
ResetTypeHandlers(true);
}
private static void ResetTypeHandlers(bool clone) private static void ResetTypeHandlers(bool clone)
{ {
typeHandlers = new Dictionary<Type, ITypeHandler>(); typeHandlers = new Dictionary<Type, ITypeHandler>();
...@@ -237,6 +229,7 @@ private static void ResetTypeHandlers(bool clone) ...@@ -237,6 +229,7 @@ private static void ResetTypeHandlers(bool clone)
AddTypeHandlerImpl(typeof(XDocument), new XDocumentHandler(), clone); AddTypeHandlerImpl(typeof(XDocument), new XDocumentHandler(), clone);
AddTypeHandlerImpl(typeof(XElement), new XElementHandler(), clone); AddTypeHandlerImpl(typeof(XElement), new XElementHandler(), clone);
} }
#if !COREFX #if !COREFX
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private static void AddSqlDataRecordsTypeHandler(bool clone) private static void AddSqlDataRecordsTypeHandler(bool clone)
...@@ -253,11 +246,9 @@ public static void AddTypeMap(Type type, DbType dbType) ...@@ -253,11 +246,9 @@ public static void AddTypeMap(Type type, DbType dbType)
// use clone, mutate, replace to avoid threading issues // use clone, mutate, replace to avoid threading issues
var snapshot = typeMap; var snapshot = typeMap;
DbType oldValue; if (snapshot.TryGetValue(type, out DbType oldValue) && oldValue == dbType) return; // nothing to do
if (snapshot.TryGetValue(type, out oldValue) && oldValue == dbType) return; // nothing to do
var newCopy = new Dictionary<Type, DbType>(snapshot) { [type] = dbType }; typeMap = new Dictionary<Type, DbType>(snapshot) { [type] = dbType };
typeMap = newCopy;
} }
/// <summary> /// <summary>
...@@ -279,15 +270,9 @@ public static void RemoveTypeMap(Type type) ...@@ -279,15 +270,9 @@ public static void RemoveTypeMap(Type type)
/// <summary> /// <summary>
/// Configure the specified type to be processed by a custom handler /// Configure the specified type to be processed by a custom handler
/// </summary> /// </summary>
public static void AddTypeHandler(Type type, ITypeHandler handler) public static void AddTypeHandler(Type type, ITypeHandler handler) => AddTypeHandlerImpl(type, handler, true);
{
AddTypeHandlerImpl(type, handler, true);
}
internal static bool HasTypeHandler(Type type) internal static bool HasTypeHandler(Type type) => typeHandlers.ContainsKey(type);
{
return typeHandlers.ContainsKey(type);
}
/// <summary> /// <summary>
/// Configure the specified type to be processed by a custom handler /// Configure the specified type to be processed by a custom handler
...@@ -313,8 +298,7 @@ public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clon ...@@ -313,8 +298,7 @@ public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clon
} }
var snapshot = typeHandlers; var snapshot = typeHandlers;
ITypeHandler oldValue; if (snapshot.TryGetValue(type, out ITypeHandler oldValue) && handler == oldValue) return; // nothing to do
if (snapshot.TryGetValue(type, out oldValue) && handler == oldValue) return; // nothing to do
var newCopy = clone ? new Dictionary<Type, ITypeHandler>(snapshot) : snapshot; var newCopy = clone ? new Dictionary<Type, ITypeHandler>(snapshot) : snapshot;
...@@ -341,10 +325,8 @@ public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clon ...@@ -341,10 +325,8 @@ public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clon
/// <summary> /// <summary>
/// Configure the specified type to be processed by a custom handler /// Configure the specified type to be processed by a custom handler
/// </summary> /// </summary>
public static void AddTypeHandler<T>(TypeHandler<T> handler) public static void AddTypeHandler<T>(TypeHandler<T> handler) =>
{
AddTypeHandlerImpl(typeof(T), handler, true); AddTypeHandlerImpl(typeof(T), handler, true);
}
private static Dictionary<Type, ITypeHandler> typeHandlers; private static Dictionary<Type, ITypeHandler> typeHandlers;
...@@ -364,9 +346,7 @@ public static DbType GetDbType(object value) ...@@ -364,9 +346,7 @@ public static DbType GetDbType(object value)
{ {
if (value == null || value is DBNull) return DbType.Object; if (value == null || value is DBNull) return DbType.Object;
ITypeHandler handler; return LookupDbType(value.GetType(), "n/a", false, out ITypeHandler handler);
return LookupDbType(value.GetType(), "n/a", false, out handler);
} }
/// <summary> /// <summary>
...@@ -379,7 +359,6 @@ public static DbType GetDbType(object value) ...@@ -379,7 +359,6 @@ public static DbType GetDbType(object value)
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public static DbType LookupDbType(Type type, string name, bool demand, out ITypeHandler handler) public static DbType LookupDbType(Type type, string name, bool demand, out ITypeHandler handler)
{ {
DbType dbType;
handler = null; handler = null;
var nullUnderlyingType = Nullable.GetUnderlyingType(type); var nullUnderlyingType = Nullable.GetUnderlyingType(type);
if (nullUnderlyingType != null) type = nullUnderlyingType; if (nullUnderlyingType != null) type = nullUnderlyingType;
...@@ -387,7 +366,7 @@ public static DbType LookupDbType(Type type, string name, bool demand, out IType ...@@ -387,7 +366,7 @@ public static DbType LookupDbType(Type type, string name, bool demand, out IType
{ {
type = Enum.GetUnderlyingType(type); type = Enum.GetUnderlyingType(type);
} }
if (typeMap.TryGetValue(type, out dbType)) if (typeMap.TryGetValue(type, out DbType dbType))
{ {
return dbType; return dbType;
} }
...@@ -421,19 +400,14 @@ public static DbType LookupDbType(Type type, string name, bool demand, out IType ...@@ -421,19 +400,14 @@ public static DbType LookupDbType(Type type, string name, bool demand, out IType
if(demand) if(demand)
throw new NotSupportedException($"The member {name} of type {type.FullName} cannot be used as a parameter value"); throw new NotSupportedException($"The member {name} of type {type.FullName} cannot be used as a parameter value");
return DbType.Object; return DbType.Object;
} }
/// <summary> /// <summary>
/// Obtains the data as a list; if it is *already* a list, the original object is returned without /// Obtains the data as a list; if it is *already* a list, the original object is returned without
/// any duplication; otherwise, ToList() is invoked. /// any duplication; otherwise, ToList() is invoked.
/// </summary> /// </summary>
public static List<T> AsList<T>(this IEnumerable<T> source) public static List<T> AsList<T>(this IEnumerable<T> source) =>
{ (source == null || source is List<T>) ? (List<T>)source : source.ToList();
return (source == null || source is List<T>) ? (List<T>)source : source.ToList();
}
/// <summary> /// <summary>
/// Execute parameterized SQL /// Execute parameterized SQL
...@@ -450,11 +424,7 @@ public static List<T> AsList<T>(this IEnumerable<T> source) ...@@ -450,11 +424,7 @@ public static List<T> AsList<T>(this IEnumerable<T> source)
/// Execute parameterized SQL /// Execute parameterized SQL
/// </summary> /// </summary>
/// <returns>Number of rows affected</returns> /// <returns>Number of rows affected</returns>
public static int Execute(this IDbConnection cnn, CommandDefinition command) public static int Execute(this IDbConnection cnn, CommandDefinition command) => ExecuteImpl(cnn, ref command);
{
return ExecuteImpl(cnn, ref command);
}
/// <summary> /// <summary>
/// Execute parameterized SQL that selects a single value /// Execute parameterized SQL that selects a single value
...@@ -484,26 +454,22 @@ public static int Execute(this IDbConnection cnn, CommandDefinition command) ...@@ -484,26 +454,22 @@ public static int Execute(this IDbConnection cnn, CommandDefinition command)
/// Execute parameterized SQL that selects a single value /// Execute parameterized SQL that selects a single value
/// </summary> /// </summary>
/// <returns>The first cell selected</returns> /// <returns>The first cell selected</returns>
public static object ExecuteScalar(this IDbConnection cnn, CommandDefinition command) public static object ExecuteScalar(this IDbConnection cnn, CommandDefinition command) =>
{ ExecuteScalarImpl<object>(cnn, ref command);
return ExecuteScalarImpl<object>(cnn, ref command);
}
/// <summary> /// <summary>
/// Execute parameterized SQL that selects a single value /// Execute parameterized SQL that selects a single value
/// </summary> /// </summary>
/// <returns>The first cell selected</returns> /// <returns>The first cell selected</returns>
public static T ExecuteScalar<T>(this IDbConnection cnn, CommandDefinition command) public static T ExecuteScalar<T>(this IDbConnection cnn, CommandDefinition command) =>
{ ExecuteScalarImpl<T>(cnn, ref command);
return ExecuteScalarImpl<T>(cnn, ref command);
}
private static IEnumerable GetMultiExec(object param) private static IEnumerable GetMultiExec(object param)
{ {
return (param is IEnumerable && return (param is IEnumerable
!(param is string || && !(param is string
param is IEnumerable<KeyValuePair<string, object>> || || param is IEnumerable<KeyValuePair<string, object>>
param is IDynamicParameters) || param is IDynamicParameters)
) ? (IEnumerable) param : null; ) ? (IEnumerable) param : null;
} }
...@@ -590,8 +556,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com ...@@ -590,8 +556,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
) )
{ {
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);
IDbCommand dbcmd; var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out IDbCommand dbcmd);
var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out dbcmd);
return new WrappedReader(dbcmd, reader); return new WrappedReader(dbcmd, reader);
} }
...@@ -605,8 +570,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com ...@@ -605,8 +570,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
/// </remarks> /// </remarks>
public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command) public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command)
{ {
IDbCommand dbcmd; var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out IDbCommand dbcmd);
var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out dbcmd);
return new WrappedReader(dbcmd, reader); return new WrappedReader(dbcmd, reader);
} }
/// <summary> /// <summary>
...@@ -619,8 +583,7 @@ public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinitio ...@@ -619,8 +583,7 @@ public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinitio
/// </remarks> /// </remarks>
public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior) public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)
{ {
IDbCommand dbcmd; var reader = ExecuteReaderImpl(cnn, ref command, commandBehavior, out IDbCommand dbcmd);
var reader = ExecuteReaderImpl(cnn, ref command, commandBehavior, out dbcmd);
return new WrappedReader(dbcmd, reader); return new WrappedReader(dbcmd, reader);
} }
...@@ -641,6 +604,7 @@ public static dynamic QueryFirst(this IDbConnection cnn, string sql, object para ...@@ -641,6 +604,7 @@ public static dynamic QueryFirst(this IDbConnection cnn, string sql, object para
{ {
return QueryFirst<DapperRow>(cnn, sql, param as object, transaction, commandTimeout, commandType); return QueryFirst<DapperRow>(cnn, sql, param as object, transaction, commandTimeout, commandType);
} }
/// <summary> /// <summary>
/// Return a dynamic object with properties matching the columns /// Return a dynamic object with properties matching the columns
/// </summary> /// </summary>
...@@ -649,6 +613,7 @@ public static dynamic QueryFirstOrDefault(this IDbConnection cnn, string sql, ob ...@@ -649,6 +613,7 @@ public static dynamic QueryFirstOrDefault(this IDbConnection cnn, string sql, ob
{ {
return QueryFirstOrDefault<DapperRow>(cnn, sql, param as object, transaction, commandTimeout, commandType); return QueryFirstOrDefault<DapperRow>(cnn, sql, param as object, transaction, commandTimeout, commandType);
} }
/// <summary> /// <summary>
/// Return a dynamic object with properties matching the columns /// Return a dynamic object with properties matching the columns
/// </summary> /// </summary>
...@@ -657,6 +622,7 @@ public static dynamic QuerySingle(this IDbConnection cnn, string sql, object par ...@@ -657,6 +622,7 @@ public static dynamic QuerySingle(this IDbConnection cnn, string sql, object par
{ {
return QuerySingle<DapperRow>(cnn, sql, param as object, transaction, commandTimeout, commandType); return QuerySingle<DapperRow>(cnn, sql, param as object, transaction, commandTimeout, commandType);
} }
/// <summary> /// <summary>
/// Return a dynamic object with properties matching the columns /// Return a dynamic object with properties matching the columns
/// </summary> /// </summary>
...@@ -694,6 +660,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o ...@@ -694,6 +660,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl<T>(cnn, Row.First, ref command, typeof(T)); return QueryRowImpl<T>(cnn, Row.First, ref command, typeof(T));
} }
/// <summary> /// <summary>
/// Executes a single-row query, returning the data typed as per T /// Executes a single-row query, returning the data typed as per T
/// </summary> /// </summary>
...@@ -707,6 +674,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o ...@@ -707,6 +674,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl<T>(cnn, Row.FirstOrDefault, ref command, typeof(T)); return QueryRowImpl<T>(cnn, Row.FirstOrDefault, ref command, typeof(T));
} }
/// <summary> /// <summary>
/// Executes a single-row query, returning the data typed as per T /// Executes a single-row query, returning the data typed as per T
/// </summary> /// </summary>
...@@ -749,6 +717,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o ...@@ -749,6 +717,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o
var data = QueryImpl<object>(cnn, command, type); var data = QueryImpl<object>(cnn, command, type);
return command.Buffered ? data.ToList() : data; return command.Buffered ? data.ToList() : data;
} }
/// <summary> /// <summary>
/// Executes a single-row query, returning the data typed as per the Type suggested /// Executes a single-row query, returning the data typed as per the Type suggested
/// </summary> /// </summary>
...@@ -763,6 +732,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o ...@@ -763,6 +732,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl<object>(cnn, Row.First, ref command, type); return QueryRowImpl<object>(cnn, Row.First, ref command, type);
} }
/// <summary> /// <summary>
/// Executes a single-row query, returning the data typed as per the Type suggested /// Executes a single-row query, returning the data typed as per the Type suggested
/// </summary> /// </summary>
...@@ -777,6 +747,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o ...@@ -777,6 +747,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl<object>(cnn, Row.FirstOrDefault, ref command, type); return QueryRowImpl<object>(cnn, Row.FirstOrDefault, ref command, type);
} }
/// <summary> /// <summary>
/// Executes a single-row query, returning the data typed as per the Type suggested /// Executes a single-row query, returning the data typed as per the Type suggested
/// </summary> /// </summary>
...@@ -791,6 +762,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o ...@@ -791,6 +762,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl<object>(cnn, Row.Single, ref command, type); return QueryRowImpl<object>(cnn, Row.Single, ref command, type);
} }
/// <summary> /// <summary>
/// Executes a single-row query, returning the data typed as per the Type suggested /// Executes a single-row query, returning the data typed as per the Type suggested
/// </summary> /// </summary>
...@@ -805,6 +777,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o ...@@ -805,6 +777,7 @@ public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, o
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None);
return QueryRowImpl<object>(cnn, Row.SingleOrDefault, ref command, type); return QueryRowImpl<object>(cnn, Row.SingleOrDefault, ref command, type);
} }
/// <summary> /// <summary>
/// Executes a query, returning the data typed as per T /// Executes a query, returning the data typed as per T
/// </summary> /// </summary>
...@@ -829,6 +802,7 @@ public static T QueryFirst<T>(this IDbConnection cnn, CommandDefinition command) ...@@ -829,6 +802,7 @@ public static T QueryFirst<T>(this IDbConnection cnn, CommandDefinition command)
{ {
return QueryRowImpl<T>(cnn, Row.First, ref command, typeof(T)); return QueryRowImpl<T>(cnn, Row.First, ref command, typeof(T));
} }
/// <summary> /// <summary>
/// Executes a query, returning the data typed as per T /// Executes a query, returning the data typed as per T
/// </summary> /// </summary>
...@@ -840,6 +814,7 @@ public static T QueryFirstOrDefault<T>(this IDbConnection cnn, CommandDefinition ...@@ -840,6 +814,7 @@ public static T QueryFirstOrDefault<T>(this IDbConnection cnn, CommandDefinition
{ {
return QueryRowImpl<T>(cnn, Row.FirstOrDefault, ref command, typeof(T)); return QueryRowImpl<T>(cnn, Row.FirstOrDefault, ref command, typeof(T));
} }
/// <summary> /// <summary>
/// Executes a query, returning the data typed as per T /// Executes a query, returning the data typed as per T
/// </summary> /// </summary>
...@@ -851,6 +826,7 @@ public static T QuerySingle<T>(this IDbConnection cnn, CommandDefinition command ...@@ -851,6 +826,7 @@ public static T QuerySingle<T>(this IDbConnection cnn, CommandDefinition command
{ {
return QueryRowImpl<T>(cnn, Row.Single, ref command, typeof(T)); return QueryRowImpl<T>(cnn, Row.Single, ref command, typeof(T));
} }
/// <summary> /// <summary>
/// Executes a query, returning the data typed as per T /// Executes a query, returning the data typed as per T
/// </summary> /// </summary>
...@@ -863,7 +839,6 @@ public static T QuerySingleOrDefault<T>(this IDbConnection cnn, CommandDefinitio ...@@ -863,7 +839,6 @@ public static T QuerySingleOrDefault<T>(this IDbConnection cnn, CommandDefinitio
return QueryRowImpl<T>(cnn, Row.SingleOrDefault, ref command, typeof(T)); return QueryRowImpl<T>(cnn, Row.SingleOrDefault, ref command, typeof(T));
} }
/// <summary> /// <summary>
/// Execute a command that returns multiple result sets, and access each in turn /// Execute a command that returns multiple result sets, and access each in turn
/// </summary> /// </summary>
...@@ -874,18 +849,17 @@ public static T QuerySingleOrDefault<T>(this IDbConnection cnn, CommandDefinitio ...@@ -874,18 +849,17 @@ public static T QuerySingleOrDefault<T>(this IDbConnection cnn, CommandDefinitio
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);
return QueryMultipleImpl(cnn, ref command); return QueryMultipleImpl(cnn, ref command);
} }
/// <summary> /// <summary>
/// Execute a command that returns multiple result sets, and access each in turn /// Execute a command that returns multiple result sets, and access each in turn
/// </summary> /// </summary>
public static GridReader QueryMultiple(this IDbConnection cnn, CommandDefinition command) public static GridReader QueryMultiple(this IDbConnection cnn, CommandDefinition command) =>
{ QueryMultipleImpl(cnn, ref command);
return QueryMultipleImpl(cnn, ref command);
}
private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandDefinition command) private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandDefinition command)
{ {
object param = command.Parameters; object param = command.Parameters;
Identity identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param?.GetType(), null);
CacheInfo info = GetCacheInfo(identity, param, command.AddToCache); CacheInfo info = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand cmd = null; IDbCommand cmd = null;
...@@ -909,8 +883,11 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD ...@@ -909,8 +883,11 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD
{ {
if (reader != null) if (reader != null)
{ {
if (!reader.IsClosed) try { cmd?.Cancel(); } if (!reader.IsClosed)
{
try { cmd?.Cancel(); }
catch { /* don't spoil the existing exception */ } catch { /* don't spoil the existing exception */ }
}
reader.Dispose(); reader.Dispose();
} }
cmd?.Dispose(); cmd?.Dispose();
...@@ -918,6 +895,7 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD ...@@ -918,6 +895,7 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD
throw; throw;
} }
} }
private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool wasClosed, CommandBehavior behavior) private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool wasClosed, CommandBehavior behavior)
{ {
try try
...@@ -934,6 +912,7 @@ private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool w ...@@ -934,6 +912,7 @@ private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool w
throw; throw;
} }
} }
private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType) private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType)
{ {
object param = command.Parameters; object param = command.Parameters;
...@@ -987,8 +966,11 @@ private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefini ...@@ -987,8 +966,11 @@ private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefini
{ {
if (reader != null) if (reader != null)
{ {
if (!reader.IsClosed) try { cmd.Cancel(); } if (!reader.IsClosed)
{
try { cmd.Cancel(); }
catch { /* don't spoil the existing exception */ } catch { /* don't spoil the existing exception */ }
}
reader.Dispose(); reader.Dispose();
} }
if (wasClosed) cnn.Close(); if (wasClosed) cnn.Close();
...@@ -1004,8 +986,9 @@ internal enum Row ...@@ -1004,8 +986,9 @@ internal enum Row
Single = 2, // & Single != 0: demand at least one row Single = 2, // & Single != 0: demand at least one row
SingleOrDefault = 3 SingleOrDefault = 3
} }
static readonly int[] ErrTwoRows = new int[2], ErrZeroRows = new int[0];
static void ThrowMultipleRows(Row row) private static readonly int[] ErrTwoRows = new int[2], ErrZeroRows = new int[0];
private static void ThrowMultipleRows(Row row)
{ {
switch (row) switch (row)
{ // get the standard exception from the runtime { // get the standard exception from the runtime
...@@ -1014,7 +997,8 @@ static void ThrowMultipleRows(Row row) ...@@ -1014,7 +997,8 @@ static void ThrowMultipleRows(Row row)
default: throw new InvalidOperationException(); default: throw new InvalidOperationException();
} }
} }
static void ThrowZeroRows(Row row)
private static void ThrowZeroRows(Row row)
{ {
switch (row) switch (row)
{ // get the standard exception from the runtime { // get the standard exception from the runtime
...@@ -1023,6 +1007,7 @@ static void ThrowZeroRows(Row row) ...@@ -1023,6 +1007,7 @@ static void ThrowZeroRows(Row row)
default: throw new InvalidOperationException(); default: throw new InvalidOperationException();
} }
} }
private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefinition command, Type effectiveType) private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefinition command, Type effectiveType)
{ {
object param = command.Parameters; object param = command.Parameters;
...@@ -1088,8 +1073,11 @@ private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefiniti ...@@ -1088,8 +1073,11 @@ private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefiniti
{ {
if (reader != null) if (reader != null)
{ {
if (!reader.IsClosed) try { cmd.Cancel(); } if (!reader.IsClosed)
{
try { cmd.Cancel(); }
catch { /* don't spoil the existing exception */ } catch { /* don't spoil the existing exception */ }
}
reader.Dispose(); reader.Dispose();
} }
if (wasClosed) cnn.Close(); if (wasClosed) cnn.Close();
...@@ -1222,7 +1210,6 @@ private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefiniti ...@@ -1222,7 +1210,6 @@ private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefiniti
return MultiMap<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, DontMap, TReturn>(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType); return MultiMap<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, DontMap, TReturn>(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
} }
/// <summary> /// <summary>
/// Perform a multi mapping query with 7 input parameters /// Perform a multi mapping query with 7 input parameters
/// </summary> /// </summary>
...@@ -1271,7 +1258,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string ...@@ -1271,7 +1258,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
return buffered ? results.ToList() : results; return buffered ? results.ToList() : results;
} }
static IEnumerable<TReturn> MultiMap<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>( private static IEnumerable<TReturn> MultiMap<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(
this IDbConnection cnn, string sql, Delegate map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType) this IDbConnection cnn, string sql, Delegate map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType)
{ {
var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None); var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);
...@@ -1279,7 +1266,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string ...@@ -1279,7 +1266,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
return buffered ? results.ToList() : results; return buffered ? results.ToList() : results;
} }
static IEnumerable<TReturn> MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn, IDataReader reader, Identity identity, bool finalize) private static IEnumerable<TReturn> MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn, IDataReader reader, Identity identity, bool finalize)
{ {
object param = command.Parameters; object param = command.Parameters;
identity = identity ?? new Identity(command.CommandText, command.CommandType, cnn, typeof(TFirst), param?.GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }); identity = identity ?? new Identity(command.CommandText, command.CommandType, cnn, typeof(TFirst), param?.GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) });
...@@ -1288,7 +1275,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string ...@@ -1288,7 +1275,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
IDbCommand ownedCommand = null; IDbCommand ownedCommand = null;
IDataReader ownedReader = null; IDataReader ownedReader = null;
bool wasClosed = cnn != null && cnn.State == ConnectionState.Closed; bool wasClosed = cnn?.State == ConnectionState.Closed;
try try
{ {
if (reader == null) if (reader == null)
...@@ -1343,7 +1330,8 @@ private static CommandBehavior GetBehavior(bool close, CommandBehavior @default) ...@@ -1343,7 +1330,8 @@ private static CommandBehavior GetBehavior(bool close, CommandBehavior @default)
{ {
return (close ? (@default | CommandBehavior.CloseConnection) : @default) & Settings.AllowedCommandBehaviors; return (close ? (@default | CommandBehavior.CloseConnection) : @default) & Settings.AllowedCommandBehaviors;
} }
static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, IDataReader reader, Identity identity, bool finalize)
private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, IDataReader reader, Identity identity, bool finalize)
{ {
if (types.Length < 1) if (types.Length < 1)
{ {
...@@ -1357,7 +1345,7 @@ static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, Comman ...@@ -1357,7 +1345,7 @@ static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, Comman
IDbCommand ownedCommand = null; IDbCommand ownedCommand = null;
IDataReader ownedReader = null; IDataReader ownedReader = null;
bool wasClosed = cnn != null && cnn.State == ConnectionState.Closed; bool wasClosed = cnn?.State == ConnectionState.Closed;
try try
{ {
if (reader == null) if (reader == null)
...@@ -1470,7 +1458,7 @@ static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, Comman ...@@ -1470,7 +1458,7 @@ static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, Comman
{ {
currentSplit = splits[++splitIdx]; currentSplit = splits[++splitIdx];
} }
deserializers.Add((GetDeserializer(type, reader, currentPos, splitPoint - currentPos, !first))); deserializers.Add(GetDeserializer(type, reader, currentPos, splitPoint - currentPos, !first));
currentPos = splitPoint; currentPos = splitPoint;
first = false; first = false;
} }
...@@ -1500,13 +1488,13 @@ static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, Comman ...@@ -1500,13 +1488,13 @@ static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, Comman
} }
} }
deserializers.Add((GetDeserializer(type, reader, splitPoint, currentPos - splitPoint, typeIdx > 0))); deserializers.Add(GetDeserializer(type, reader, splitPoint, currentPos - splitPoint, typeIdx > 0));
currentPos = splitPoint; currentPos = splitPoint;
} }
deserializers.Reverse(); deserializers.Reverse();
} }
return deserializers.ToArray(); return deserializers.ToArray();
} }
...@@ -1553,10 +1541,9 @@ private static int GetNextSplit(int startIdx, string splitOn, IDataReader reader ...@@ -1553,10 +1541,9 @@ private static int GetNextSplit(int startIdx, string splitOn, IDataReader reader
private static CacheInfo GetCacheInfo(Identity identity, object exampleParameters, bool addToCache) private static CacheInfo GetCacheInfo(Identity identity, object exampleParameters, bool addToCache)
{ {
CacheInfo info; if (!TryGetQueryCache(identity, out CacheInfo info))
if (!TryGetQueryCache(identity, out info))
{ {
if(GetMultiExec(exampleParameters) != null) if (GetMultiExec(exampleParameters) != null)
{ {
throw new InvalidOperationException("An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context"); throw new InvalidOperationException("An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context");
} }
...@@ -1566,7 +1553,7 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter ...@@ -1566,7 +1553,7 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter
Action<IDbCommand, object> reader; Action<IDbCommand, object> reader;
if (exampleParameters is IDynamicParameters) if (exampleParameters is IDynamicParameters)
{ {
reader = (cmd, obj) => { ((IDynamicParameters)obj).AddParameters(cmd, identity); }; reader = (cmd, obj) => ((IDynamicParameters)obj).AddParameters(cmd, identity);
} }
else if (exampleParameters is IEnumerable<KeyValuePair<string, object>>) else if (exampleParameters is IEnumerable<KeyValuePair<string, object>>)
{ {
...@@ -1581,7 +1568,7 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter ...@@ -1581,7 +1568,7 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter
var literals = GetLiteralTokens(identity.sql); var literals = GetLiteralTokens(identity.sql);
reader = CreateParamInfoGenerator(identity, false, true, literals); reader = CreateParamInfoGenerator(identity, false, true, literals);
} }
if((identity.commandType == null || identity.commandType == CommandType.Text) && ShouldPassByPosition(identity.sql)) if ((identity.commandType == null || identity.commandType == CommandType.Text) && ShouldPassByPosition(identity.sql))
{ {
var tail = reader; var tail = reader;
reader = (cmd, obj) => reader = (cmd, obj) =>
...@@ -1592,14 +1579,14 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter ...@@ -1592,14 +1579,14 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter
} }
info.ParamReader = reader; info.ParamReader = reader;
} }
if(addToCache) SetQueryCache(identity, info); if (addToCache) SetQueryCache(identity, info);
} }
return info; return info;
} }
private static bool ShouldPassByPosition(string sql) private static bool ShouldPassByPosition(string sql)
{ {
return sql != null && sql.IndexOf('?') >= 0 && pseudoPositional.IsMatch(sql); return sql?.IndexOf('?') >= 0 && pseudoPositional.IsMatch(sql);
} }
private static void PassByPosition(IDbCommand cmd) private static void PassByPosition(IDbCommand cmd)
...@@ -1617,14 +1604,13 @@ private static void PassByPosition(IDbCommand cmd) ...@@ -1617,14 +1604,13 @@ private static void PassByPosition(IDbCommand cmd)
cmd.CommandText = pseudoPositional.Replace(cmd.CommandText, match => cmd.CommandText = pseudoPositional.Replace(cmd.CommandText, match =>
{ {
string key = match.Groups[1].Value; string key = match.Groups[1].Value;
IDbDataParameter param;
if (!consumed.Add(key)) if (!consumed.Add(key))
{ {
throw new InvalidOperationException("When passing parameters by position, each parameter can only be referenced once"); throw new InvalidOperationException("When passing parameters by position, each parameter can only be referenced once");
} }
else if (parameters.TryGetValue(key, out param)) else if (parameters.TryGetValue(key, out IDbDataParameter param))
{ {
if(firstMatch) if (firstMatch)
{ {
firstMatch = false; firstMatch = false;
cmd.Parameters.Clear(); // only clear if we are pretty positive that we've found this pattern successfully cmd.Parameters.Clear(); // only clear if we are pretty positive that we've found this pattern successfully
...@@ -1645,7 +1631,6 @@ private static void PassByPosition(IDbCommand cmd) ...@@ -1645,7 +1631,6 @@ private static void PassByPosition(IDbCommand cmd)
private static Func<IDataReader, object> GetDeserializer(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing) private static Func<IDataReader, object> GetDeserializer(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
{ {
// dynamic is passed in as Object ... by c# design // dynamic is passed in as Object ... by c# design
if (type == typeof(object) if (type == typeof(object)
|| type == typeof(DapperRow)) || type == typeof(DapperRow))
...@@ -1653,11 +1638,10 @@ private static void PassByPosition(IDbCommand cmd) ...@@ -1653,11 +1638,10 @@ private static void PassByPosition(IDbCommand cmd)
return GetDapperRowDeserializer(reader, startBound, length, returnNullIfFirstMissing); return GetDapperRowDeserializer(reader, startBound, length, returnNullIfFirstMissing);
} }
Type underlyingType = null; Type underlyingType = null;
if (!(typeMap.ContainsKey(type) || type.IsEnum() || type.FullName == LinqBinary || if (!(typeMap.ContainsKey(type) || type.IsEnum() || type.FullName == LinqBinary
(type.IsValueType() && (underlyingType = Nullable.GetUnderlyingType(type)) != null && underlyingType.IsEnum()))) || (type.IsValueType() && (underlyingType = Nullable.GetUnderlyingType(type)) != null && underlyingType.IsEnum())))
{ {
ITypeHandler handler; if (typeHandlers.TryGetValue(type, out ITypeHandler handler))
if (typeHandlers.TryGetValue(type, out handler))
{ {
return GetHandlerDeserializer(handler, type, startBound); return GetHandlerDeserializer(handler, type, startBound);
} }
...@@ -1665,12 +1649,12 @@ private static void PassByPosition(IDbCommand cmd) ...@@ -1665,12 +1649,12 @@ private static void PassByPosition(IDbCommand cmd)
} }
return GetStructDeserializer(type, underlyingType ?? type, startBound); return GetStructDeserializer(type, underlyingType ?? type, startBound);
} }
private static Func<IDataReader, object> GetHandlerDeserializer(ITypeHandler handler, Type type, int startBound) private static Func<IDataReader, object> GetHandlerDeserializer(ITypeHandler handler, Type type, int startBound)
{ {
return reader => handler.Parse(type, reader.GetValue(startBound)); return reader => handler.Parse(type, reader.GetValue(startBound));
} }
private static Exception MultiMapException(IDataRecord reader) private static Exception MultiMapException(IDataRecord reader)
{ {
bool hasFields = false; bool hasFields = false;
...@@ -1778,7 +1762,6 @@ public static char ReadChar(object value) ...@@ -1778,7 +1762,6 @@ public static char ReadChar(object value)
return s[0]; return s[0];
} }
/// <summary> /// <summary>
/// Internal use only /// Internal use only
/// </summary> /// </summary>
...@@ -1879,12 +1862,11 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -1879,12 +1862,11 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
} }
if (!isDbString) if (!isDbString)
{ {
ITypeHandler handler; dbType = LookupDbType(item.GetType(), "", true, out ITypeHandler handler);
dbType = LookupDbType(item.GetType(), "", true, out handler);
} }
} }
var nextName = namePrefix + count.ToString(); var nextName = namePrefix + count.ToString();
if (isDbString && item as DbString != null) if (isDbString && item is DbString)
{ {
var str = item as DbString; var str = item as DbString;
str.AddParameter(command, nextName); str.AddParameter(command, nextName);
...@@ -1929,7 +1911,6 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -1929,7 +1911,6 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
} }
} }
if(viaSplit) if(viaSplit)
{ {
// already done // already done
...@@ -1976,7 +1957,6 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -1976,7 +1957,6 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
} }
else else
{ {
var sb = GetStringBuilder().Append('(').Append(variableName); var sb = GetStringBuilder().Append('(').Append(variableName);
if(!byPosition) sb.Append(1); if(!byPosition) sb.Append(1);
for (int i = 2; i <= count; i++) for (int i = 2; i <= count; i++)
...@@ -2005,6 +1985,7 @@ private static bool TryStringSplit(ref IEnumerable list, int splitAt, string nam ...@@ -2005,6 +1985,7 @@ private static bool TryStringSplit(ref IEnumerable list, int splitAt, string nam
(sb, i) => sb.Append(i.ToString(CultureInfo.InvariantCulture))); (sb, i) => sb.Append(i.ToString(CultureInfo.InvariantCulture)));
return false; return false;
} }
private static bool TryStringSplit<T>(ref IEnumerable list, int splitAt, string namePrefix, IDbCommand command, string colType, bool byPosition, private static bool TryStringSplit<T>(ref IEnumerable list, int splitAt, string namePrefix, IDbCommand command, string colType, bool byPosition,
Action<StringBuilder, T> append) Action<StringBuilder, T> append)
{ {
...@@ -2094,18 +2075,17 @@ public static object SanitizeParameterValue(object value) ...@@ -2094,18 +2075,17 @@ public static object SanitizeParameterValue(object value)
} }
return value; return value;
} }
private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyInfo> parameters, string sql) private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyInfo> parameters, string sql)
{ {
return parameters.Where(p => Regex.IsMatch(sql, @"[?@:]" + p.Name + @"([^\p{L}\p{N}_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant)); return parameters.Where(p => Regex.IsMatch(sql, @"[?@:]" + p.Name + @"([^\p{L}\p{N}_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant));
} }
// look for ? / @ / : *by itself* // look for ? / @ / : *by itself*
static readonly Regex smellsLikeOleDb = new Regex(@"(?<![\p{L}\p{N}@_])[?@:](?![\p{L}\p{N}@_])", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled), private static readonly Regex smellsLikeOleDb = new Regex(@"(?<![\p{L}\p{N}@_])[?@:](?![\p{L}\p{N}@_])", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled),
literalTokens = new Regex(@"(?<![\p{L}\p{N}_])\{=([\p{L}\p{N}_]+)\}", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled), literalTokens = new Regex(@"(?<![\p{L}\p{N}_])\{=([\p{L}\p{N}_]+)\}", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled),
pseudoPositional = new Regex(@"\?([\p{L}_][\p{L}\p{N}_]*)\?", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); pseudoPositional = new Regex(@"\?([\p{L}_][\p{L}\p{N}_]*)\?", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
/// <summary> /// <summary>
/// Replace all literal tokens with their text form /// Replace all literal tokens with their text form
/// </summary> /// </summary>
...@@ -2116,6 +2096,7 @@ public static void ReplaceLiterals(this IParameterLookup parameters, IDbCommand ...@@ -2116,6 +2096,7 @@ public static void ReplaceLiterals(this IParameterLookup parameters, IDbCommand
} }
internal static readonly MethodInfo format = typeof(SqlMapper).GetMethod("Format", BindingFlags.Public | BindingFlags.Static); internal static readonly MethodInfo format = typeof(SqlMapper).GetMethod("Format", BindingFlags.Public | BindingFlags.Static);
/// <summary> /// <summary>
/// Convert numeric values to their string form for SQL literal purposes /// Convert numeric values to their string form for SQL literal purposes
/// </summary> /// </summary>
...@@ -2191,7 +2172,6 @@ public static string Format(object value) ...@@ -2191,7 +2172,6 @@ public static string Format(object value)
} }
} }
internal static void ReplaceLiterals(IParameterLookup parameters, IDbCommand command, IList<LiteralToken> tokens) internal static void ReplaceLiterals(IParameterLookup parameters, IDbCommand command, IList<LiteralToken> tokens)
{ {
var sql = command.CommandText; var sql = command.CommandText;
...@@ -2232,9 +2212,10 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2232,9 +2212,10 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
{ {
return CreateParamInfoGenerator(identity, checkForDuplicates, removeUnused, GetLiteralTokens(identity.sql)); return CreateParamInfoGenerator(identity, checkForDuplicates, removeUnused, GetLiteralTokens(identity.sql));
} }
static bool IsValueTuple(Type type) => type != null && type.IsValueType() && type.FullName.StartsWith("System.ValueTuple`");
static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) private static bool IsValueTuple(Type type) => type?.IsValueType() == true && type.FullName.StartsWith("System.ValueTuple`");
private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
{ {
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
var result = new List<IMemberMap>(names.Length); var result = new List<IMemberMap>(names.Length);
...@@ -2326,8 +2307,7 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2326,8 +2307,7 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
ok = true; ok = true;
for (int i = 0; i < propsArr.Length; i++) for (int i = 0; i < propsArr.Length; i++)
{ {
int pos; if (!positionByName.TryGetValue(propsArr[i].Name, out int pos))
if (!positionByName.TryGetValue(propsArr[i].Name, out pos))
{ {
ok = false; ok = false;
break; break;
...@@ -2342,7 +2322,7 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2342,7 +2322,7 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
} }
} }
} }
if(props == null) props = propsArr.OrderBy(x => x.Name); props = props ?? propsArr.OrderBy(x => x.Name);
if (filterParams) if (filterParams)
{ {
props = FilterParameters(props, identity.sql); props = FilterParameters(props, identity.sql);
...@@ -2360,9 +2340,8 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2360,9 +2340,8 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
il.EmitCall(OpCodes.Callvirt, prop.PropertyType.GetMethod(nameof(ICustomQueryParameter.AddParameter)), null); // stack is now [parameters] il.EmitCall(OpCodes.Callvirt, prop.PropertyType.GetMethod(nameof(ICustomQueryParameter.AddParameter)), null); // stack is now [parameters]
continue; continue;
} }
ITypeHandler handler;
#pragma warning disable 618 #pragma warning disable 618
DbType dbType = LookupDbType(prop.PropertyType, prop.Name, true, out handler); DbType dbType = LookupDbType(prop.PropertyType, prop.Name, true, out ITypeHandler handler);
#pragma warning restore 618 #pragma warning restore 618
if (dbType == DynamicParameters.EnumerableMultiParameter) if (dbType == DynamicParameters.EnumerableMultiParameter)
{ {
...@@ -2641,7 +2620,6 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2641,7 +2620,6 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
if (propType.IsValueType()) il.Emit(OpCodes.Box, propType); // command, sql, object value if (propType.IsValueType()) il.Emit(OpCodes.Box, propType); // command, sql, object value
il.EmitCall(OpCodes.Call, format, null); // command, sql, string value il.EmitCall(OpCodes.Call, format, null); // command, sql, string value
break; break;
} }
il.EmitCall(OpCodes.Callvirt, StringReplace, null); il.EmitCall(OpCodes.Callvirt, StringReplace, null);
} }
...@@ -2652,17 +2630,19 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2652,17 +2630,19 @@ static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
return (Action<IDbCommand, object>)dm.CreateDelegate(typeof(Action<IDbCommand, object>)); return (Action<IDbCommand, object>)dm.CreateDelegate(typeof(Action<IDbCommand, object>));
} }
static readonly Dictionary<TypeCode, MethodInfo> toStrings = new[]
private static readonly Dictionary<TypeCode, MethodInfo> toStrings = new[]
{ {
typeof(bool), typeof(sbyte), typeof(byte), typeof(ushort), typeof(short), typeof(bool), typeof(sbyte), typeof(byte), typeof(ushort), typeof(short),
typeof(uint), typeof(int), typeof(ulong), typeof(long), typeof(float), typeof(double), typeof(decimal) typeof(uint), typeof(int), typeof(ulong), typeof(long), typeof(float), typeof(double), typeof(decimal)
}.ToDictionary(x => TypeExtensions.GetTypeCode(x), x => x.GetPublicInstanceMethod(nameof(object.ToString), new[] { typeof(IFormatProvider) })); }.ToDictionary(x => TypeExtensions.GetTypeCode(x), x => x.GetPublicInstanceMethod(nameof(object.ToString), new[] { typeof(IFormatProvider) }));
static MethodInfo GetToString(TypeCode typeCode)
private static MethodInfo GetToString(TypeCode typeCode)
{ {
MethodInfo method; return toStrings.TryGetValue(typeCode, out MethodInfo method) ? method : null;
return toStrings.TryGetValue(typeCode, out method) ? method : null;
} }
static readonly MethodInfo StringReplace = typeof(string).GetPublicInstanceMethod(nameof(string.Replace), new Type[] { typeof(string), typeof(string) }),
private static readonly MethodInfo StringReplace = typeof(string).GetPublicInstanceMethod(nameof(string.Replace), new Type[] { typeof(string), typeof(string) }),
InvariantCulture = typeof(CultureInfo).GetProperty(nameof(CultureInfo.InvariantCulture), BindingFlags.Public | BindingFlags.Static).GetGetMethod(); InvariantCulture = typeof(CultureInfo).GetProperty(nameof(CultureInfo.InvariantCulture), BindingFlags.Public | BindingFlags.Static).GetGetMethod();
private static int ExecuteCommand(IDbConnection cnn, ref CommandDefinition command, Action<IDbCommand, object> paramReader) private static int ExecuteCommand(IDbConnection cnn, ref CommandDefinition command, Action<IDbCommand, object> paramReader)
...@@ -2784,8 +2764,7 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin ...@@ -2784,8 +2764,7 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin
return val is DBNull ? null : Enum.ToObject(effectiveType, val); return val is DBNull ? null : Enum.ToObject(effectiveType, val);
}; };
} }
ITypeHandler handler; if (typeHandlers.TryGetValue(type, out ITypeHandler handler))
if(typeHandlers.TryGetValue(type, out handler))
{ {
return r => return r =>
{ {
...@@ -2814,18 +2793,17 @@ private static T Parse<T>(object value) ...@@ -2814,18 +2793,17 @@ private static T Parse<T>(object value)
} }
return (T)Enum.ToObject(type, value); return (T)Enum.ToObject(type, value);
} }
ITypeHandler handler; if (typeHandlers.TryGetValue(type, out ITypeHandler handler))
if (typeHandlers.TryGetValue(type, out handler))
{ {
return (T)handler.Parse(type, value); return (T)handler.Parse(type, value);
} }
return (T)Convert.ChangeType(value, type, CultureInfo.InvariantCulture); return (T)Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
} }
static readonly MethodInfo private static readonly MethodInfo
enumParse = typeof(Enum).GetMethod(nameof(Enum.Parse), new Type[] { typeof(Type), typeof(string), typeof(bool) }), enumParse = typeof(Enum).GetMethod(nameof(Enum.Parse), new Type[] { typeof(Type), typeof(string), typeof(bool) }),
getItem = typeof(IDataRecord).GetProperties(BindingFlags.Instance | BindingFlags.Public) getItem = typeof(IDataRecord).GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.GetIndexParameters().Any() && p.GetIndexParameters()[0].ParameterType == typeof(int)) .Where(p => p.GetIndexParameters().Length > 0 && p.GetIndexParameters()[0].ParameterType == typeof(int))
.Select(p => p.GetGetMethod()).First(); .Select(p => p.GetGetMethod()).First();
/// <summary> /// <summary>
...@@ -2905,12 +2883,12 @@ public static void SetTypeMap(Type type, ITypeMap map) ...@@ -2905,12 +2883,12 @@ public static void SetTypeMap(Type type, ITypeMap map)
{ {
return TypeDeserializerCache.GetReader(type, reader, startBound, length, returnNullIfFirstMissing); return TypeDeserializerCache.GetReader(type, reader, startBound, length, returnNullIfFirstMissing);
} }
static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuilder> locals, Type type, bool initAndLoad)
private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuilder> locals, Type type, bool initAndLoad)
{ {
if (type == null) throw new ArgumentNullException(nameof(type)); if (type == null) throw new ArgumentNullException(nameof(type));
if (locals == null) locals = new Dictionary<Type, LocalBuilder>(); locals = locals ?? new Dictionary<Type, LocalBuilder>();
LocalBuilder found; if (!locals.TryGetValue(type, out LocalBuilder found))
if (!locals.TryGetValue(type, out found))
{ {
found = il.DeclareLocal(type); found = il.DeclareLocal(type);
locals.Add(type, found); locals.Add(type, found);
...@@ -2924,6 +2902,7 @@ static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuild ...@@ -2924,6 +2902,7 @@ static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuild
} }
return found; return found;
} }
private static Func<IDataReader, object> GetTypeDeserializerImpl( private static Func<IDataReader, object> GetTypeDeserializerImpl(
Type type, IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false Type type, IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false
) )
...@@ -3079,7 +3058,7 @@ static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuild ...@@ -3079,7 +3058,7 @@ static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuild
// unbox nullable enums as the primitive, i.e. byte etc // unbox nullable enums as the primitive, i.e. byte etc
var nullUnderlyingType = Nullable.GetUnderlyingType(memberType); var nullUnderlyingType = Nullable.GetUnderlyingType(memberType);
var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum() ? nullUnderlyingType : memberType; var unboxType = nullUnderlyingType?.IsEnum() == true ? nullUnderlyingType : memberType;
if (unboxType.IsEnum()) if (unboxType.IsEnum())
{ {
...@@ -3214,7 +3193,7 @@ static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuild ...@@ -3214,7 +3193,7 @@ static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuild
il.MarkLabel(finishLabel); il.MarkLabel(finishLabel);
} }
first = false; first = false;
index += 1; index++;
} }
if (type.IsValueType()) if (type.IsValueType())
{ {
...@@ -3336,7 +3315,7 @@ private static void FlexibleConvertBoxedFromHeadOfStack(ILGenerator il, Type fro ...@@ -3336,7 +3315,7 @@ private static void FlexibleConvertBoxedFromHeadOfStack(ILGenerator il, Type fro
} }
} }
static MethodInfo GetOperator(Type from, Type to) private static MethodInfo GetOperator(Type from, Type to)
{ {
if (to == null) return null; if (to == null) return null;
MethodInfo[] fromMethods, toMethods; MethodInfo[] fromMethods, toMethods;
...@@ -3346,7 +3325,7 @@ static MethodInfo GetOperator(Type from, Type to) ...@@ -3346,7 +3325,7 @@ static MethodInfo GetOperator(Type from, Type to)
?? ResolveOperator(toMethods, from, to, "op_Explicit"); ?? ResolveOperator(toMethods, from, to, "op_Explicit");
} }
static MethodInfo ResolveOperator(MethodInfo[] methods, Type from, Type to, string name) private static MethodInfo ResolveOperator(MethodInfo[] methods, Type from, Type to, string name)
{ {
for (int i = 0; i < methods.Length; i++) for (int i = 0; i < methods.Length; i++)
{ {
...@@ -3379,6 +3358,7 @@ private static void LoadLocal(ILGenerator il, int index) ...@@ -3379,6 +3358,7 @@ private static void LoadLocal(ILGenerator il, int index)
break; break;
} }
} }
private static void StoreLocal(ILGenerator il, int index) private static void StoreLocal(ILGenerator il, int index)
{ {
if (index < 0 || index >= short.MaxValue) throw new ArgumentNullException(nameof(index)); if (index < 0 || index >= short.MaxValue) throw new ArgumentNullException(nameof(index));
...@@ -3491,6 +3471,7 @@ public static IEqualityComparer<string> ConnectionStringComparer ...@@ -3491,6 +3471,7 @@ public static IEqualityComparer<string> ConnectionStringComparer
get { return connectionStringComparer; } get { return connectionStringComparer; }
set { connectionStringComparer = value ?? StringComparer.Ordinal; } set { connectionStringComparer = value ?? StringComparer.Ordinal; }
} }
private static IEqualityComparer<string> connectionStringComparer = StringComparer.Ordinal; private static IEqualityComparer<string> connectionStringComparer = StringComparer.Ordinal;
#if !COREFX #if !COREFX
...@@ -3558,10 +3539,7 @@ private static string __ToStringRecycle(this StringBuilder obj) ...@@ -3558,10 +3539,7 @@ private static string __ToStringRecycle(this StringBuilder obj)
{ {
if (obj == null) return ""; if (obj == null) return "";
var s = obj.ToString(); var s = obj.ToString();
if(perThreadStringBuilderCache == null) perThreadStringBuilderCache = perThreadStringBuilderCache ?? obj;
{
perThreadStringBuilderCache = obj;
}
return s; return s;
} }
} }
......
...@@ -8,7 +8,7 @@ namespace Dapper ...@@ -8,7 +8,7 @@ namespace Dapper
/// <summary> /// <summary>
/// Used to pass a DataTable as a TableValuedParameter /// Used to pass a DataTable as a TableValuedParameter
/// </summary> /// </summary>
sealed class TableValuedParameter : SqlMapper.ICustomQueryParameter internal sealed class TableValuedParameter : SqlMapper.ICustomQueryParameter
{ {
private readonly DataTable table; private readonly DataTable table;
private readonly string typeName; private readonly string typeName;
...@@ -25,7 +25,8 @@ public TableValuedParameter(DataTable table, string typeName) ...@@ -25,7 +25,8 @@ public TableValuedParameter(DataTable table, string typeName)
this.table = table; this.table = table;
this.typeName = typeName; this.typeName = typeName;
} }
static readonly Action<System.Data.SqlClient.SqlParameter, string> setTypeName;
private static readonly Action<System.Data.SqlClient.SqlParameter, string> setTypeName;
static TableValuedParameter() static TableValuedParameter()
{ {
var prop = typeof(System.Data.SqlClient.SqlParameter).GetProperty("TypeName", BindingFlags.Instance | BindingFlags.Public); var prop = typeof(System.Data.SqlClient.SqlParameter).GetProperty("TypeName", BindingFlags.Instance | BindingFlags.Public);
...@@ -35,6 +36,7 @@ static TableValuedParameter() ...@@ -35,6 +36,7 @@ static TableValuedParameter()
Delegate.CreateDelegate(typeof(Action<System.Data.SqlClient.SqlParameter, string>), prop.GetSetMethod()); Delegate.CreateDelegate(typeof(Action<System.Data.SqlClient.SqlParameter, string>), prop.GetSetMethod());
} }
} }
void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string name) void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string name)
{ {
var param = command.CreateParameter(); var param = command.CreateParameter();
...@@ -42,6 +44,7 @@ void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string nam ...@@ -42,6 +44,7 @@ void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string nam
Set(param, table, typeName); Set(param, table, typeName);
command.Parameters.Add(param); command.Parameters.Add(param);
} }
internal static void Set(IDbDataParameter parameter, DataTable table, string typeName) internal static void Set(IDbDataParameter parameter, DataTable table, string typeName)
{ {
#pragma warning disable 0618 #pragma warning disable 0618
...@@ -53,8 +56,7 @@ internal static void Set(IDbDataParameter parameter, DataTable table, string typ ...@@ -53,8 +56,7 @@ internal static void Set(IDbDataParameter parameter, DataTable table, string typ
} }
if (!string.IsNullOrEmpty(typeName)) if (!string.IsNullOrEmpty(typeName))
{ {
var sqlParam = parameter as System.Data.SqlClient.SqlParameter; if (parameter is System.Data.SqlClient.SqlParameter sqlParam)
if (sqlParam != null)
{ {
setTypeName?.Invoke(sqlParam, typeName); setTypeName?.Invoke(sqlParam, typeName);
sqlParam.SqlDbType = SqlDbType.Structured; sqlParam.SqlDbType = SqlDbType.Structured;
......
...@@ -6,47 +6,41 @@ namespace Dapper ...@@ -6,47 +6,41 @@ namespace Dapper
{ {
internal static class TypeExtensions internal static class TypeExtensions
{ {
public static string Name(this Type type) public static string Name(this Type type) =>
{
#if COREFX #if COREFX
return type.GetTypeInfo().Name; type.GetTypeInfo().Name;
#else #else
return type.Name; type.Name;
#endif #endif
}
public static bool IsValueType(this Type type) public static bool IsValueType(this Type type) =>
{
#if COREFX #if COREFX
return type.GetTypeInfo().IsValueType; type.GetTypeInfo().IsValueType;
#else #else
return type.IsValueType; type.IsValueType;
#endif #endif
}
public static bool IsEnum(this Type type) public static bool IsEnum(this Type type) =>
{
#if COREFX #if COREFX
return type.GetTypeInfo().IsEnum; type.GetTypeInfo().IsEnum;
#else #else
return type.IsEnum; type.IsEnum;
#endif #endif
}
public static bool IsGenericType(this Type type) public static bool IsGenericType(this Type type) =>
{
#if COREFX #if COREFX
return type.GetTypeInfo().IsGenericType; type.GetTypeInfo().IsGenericType;
#else #else
return type.IsGenericType; type.IsGenericType;
#endif #endif
}
public static bool IsInterface(this Type type) public static bool IsInterface(this Type type) =>
{
#if COREFX #if COREFX
return type.GetTypeInfo().IsInterface; type.GetTypeInfo().IsInterface;
#else #else
return type.IsInterface; type.IsInterface;
#endif #endif
}
#if COREFX #if COREFX
public static IEnumerable<Attribute> GetCustomAttributes(this Type type, bool inherit) public static IEnumerable<Attribute> GetCustomAttributes(this Type type, bool inherit)
{ {
...@@ -56,8 +50,7 @@ public static IEnumerable<Attribute> GetCustomAttributes(this Type type, bool in ...@@ -56,8 +50,7 @@ public static IEnumerable<Attribute> GetCustomAttributes(this Type type, bool in
public static TypeCode GetTypeCode(Type type) public static TypeCode GetTypeCode(Type type)
{ {
if (type == null) return TypeCode.Empty; if (type == null) return TypeCode.Empty;
TypeCode result; if (typeCodeLookup.TryGetValue(type, out TypeCode result)) return result;
if (typeCodeLookup.TryGetValue(type, out result)) return result;
if (type.IsEnum()) if (type.IsEnum())
{ {
...@@ -66,41 +59,38 @@ public static TypeCode GetTypeCode(Type type) ...@@ -66,41 +59,38 @@ public static TypeCode GetTypeCode(Type type)
} }
return TypeCode.Object; return TypeCode.Object;
} }
static readonly Dictionary<Type, TypeCode> typeCodeLookup = new Dictionary<Type, TypeCode>
private static readonly Dictionary<Type, TypeCode> typeCodeLookup = new Dictionary<Type, TypeCode>
{ {
{typeof(bool), TypeCode.Boolean }, [typeof(bool)] = TypeCode.Boolean,
{typeof(byte), TypeCode.Byte }, [typeof(byte)] = TypeCode.Byte,
{typeof(char), TypeCode.Char}, [typeof(char)] = TypeCode.Char,
{typeof(DateTime), TypeCode.DateTime}, [typeof(DateTime)] = TypeCode.DateTime,
{typeof(decimal), TypeCode.Decimal}, [typeof(decimal)] = TypeCode.Decimal,
{typeof(double), TypeCode.Double }, [typeof(double)] = TypeCode.Double,
{typeof(short), TypeCode.Int16 }, [typeof(short)] = TypeCode.Int16,
{typeof(int), TypeCode.Int32 }, [typeof(int)] = TypeCode.Int32,
{typeof(long), TypeCode.Int64 }, [typeof(long)] = TypeCode.Int64,
{typeof(object), TypeCode.Object}, [typeof(object)] = TypeCode.Object,
{typeof(sbyte), TypeCode.SByte }, [typeof(sbyte)] = TypeCode.SByte,
{typeof(float), TypeCode.Single }, [typeof(float)] = TypeCode.Single,
{typeof(string), TypeCode.String }, [typeof(string)] = TypeCode.String,
{typeof(ushort), TypeCode.UInt16 }, [typeof(ushort)] = TypeCode.UInt16,
{typeof(uint), TypeCode.UInt32 }, [typeof(uint)] = TypeCode.UInt32,
{typeof(ulong), TypeCode.UInt64 }, [typeof(ulong)] = TypeCode.UInt64,
}; };
#else #else
public static TypeCode GetTypeCode(Type type) public static TypeCode GetTypeCode(Type type) => Type.GetTypeCode(type);
{
return Type.GetTypeCode(type);
}
#endif #endif
public static MethodInfo GetPublicInstanceMethod(this Type type, string name, Type[] types) public static MethodInfo GetPublicInstanceMethod(this Type type, string name, Type[] types)
{ {
#if COREFX #if COREFX
var method = type.GetMethod(name, types); var method = type.GetMethod(name, types);
return (method != null && method.IsPublic && !method.IsStatic) ? method : null; return (method?.IsPublic == true && !method.IsStatic) ? method : null;
#else #else
return type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public, null, types, null); return type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public, null, types, null);
#endif #endif
} }
} }
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Dapper namespace Dapper
{ {
partial class SqlMapper public static partial class SqlMapper
{ {
#if !COREFX #if !COREFX
/// <summary> /// <summary>
...@@ -21,6 +21,7 @@ public UdtTypeHandler(string udtTypeName) ...@@ -21,6 +21,7 @@ public UdtTypeHandler(string udtTypeName)
if (string.IsNullOrEmpty(udtTypeName)) throw new ArgumentException("Cannot be null or empty", udtTypeName); if (string.IsNullOrEmpty(udtTypeName)) throw new ArgumentException("Cannot be null or empty", udtTypeName);
this.udtTypeName = udtTypeName; this.udtTypeName = udtTypeName;
} }
object ITypeHandler.Parse(Type destinationType, object value) object ITypeHandler.Parse(Type destinationType, object value)
{ {
return value is DBNull ? null : value; return value is DBNull ? null : value;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Dapper namespace Dapper
{ {
internal class WrappedReader : IDataReader, IWrappedDataReader internal class WrappedReader : IWrappedDataReader
{ {
private IDataReader reader; private IDataReader reader;
private IDbCommand cmd; private IDbCommand cmd;
...@@ -17,6 +17,7 @@ public IDataReader Reader ...@@ -17,6 +17,7 @@ public IDataReader Reader
return tmp; return tmp;
} }
} }
IDbCommand IWrappedDataReader.Command IDbCommand IWrappedDataReader.Command
{ {
get get
...@@ -26,35 +27,24 @@ IDbCommand IWrappedDataReader.Command ...@@ -26,35 +27,24 @@ IDbCommand IWrappedDataReader.Command
return tmp; return tmp;
} }
} }
public WrappedReader(IDbCommand cmd, IDataReader reader) public WrappedReader(IDbCommand cmd, IDataReader reader)
{ {
this.cmd = cmd; this.cmd = cmd;
this.reader = reader; this.reader = reader;
} }
void IDataReader.Close() void IDataReader.Close() => reader?.Close();
{
reader?.Close();
}
int IDataReader.Depth => Reader.Depth; int IDataReader.Depth => Reader.Depth;
DataTable IDataReader.GetSchemaTable() DataTable IDataReader.GetSchemaTable() => Reader.GetSchemaTable();
{
return Reader.GetSchemaTable();
}
bool IDataReader.IsClosed => reader?.IsClosed ?? true; bool IDataReader.IsClosed => reader?.IsClosed ?? true;
bool IDataReader.NextResult() bool IDataReader.NextResult() => Reader.NextResult();
{
return Reader.NextResult();
}
bool IDataReader.Read() bool IDataReader.Read() => Reader.Read();
{
return Reader.Read();
}
int IDataReader.RecordsAffected => Reader.RecordsAffected; int IDataReader.RecordsAffected => Reader.RecordsAffected;
...@@ -69,115 +59,51 @@ void IDisposable.Dispose() ...@@ -69,115 +59,51 @@ void IDisposable.Dispose()
int IDataRecord.FieldCount => Reader.FieldCount; int IDataRecord.FieldCount => Reader.FieldCount;
bool IDataRecord.GetBoolean(int i) bool IDataRecord.GetBoolean(int i) => Reader.GetBoolean(i);
{
return Reader.GetBoolean(i);
}
byte IDataRecord.GetByte(int i) byte IDataRecord.GetByte(int i) => Reader.GetByte(i);
{
return Reader.GetByte(i);
}
long IDataRecord.GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) long IDataRecord.GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) =>
{ Reader.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
return Reader.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
}
char IDataRecord.GetChar(int i) char IDataRecord.GetChar(int i) => Reader.GetChar(i);
{
return Reader.GetChar(i);
}
long IDataRecord.GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) long IDataRecord.GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) =>
{ Reader.GetChars(i, fieldoffset, buffer, bufferoffset, length);
return Reader.GetChars(i, fieldoffset, buffer, bufferoffset, length);
}
IDataReader IDataRecord.GetData(int i) IDataReader IDataRecord.GetData(int i) => Reader.GetData(i);
{
return Reader.GetData(i);
}
string IDataRecord.GetDataTypeName(int i) string IDataRecord.GetDataTypeName(int i) => Reader.GetDataTypeName(i);
{
return Reader.GetDataTypeName(i);
}
DateTime IDataRecord.GetDateTime(int i) DateTime IDataRecord.GetDateTime(int i) => Reader.GetDateTime(i);
{
return Reader.GetDateTime(i);
}
decimal IDataRecord.GetDecimal(int i) decimal IDataRecord.GetDecimal(int i) => Reader.GetDecimal(i);
{
return Reader.GetDecimal(i);
}
double IDataRecord.GetDouble(int i) double IDataRecord.GetDouble(int i) => Reader.GetDouble(i);
{
return Reader.GetDouble(i);
}
Type IDataRecord.GetFieldType(int i) Type IDataRecord.GetFieldType(int i) => Reader.GetFieldType(i);
{
return Reader.GetFieldType(i);
}
float IDataRecord.GetFloat(int i) float IDataRecord.GetFloat(int i) => Reader.GetFloat(i);
{
return Reader.GetFloat(i);
}
Guid IDataRecord.GetGuid(int i) Guid IDataRecord.GetGuid(int i) => Reader.GetGuid(i);
{
return Reader.GetGuid(i);
}
short IDataRecord.GetInt16(int i) short IDataRecord.GetInt16(int i) => Reader.GetInt16(i);
{
return Reader.GetInt16(i);
}
int IDataRecord.GetInt32(int i) int IDataRecord.GetInt32(int i) => Reader.GetInt32(i);
{
return Reader.GetInt32(i);
}
long IDataRecord.GetInt64(int i) long IDataRecord.GetInt64(int i) => Reader.GetInt64(i);
{
return Reader.GetInt64(i);
}
string IDataRecord.GetName(int i) string IDataRecord.GetName(int i) => Reader.GetName(i);
{
return Reader.GetName(i);
}
int IDataRecord.GetOrdinal(string name) int IDataRecord.GetOrdinal(string name) => Reader.GetOrdinal(name);
{
return Reader.GetOrdinal(name);
}
string IDataRecord.GetString(int i) string IDataRecord.GetString(int i) => Reader.GetString(i);
{
return Reader.GetString(i);
}
object IDataRecord.GetValue(int i) object IDataRecord.GetValue(int i) => Reader.GetValue(i);
{
return Reader.GetValue(i);
}
int IDataRecord.GetValues(object[] values) int IDataRecord.GetValues(object[] values) => Reader.GetValues(values);
{
return Reader.GetValues(values);
}
bool IDataRecord.IsDBNull(int i) bool IDataRecord.IsDBNull(int i) => Reader.IsDBNull(i);
{
return Reader.IsDBNull(i);
}
object IDataRecord.this[string name] => Reader[name]; object IDataRecord.this[string name] => Reader[name];
......
...@@ -12,6 +12,7 @@ public override void SetValue(IDbDataParameter parameter, T value) ...@@ -12,6 +12,7 @@ public override void SetValue(IDbDataParameter parameter, T value)
parameter.DbType = DbType.Xml; parameter.DbType = DbType.Xml;
} }
} }
internal sealed class XmlDocumentHandler : XmlTypeHandler<XmlDocument> internal sealed class XmlDocumentHandler : XmlTypeHandler<XmlDocument>
{ {
protected override XmlDocument Parse(string xml) protected override XmlDocument Parse(string xml)
...@@ -20,13 +21,16 @@ protected override XmlDocument Parse(string xml) ...@@ -20,13 +21,16 @@ protected override XmlDocument Parse(string xml)
doc.LoadXml(xml); doc.LoadXml(xml);
return doc; return doc;
} }
protected override string Format(XmlDocument xml) => xml.OuterXml; protected override string Format(XmlDocument xml) => xml.OuterXml;
} }
internal sealed class XDocumentHandler : XmlTypeHandler<XDocument> internal sealed class XDocumentHandler : XmlTypeHandler<XDocument>
{ {
protected override XDocument Parse(string xml) => XDocument.Parse(xml); protected override XDocument Parse(string xml) => XDocument.Parse(xml);
protected override string Format(XDocument xml) => xml.ToString(); protected override string Format(XDocument xml) => xml.ToString();
} }
internal sealed class XElementHandler : XmlTypeHandler<XElement> internal sealed class XElementHandler : XmlTypeHandler<XElement>
{ {
protected override XElement Parse(string xml) => XElement.Parse(xml); protected override XElement Parse(string xml) => XElement.Parse(xml);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment