Commit f6132344 authored by Nick Craver's avatar Nick Craver

Lots of code cleanup, no functional changes

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