Commit d7c9763d authored by Sam Saffron's avatar Sam Saffron

code cleanup ...

parent 7c2efbe5
...@@ -17,8 +17,13 @@ namespace Dapper ...@@ -17,8 +17,13 @@ namespace Dapper
{ {
public static class SqlMapper public static class SqlMapper
{ {
static ConcurrentDictionary<Identity, object> cachedSerializers = new ConcurrentDictionary<Identity, object>(); class CacheInfo
static ConcurrentDictionary<Type, Func<object, List<ParamInfo>>> cachedParamReaders = new ConcurrentDictionary<Type, Func<object, List<ParamInfo>>>(); {
public object Deserializer { get; set; }
public Func<object, List<ParamInfo>> ParamReader { get; set; }
}
static ConcurrentDictionary<Identity, CacheInfo> queryCache = new ConcurrentDictionary<Identity, CacheInfo>();
static Dictionary<Type, DbType> typeMap; static Dictionary<Type, DbType> typeMap;
static SqlMapper() static SqlMapper()
...@@ -76,7 +81,7 @@ private static DbType LookupDbType(Type type) ...@@ -76,7 +81,7 @@ private static DbType LookupDbType(Type type)
} }
} }
throw new NotSupportedException("The type : " + type.ToString() + " is not supported by the mapper"); throw new NotSupportedException("The type : " + type.ToString() + " is not supported by dapper");
} }
class ParamInfo class ParamInfo
...@@ -101,17 +106,20 @@ private class Identity : IEquatable<Identity> ...@@ -101,17 +106,20 @@ private class Identity : IEquatable<Identity>
public String ConnectionString { get { return connectionString; } } public String ConnectionString { get { return connectionString; } }
public Type Type { get { return type; } } public Type Type { get { return type; } }
public string Sql { get { return sql; } } public string Sql { get { return sql; } }
internal Identity(string sql, IDbConnection cnn, Type type) public Type ParametersType { get { return ParametersType; } }
internal Identity(string sql, IDbConnection cnn, Type type, Type parametersType)
{ {
this.sql = sql; this.sql = sql;
this.connectionString = cnn.ConnectionString; this.connectionString = cnn.ConnectionString;
this.type = type; this.type = type;
this.parametersType = parametersType;
unchecked unchecked
{ {
hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this
hashCode = hashCode * 23 + (sql == null ? 0 : sql.GetHashCode()); hashCode = hashCode * 23 + (sql == null ? 0 : sql.GetHashCode());
hashCode = hashCode * 23 + (type == null ? 0 : type.GetHashCode()); hashCode = hashCode * 23 + (type == null ? 0 : type.GetHashCode());
hashCode = hashCode * 23 + (connectionString == null ? 0 : connectionString.GetHashCode()); hashCode = hashCode * 23 + (connectionString == null ? 0 : connectionString.GetHashCode());
hashCode = hashCode * 23 + (parametersType == null ? 0 : parametersType.GetHashCode());
} }
} }
public override bool Equals(object obj) public override bool Equals(object obj)
...@@ -122,14 +130,19 @@ public override bool Equals(object obj) ...@@ -122,14 +130,19 @@ public override bool Equals(object obj)
private readonly int hashCode; private readonly int hashCode;
private readonly Type type; private readonly Type type;
private readonly string connectionString; private readonly string connectionString;
private readonly Type parametersType;
public override int GetHashCode() public override int GetHashCode()
{ {
return hashCode; return hashCode;
} }
public bool Equals(Identity other) public bool Equals(Identity other)
{ {
return other != null && this.type == other.type return
&& sql == other.sql && connectionString == other.connectionString; other != null &&
this.type == other.type &&
sql == other.sql &&
connectionString == other.connectionString &&
parametersType == other.parametersType;
} }
} }
...@@ -139,7 +152,15 @@ public bool Equals(Identity other) ...@@ -139,7 +152,15 @@ public bool Equals(Identity other)
/// <returns>Number of rows affected</returns> /// <returns>Number of rows affected</returns>
public static int Execute(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null) public static int Execute(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null)
{ {
return ExecuteCommand(cnn, transaction, sql, GetParamInfo(param)); var identity = new Identity(sql, cnn, null, param == null ? null : param.GetType());
var info = GetCacheInfo(param, identity);
List<ParamInfo> paramInfos = null;
if (info.ParamReader != null)
{
paramInfos = info.ParamReader(param);
}
return ExecuteCommand(cnn, transaction, sql, paramInfos);
} }
/// <summary> /// <summary>
...@@ -147,101 +168,86 @@ public static int Execute(this IDbConnection cnn, string sql, object param = nul ...@@ -147,101 +168,86 @@ public static int Execute(this IDbConnection cnn, string sql, object param = nul
/// </summary> /// </summary>
public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true) public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true)
{ {
if (!buffered) return Query<ExpandoObject>(cnn, sql, param, transaction, buffered);
{
return EnumerateMapperQuery(cnn, sql, param, transaction);
} }
var identity = new Identity(sql, cnn, DynamicStub.Type);
var list = new List<dynamic>();
using (var reader = GetReader(cnn, transaction, sql, GetParamInfo(param))) public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true)
{ {
Func<IDataReader, ExpandoObject> deserializer = GetDeserializer<ExpandoObject>(identity, reader); var data = QueryInternal<T>(cnn, sql, param, transaction);
while (reader.Read()) if (buffered)
{ {
list.Add(deserializer(reader)); return data.ToList();
} }
else
{
return data;
} }
return list;
} }
/// <summary> /// <summary>
/// Return a typed list of objects, reader is closed after the call /// Return a typed list of objects, reader is closed after the call
/// </summary> /// </summary>
public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true) private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null)
{ {
var identity = new Identity(sql, cnn, typeof(T), param == null ? null : param.GetType());
var info = GetCacheInfo(param, identity);
if (!buffered) List<ParamInfo> paramInfos = null;
if (info.ParamReader != null)
{ {
return EnumerateMapperQuery<T>(cnn, sql, param, transaction); paramInfos = info.ParamReader(param);
} }
var identity = new Identity(sql, cnn, typeof(T)); using (var reader = GetReader(cnn, transaction, sql, paramInfos))
var rval = new List<T>();
using (var reader = GetReader(cnn, transaction, sql, GetParamInfo(param)))
{ {
Func<IDataReader, T> deserializer = GetDeserializer<T>(identity, reader); if (info.Deserializer == null)
while (reader.Read())
{ {
rval.Add(deserializer(reader)); info.Deserializer = GetDeserializer<T>(identity, reader);
} queryCache[identity] = info;
}
return rval;
} }
public static List<T> Query<T,U>(this IDbConnection cnn, string sql, Action<T,U> map, object param = null, IDbTransaction transaction = null) var deserializer = (Func<IDataReader,T>)info.Deserializer;
while (reader.Read())
{ {
return null; yield return deserializer(reader);
}
} }
static class DynamicStub
{
public static Type Type = typeof(DynamicStub);
} }
/// <summary> private static CacheInfo GetCacheInfo(object param, Identity identity)
/// Enumerates the query, keeping the reader open after it is called. Use when iterating through huge result sets . You should usually use ExecuteMapperQuery instead.
/// </summary>
static IEnumerable<T> EnumerateMapperQuery<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null)
{ {
var identity = new Identity(sql, cnn, typeof(T)); CacheInfo info;
if (!queryCache.TryGetValue(identity, out info))
using (var reader = GetReader(cnn, transaction, sql, GetParamInfo(param)))
{ {
Func<IDataReader, T> deserializer = GetDeserializer<T>(identity, reader); info = new CacheInfo();
while (reader.Read()) if (param != null)
{ {
yield return deserializer(reader); info.ParamReader = CreateParamInfoGenerator(param.GetType());
} }
} }
return info;
} }
/// <summary> public static List<T> Query<T,U>(this IDbConnection cnn, string sql, Action<T,U> map, object param = null, IDbTransaction transaction = null)
/// Enumerates the query, keeping the reader open after it is called. Use when iterating through huge result sets. You should usually use ExecuteMapperQuery instead
/// </summary>
static IEnumerable<dynamic> EnumerateMapperQuery(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null)
{ {
var identity = new Identity(sql, cnn, DynamicStub.Type); return null;
}
using (var reader = GetReader(cnn, transaction, sql, GetParamInfo(param)))
{ static class DynamicStub
Func<IDataReader, ExpandoObject> deserializer = GetDeserializer<ExpandoObject>(identity, reader);
while (reader.Read())
{ {
yield return deserializer(reader); public static Type Type = typeof(DynamicStub);
}
}
} }
static Func<IDataReader, T> GetDeserializer<T>(Identity identity, IDataReader reader) static Func<IDataReader, T> GetDeserializer<T>(Identity identity, IDataReader reader)
{ {
object oDeserializer; object oDeserializer;
if (!cachedSerializers.TryGetValue(identity, out oDeserializer))
{
if (typeof(T) == DynamicStub.Type || typeof(T) == typeof(ExpandoObject)) if (typeof(T) == DynamicStub.Type || typeof(T) == typeof(ExpandoObject))
{ {
oDeserializer = GetDynamicDeserializer(reader); oDeserializer = GetDynamicDeserializer(reader);
...@@ -255,30 +261,10 @@ static IEnumerable<dynamic> EnumerateMapperQuery(this IDbConnection cnn, string ...@@ -255,30 +261,10 @@ static IEnumerable<dynamic> EnumerateMapperQuery(this IDbConnection cnn, string
oDeserializer = GetStructDeserializer<T>(reader); oDeserializer = GetStructDeserializer<T>(reader);
} }
cachedSerializers[identity] = oDeserializer;
}
Func<IDataReader, T> deserializer = (Func<IDataReader, T>)oDeserializer; Func<IDataReader, T> deserializer = (Func<IDataReader, T>)oDeserializer;
return deserializer; return deserializer;
} }
private static List<ParamInfo> GetParamInfo(object param)
{
Func<object, List<ParamInfo>> paramInfoGenerator;
List<ParamInfo> paramInfo = null;
if (param != null)
{
if (!cachedParamReaders.TryGetValue(param.GetType(), out paramInfoGenerator))
{
paramInfoGenerator = CreateParamInfoGenerator(param.GetType());
cachedParamReaders[param.GetType()] = paramInfoGenerator;
}
paramInfo = paramInfoGenerator(param);
}
return paramInfo;
}
private static object GetDynamicDeserializer(IDataReader reader) private static object GetDynamicDeserializer(IDataReader reader)
{ {
List<string> colNames = new List<string>(); List<string> colNames = new List<string>();
......
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