欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

sqlmapper.cs下载 dapperSqlMapper.csORM 

程序员文章站 2022-07-12 18:27:57
...

Dapper是一款轻量级ORM工具(Github)。如果你在小的项目中,使用Entity Framework、NHibernate 来处理大数据访问及关系映射,未免有点杀鸡用牛刀。你又觉得ORM省时省力,这时Dapper 将是你不二的选择。

具体使用参考:http://www.cnblogs.com/wywnet/p/3422150.html

sqlmapper.cs下载 http://pan.baidu.com/s/1pL12hqr

 

/* 
 License: http://www.apache.org/licenses/LICENSE-2.0  
 Home page: http://code.google.com/p/dapper-dot-net/ 
 Note: to build on C# 3.0 + .NET 3.5, include the CSHARP30 compiler symbol (and yes, 
 I know the difference between language and runtime versions; this is a compromise). 
 */  
  
  
using System;  
using System.Collections;  
using System.Collections.Generic;  
using System.ComponentModel;  
using System.Data;  
using System.Linq;  
using System.Reflection;  
using System.Reflection.Emit;  
using System.Text;  
using System.Threading;  
using System.Text.RegularExpressions;  
using System.Diagnostics;  
using System.Globalization;  
using System.Linq.Expressions;  
  
  
namespace Dapper  
{  
    [AssemblyNeutral, AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]  
    internal sealed class AssemblyNeutralAttribute : Attribute { }  
  
  
    /// <summary>  
    /// Additional state flags that control command behaviour  
    /// </summary>  
    [Flags]  
    public enum CommandFlags  
    {  
        /// <summary>  
        /// No additional flags  
        /// </summary>  
        None = 0,  
        /// <summary>  
        /// Should data be buffered before returning?  
        /// </summary>  
        Buffered = 1,  
        /// <summary>  
        /// Can async queries be pipelined?  
        /// </summary>  
        Pipelined = 2,  
        /// <summary>  
        /// Should the plan cache be bypassed?  
        /// </summary>  
        NoCache = 4,  
    }  
    /// <summary>  
    /// Represents the key aspects of a sql operation  
    /// </summary>  
    public struct CommandDefinition  
    {  
        internal static CommandDefinition ForCallback(object parameters)  
        {  
            if(parameters is DynamicParameters)  
            {  
                return new CommandDefinition(parameters);  
            }  
            else  
            {  
                return default(CommandDefinition);  
            }  
        }  
        private readonly string commandText;  
        private readonly object parameters;  
        private readonly IDbTransaction transaction;  
        private readonly int? commandTimeout;  
        private readonly CommandType? commandType;  
        private readonly CommandFlags flags;  
  
  
  
  
        internal void OnCompleted()  
        {  
            if (parameters is SqlMapper.IParameterCallbacks)  
            {  
                ((SqlMapper.IParameterCallbacks)parameters).OnCompleted();  
            }  
        }  
        /// <summary>  
        /// The command (sql or a stored-procedure name) to execute  
        /// </summary>  
        public string CommandText { get { return commandText; } }  
        /// <summary>  
        /// The parameters associated with the command  
        /// </summary>  
        public object Parameters { get { return parameters; } }  
        /// <summary>  
        /// The active transaction for the command  
        /// </summary>  
        public IDbTransaction Transaction { get { return transaction; } }  
        /// <summary>  
        /// The effective timeout for the command  
        /// </summary>  
        public int? CommandTimeout { get { return commandTimeout; } }  
        /// <summary>  
        /// The type of command that the command-text represents  
        /// </summary>  
        public CommandType? CommandType { get { return commandType; } }  
  
  
        /// <summary>  
        /// Should data be buffered before returning?  
        /// </summary>  
        public bool Buffered { get { return (flags & CommandFlags.Buffered) != 0; } }  
  
  
        /// <summary>  
        /// Should the plan for this query be cached?  
        /// </summary>  
        internal bool AddToCache {  get { return (flags & CommandFlags.NoCache) == 0; } }  
  
  
        /// <summary>  
        /// Additional state flags against this command  
        /// </summary>  
        public CommandFlags Flags {  get { return flags; } }  
  
  
        /// <summary>  
        /// Can async queries be pipelined?  
        /// </summary>  
        public bool Pipelined { get { return (flags & CommandFlags.Pipelined) != 0; } }  
  
  
        /// <summary>  
        /// Initialize the command definition  
        /// </summary>  
#if CSHARP30  
        public CommandDefinition(string commandText, object parameters, IDbTransaction transaction, int? commandTimeout,  
            CommandType? commandType, CommandFlags flags)  
#else  
        public CommandDefinition(string commandText, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null,  
            CommandType? commandType = null, CommandFlags flags = CommandFlags.Buffered  
#if ASYNC  
            , CancellationToken cancellationToken = default(CancellationToken)  
#endif  
            )  
#endif  
        {  
            this.commandText = commandText;  
            this.parameters = parameters;  
            this.transaction = transaction;  
            this.commandTimeout = commandTimeout;  
            this.commandType = commandType;  
            this.flags = flags;  
#if ASYNC  
            this.cancellationToken = cancellationToken;  
#endif  
        }  
  
  
        private CommandDefinition(object parameters) : this()  
        {  
            this.parameters = parameters;  
        }  
 
 
#if ASYNC  
        private readonly CancellationToken cancellationToken;  
        /// <summary>  
        /// For asynchronous operations, the cancellation-token  
        /// </summary>  
        public CancellationToken CancellationToken { get { return cancellationToken; } }  
#endif  
  
  
        internal IDbCommand SetupCommand(IDbConnection cnn, Action<IDbCommand, object> paramReader)  
        {  
            var cmd = cnn.CreateCommand();  
            var init = GetInit(cmd.GetType());  
            if (init != null) init(cmd);  
            if (transaction != null)  
                cmd.Transaction = transaction;  
            cmd.CommandText = commandText;  
            if (commandTimeout.HasValue)  
                cmd.CommandTimeout = commandTimeout.Value;  
            if (commandType.HasValue)  
                cmd.CommandType = commandType.Value;  
            if (paramReader != null)  
            {  
                paramReader(cmd, parameters);  
            }  
            return cmd;  
        }  
  
  
        static SqlMapper.Link<Type, Action<IDbCommand>> commandInitCache;  
        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))  
            {  
                return action;  
            }  
            var bindByName = GetBasicPropertySetter(commandType, "BindByName", typeof(bool));  
            var initialLongFetchSize = GetBasicPropertySetter(commandType, "InitialLONGFetchSize", typeof(int));  
  
  
            action = null;  
            if (bindByName != null || initialLongFetchSize != null)  
            {  
                var method = new DynamicMethod(commandType.Name + "_init", null, new Type[] { typeof(IDbCommand) });  
                var il = method.GetILGenerator();  
  
  
                if (bindByName != null)  
                {  
                    // .BindByName = true  
                    il.Emit(OpCodes.Ldarg_0);  
                    il.Emit(OpCodes.Castclass, commandType);  
                    il.Emit(OpCodes.Ldc_I4_1);  
                    il.EmitCall(OpCodes.Callvirt, bindByName, null);  
                }  
                if (initialLongFetchSize != null)  
                {  
                    // .InitialLONGFetchSize = -1  
                    il.Emit(OpCodes.Ldarg_0);  
                    il.Emit(OpCodes.Castclass, commandType);  
                    il.Emit(OpCodes.Ldc_I4_M1);  
                    il.EmitCall(OpCodes.Callvirt, initialLongFetchSize, null);  
                }  
                il.Emit(OpCodes.Ret);  
                action = (Action<IDbCommand>)method.CreateDelegate(typeof(Action<IDbCommand>));  
            }  
            // cache it              
            SqlMapper.Link<Type, Action<IDbCommand>>.TryAdd(ref commandInitCache, commandType, ref action);  
            return action;  
        }  
        static MethodInfo GetBasicPropertySetter(Type declaringType, string name, Type expectedType)  
        {  
            var prop = declaringType.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);  
            ParameterInfo[] indexers;  
            if (prop != null && prop.CanWrite && prop.PropertyType == expectedType  
                && ((indexers = prop.GetIndexParameters()) == null || indexers.Length == 0))  
            {  
                return prop.GetSetMethod();  
            }  
            return null;  
        }  
    }  
  
  
    /// <summary>  
    /// Dapper, a light weight object mapper for ADO.NET  
    /// </summary>  
    static partial class SqlMapper  
    {  
        /// <summary>  
        /// Implement this interface to pass an arbitrary db specific set of parameters to Dapper  
        /// </summary>  
        public partial interface IDynamicParameters  
        {  
            /// <summary>  
            /// Add all the parameters needed to the command just before it executes  
            /// </summary>  
            /// <param name="command">The raw command prior to execution</param>  
            /// <param name="identity">Information about the query</param>  
            void AddParameters(IDbCommand command, Identity identity);  
        }  
  
  
        /// <summary>  
        /// Extends IDynamicParameters providing by-name lookup of parameter values  
        /// </summary>  
        public interface IParameterLookup : IDynamicParameters  
        {  
            /// <summary>  
            /// Get the value of the specified parameter (return null if not found)  
            /// </summary>  
            object this[string name] { get; }  
        }  
  
  
        /// <summary>  
        /// Extends IDynamicParameters with facilities for executing callbacks after commands have completed  
        /// </summary>  
        public partial interface IParameterCallbacks : IDynamicParameters  
        {  
            /// <summary>  
            /// Invoked when the command has executed  
            /// </summary>  
            void OnCompleted();  
        }  
  
  
        /// <summary>  
        /// Implement this interface to pass an arbitrary db specific parameter to Dapper  
        /// </summary>  
        [AssemblyNeutral]  
        public interface ICustomQueryParameter  
        {  
            /// <summary>  
            /// Add the parameter needed to the command before it executes  
            /// </summary>  
            /// <param name="command">The raw command prior to execution</param>  
            /// <param name="name">Parameter name</param>  
            void AddParameter(IDbCommand command, string name);  
        }  
  
  
        /// <summary>  
        /// Implement this interface to perform custom type-based parameter handling and value parsing  
        /// </summary>  
        [AssemblyNeutral]  
        public interface ITypeHandler  
        {  
            /// <summary>  
            /// Assign the value of a parameter before a command executes  
            /// </summary>  
            /// <param name="parameter">The parameter to configure</param>  
            /// <param name="value">Parameter value</param>  
            void SetValue(IDbDataParameter parameter, object value);  
  
  
            /// <summary>  
            /// Parse a database value back to a typed value  
            /// </summary>  
            /// <param name="value">The value from the database</param>  
            /// <param name="destinationType">The type to parse to</param>  
            /// <returns>The typed value</returns>  
            object Parse(Type destinationType, object value);  
        }  
  
  
        /// <summary>  
        /// A type handler for data-types that are supported by the underlying provider, but which need  
        /// a well-known UdtTypeName to be specified  
        /// </summary>  
        public class UdtTypeHandler : ITypeHandler  
        {  
            private readonly string udtTypeName;  
            /// <summary>  
            /// Creates a new instance of UdtTypeHandler with the specified UdtTypeName  
            /// </summary>  
            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;  
            }  
  
  
            void ITypeHandler.SetValue(IDbDataParameter parameter, object value)  
            {  
                parameter.Value = ((object)value) ?? DBNull.Value;  
                if (parameter is System.Data.SqlClient.SqlParameter)  
                {  
                    ((System.Data.SqlClient.SqlParameter)parameter).UdtTypeName = udtTypeName;  
                }  
            }  
        }  
  
  
        /// <summary>  
        /// Base-class for simple type-handlers  
        /// </summary>  
        public abstract class TypeHandler<T> : ITypeHandler  
        {  
            /// <summary>  
            /// Assign the value of a parameter before a command executes  
            /// </summary>  
            /// <param name="parameter">The parameter to configure</param>  
            /// <param name="value">Parameter value</param>  
            public abstract void SetValue(IDbDataParameter parameter, T value);  
  
  
            /// <summary>  
            /// Parse a database value back to a typed value  
            /// </summary>  
            /// <param name="value">The value from the database</param>  
            /// <returns>The typed value</returns>  
            public abstract T Parse(object value);  
  
  
            void ITypeHandler.SetValue(IDbDataParameter parameter, object value)  
            {  
                if (value is DBNull)  
                {  
                    parameter.Value = value;  
                }  
                else  
                {  
                    SetValue(parameter, (T)value);  
                }  
            }  
  
  
            object ITypeHandler.Parse(Type destinationType, object value)  
            {  
                return Parse(value);  
            }  
        }  
  
  
        /// <summary>  
        /// Implement this interface to change default mapping of reader columns to type members  
        /// </summary>  
        public interface ITypeMap  
        {  
            /// <summary>  
            /// Finds best constructor  
            /// </summary>  
            /// <param name="names">DataReader column names</param>  
            /// <param name="types">DataReader column types</param>  
            /// <returns>Matching constructor or default one</returns>  
            ConstructorInfo FindConstructor(string[] names, Type[] types);  
  
  
            /// <summary>  
            /// Returns a constructor which should *always* be used.  
            ///   
            /// Parameters will be default values, nulls for reference types and zero'd for value types.  
            ///   
            /// Use this class to force object creation away from parameterless constructors you don't control.  
            /// </summary>  
            ConstructorInfo FindExplicitConstructor();  
  
  
            /// <summary>  
            /// Gets mapping for constructor parameter  
            /// </summary>  
            /// <param name="constructor">Constructor to resolve</param>  
            /// <param name="columnName">DataReader column name</param>  
            /// <returns>Mapping implementation</returns>  
            IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName);  
  
  
            /// <summary>  
            /// Gets member mapping for column  
            /// </summary>  
            /// <param name="columnName">DataReader column name</param>  
            /// <returns>Mapping implementation</returns>  
            IMemberMap GetMember(string columnName);  
        }  
  
  
        /// <summary>  
        /// Implements this interface to provide custom member mapping  
        /// </summary>  
        public interface IMemberMap  
        {  
            /// <summary>  
            /// Source DataReader column name  
            /// </summary>  
            string ColumnName { get; }  
  
  
            /// <summary>  
            ///  Target member type  
            /// </summary>  
            Type MemberType { get; }  
  
  
            /// <summary>  
            /// Target property  
            /// </summary>  
            PropertyInfo Property { get; }  
  
  
            /// <summary>  
            /// Target field  
            /// </summary>  
            FieldInfo Field { get; }  
  
  
            /// <summary>  
            /// Target constructor parameter  
            /// </summary>  
            ParameterInfo Parameter { get; }  
        }  
  
  
        /// <summary>  
        /// This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example),  
        /// and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE**  
        /// equality. The type is fully thread-safe.  
        /// </summary>  
        internal partial class Link<TKey, TValue> where TKey : class  
        {  
            public static bool TryGet(Link<TKey, TValue> link, TKey key, out TValue value)  
            {  
                while (link != null)  
                {  
                    if ((object)key == (object)link.Key)  
                    {  
                        value = link.Value;  
                        return true;  
                    }  
                    link = link.Tail;  
                }  
                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))  
                    { // existing match; report the existing value instead  
                        value = found;  
                        return false;  
                    }  
                    var newNode = new Link<TKey, TValue>(key, value, snapshot);  
                    // did somebody move our cheese?  
                    tryAgain = Interlocked.CompareExchange(ref head, newNode, snapshot) != snapshot;  
                } while (tryAgain);  
                return true;  
            }  
            private Link(TKey key, TValue value, Link<TKey, TValue> tail)  
            {  
                Key = key;  
                Value = value;  
                Tail = tail;  
            }  
            public TKey Key { get; private set; }  
            public TValue Value { get; private set; }  
            public Link<TKey, TValue> Tail { get; private set; }  
        }  
        partial class CacheInfo  
        {  
            public DeserializerState Deserializer { get; set; }  
            public Func<IDataReader, object>[] OtherDeserializers { get; set; }  
            public Action<IDbCommand, object> ParamReader { get; set; }  
            private int hitCount;  
            public int GetHitCount() { return Interlocked.CompareExchange(ref hitCount, 0, 0); }  
            public void RecordHit() { Interlocked.Increment(ref hitCount); }  
        }  
        static int GetColumnHash(IDataReader reader)  
        {  
            unchecked  
            {  
                int colCount = reader.FieldCount, hash = colCount;  
                for (int i = 0; i < colCount; i++)  
                {   // binding code is only interested in names - not types  
                    object tmp = reader.GetName(i);  
                    hash = (hash * 31) + (tmp == null ? 0 : tmp.GetHashCode());  
                }  
                return hash;  
            }  
        }  
        struct DeserializerState  
        {  
            public readonly int Hash;  
            public readonly Func<IDataReader, object> Func;  
  
  
            public DeserializerState(int hash, Func<IDataReader, object> func)  
            {  
                Hash = hash;  
                Func = func;  
            }  
        }  
  
  
        /// <summary>  
        /// Called if the query cache is purged via PurgeQueryCache  
        /// </summary>  
        public static event EventHandler QueryCachePurged;  
        private static void OnQueryCachePurged()  
        {  
            var handler = QueryCachePurged;  
            if (handler != null) handler(null, EventArgs.Empty);  
        }  
#if CSHARP30  
        private static readonly Dictionary<Identity, CacheInfo> _queryCache = new Dictionary<Identity, CacheInfo>();  
        // note: conflicts between readers and writers are so short-lived that it isn't worth the overhead of  
        // ReaderWriterLockSlim etc; a simple lock is faster  
        private static void SetQueryCache(Identity key, CacheInfo value)  
        {  
            lock (_queryCache) { _queryCache[key] = value; }  
        }  
        private static bool TryGetQueryCache(Identity key, out CacheInfo value)  
        {  
            lock (_queryCache) { return _queryCache.TryGetValue(key, out value); }  
        }  
        private static void PurgeQueryCacheByType(Type type)  
        {  
            lock (_queryCache)  
            {  
                var toRemove = _queryCache.Keys.Where(id => id.type == type).ToArray();  
                foreach (var key in toRemove)  
                    _queryCache.Remove(key);  
            }  
        }  
        /// <summary>  
        /// Purge the query cache   
        /// </summary>  
        public static void PurgeQueryCache()  
        {  
            lock (_queryCache)  
            {  
                _queryCache.Clear();  
            }  
            OnQueryCachePurged();  
        }  
#else  
        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)  
            {  
                CollectCacheGarbage();  
            }  
            _queryCache[key] = value;  
        }  
  
  
        private static void CollectCacheGarbage()  
        {  
            try  
            {  
                foreach (var pair in _queryCache)  
                {  
                    if (pair.Value.GetHitCount() <= COLLECT_HIT_COUNT_MIN)  
                    {  
                        CacheInfo cache;  
                        _queryCache.TryRemove(pair.Key, out cache);  
                    }  
                }  
            }  
  
  
            finally  
            {  
                Interlocked.Exchange(ref collect, 0);  
            }  
        }  
  
  
        private const int COLLECT_PER_ITEMS = 1000, COLLECT_HIT_COUNT_MIN = 0;  
        private static int collect;  
        private static bool TryGetQueryCache(Identity key, out CacheInfo value)  
        {  
            if (_queryCache.TryGetValue(key, out value))  
            {  
                value.RecordHit();  
                return true;  
            }  
            value = null;  
            return false;  
        }  
  
  
        /// <summary>  
        /// Purge the query cache   
        /// </summary>  
        public static void PurgeQueryCache()  
        {  
            _queryCache.Clear();  
            OnQueryCachePurged();  
        }  
  
  
        private static void PurgeQueryCacheByType(Type type)  
        {  
            foreach (var entry in _queryCache)  
            {  
                CacheInfo cache;  
                if (entry.Key.type == type)  
                    _queryCache.TryRemove(entry.Key, out cache);  
            }  
        }  
  
  
        /// <summary>  
        /// Return a count of all the cached queries by dapper  
        /// </summary>  
        /// <returns></returns>  
        public static int GetCachedSQLCount()  
        {  
            return _queryCache.Count;  
        }  
  
  
        /// <summary>  
        /// Return a list of all the queries cached by dapper  
        /// </summary>  
        /// <param name="ignoreHitCountAbove"></param>  
        /// <returns></returns>  
        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;  
        }  
  
  
        /// <summary>  
        /// Deep diagnostics only: find any hash collisions in the cache  
        /// </summary>  
        /// <returns></returns>  
        public static IEnumerable<Tuple<int, int>> GetHashCollissions()  
        {  
            var counts = new Dictionary<int, int>();  
            foreach (var key in _queryCache.Keys)  
            {  
                int count;  
                if (!counts.TryGetValue(key.hashCode, out count))  
                {  
                    counts.Add(key.hashCode, 1);  
                }  
                else  
                {  
                    counts[key.hashCode] = count + 1;  
                }  
            }  
            return from pair in counts  
                   where pair.Value > 1  
                   select Tuple.Create(pair.Key, pair.Value);  
  
  
        }  
#endif  
  
  
  
  
        static Dictionary<Type, DbType> typeMap;  
  
  
        static SqlMapper()  
        {  
            typeMap = new Dictionary<Type, DbType>();  
            typeMap[typeof(byte)] = DbType.Byte;  
            typeMap[typeof(sbyte)] = DbType.SByte;  
            typeMap[typeof(short)] = DbType.Int16;  
            typeMap[typeof(ushort)] = DbType.UInt16;  
            typeMap[typeof(int)] = DbType.Int32;  
            typeMap[typeof(uint)] = DbType.UInt32;  
            typeMap[typeof(long)] = DbType.Int64;  
            typeMap[typeof(ulong)] = DbType.UInt64;  
            typeMap[typeof(float)] = DbType.Single;  
            typeMap[typeof(double)] = DbType.Double;  
            typeMap[typeof(decimal)] = DbType.Decimal;  
            typeMap[typeof(bool)] = DbType.Boolean;  
            typeMap[typeof(string)] = DbType.String;  
            typeMap[typeof(char)] = DbType.StringFixedLength;  
            typeMap[typeof(Guid)] = DbType.Guid;  
            typeMap[typeof(DateTime)] = DbType.DateTime;  
            typeMap[typeof(DateTimeOffset)] = DbType.DateTimeOffset;  
            typeMap[typeof(TimeSpan)] = DbType.Time;  
            typeMap[typeof(byte[])] = DbType.Binary;  
            typeMap[typeof(byte?)] = DbType.Byte;  
            typeMap[typeof(sbyte?)] = DbType.SByte;  
            typeMap[typeof(short?)] = DbType.Int16;  
            typeMap[typeof(ushort?)] = DbType.UInt16;  
            typeMap[typeof(int?)] = DbType.Int32;  
            typeMap[typeof(uint?)] = DbType.UInt32;  
            typeMap[typeof(long?)] = DbType.Int64;  
            typeMap[typeof(ulong?)] = DbType.UInt64;  
            typeMap[typeof(float?)] = DbType.Single;  
            typeMap[typeof(double?)] = DbType.Double;  
            typeMap[typeof(decimal?)] = DbType.Decimal;  
            typeMap[typeof(bool?)] = DbType.Boolean;  
            typeMap[typeof(char?)] = DbType.StringFixedLength;  
            typeMap[typeof(Guid?)] = DbType.Guid;  
            typeMap[typeof(DateTime?)] = DbType.DateTime;  
            typeMap[typeof(DateTimeOffset?)] = DbType.DateTimeOffset;  
            typeMap[typeof(TimeSpan?)] = DbType.Time;  
            typeMap[typeof(object)] = DbType.Object;  
  
  
            AddTypeHandlerImpl(typeof(DataTable), new DataTableHandler(), false);  
        }  
  
  
        /// <summary>  
        /// Clear the registered type handlers  
        /// </summary>  
        public static void ResetTypeHandlers()  
        {  
            typeHandlers = new Dictionary<Type, ITypeHandler>();  
            AddTypeHandlerImpl(typeof(DataTable), new DataTableHandler(), true);  
        }  
        /// <summary>  
        /// Configure the specified type to be mapped to a given db-type  
        /// </summary>  
        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  
  
  
            var newCopy = new Dictionary<Type, DbType>(snapshot);  
            newCopy[type] = dbType;  
            typeMap = newCopy;  
        }  
  
  
        /// <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);  
        }  
  
  
        /// <summary>  
        /// Configure the specified type to be processed by a custom handler  
        /// </summary>  
        public static void AddTypeHandlerImpl(Type type, ITypeHandler handler, bool clone)  
        {  
            if (type == null) throw new ArgumentNullException("type");  
  
  
            Type secondary = null;  
            if(type.IsValueType)  
            {  
                var underlying = Nullable.GetUnderlyingType(type);  
                if(underlying == null)  
                {  
                    secondary = typeof(Nullable<>).MakeGenericType(type); // the Nullable<T>  
                    // type is already the T  
                }  
                else  
                {  
                    secondary = type; // the Nullable<T>  
                    type = underlying; // the T  
                }  
            }  
  
  
            var snapshot = typeHandlers;  
            ITypeHandler oldValue;  
            if (snapshot.TryGetValue(type, out oldValue) && handler == oldValue) return; // nothing to do  
  
  
            var newCopy = clone ? new Dictionary<Type, ITypeHandler>(snapshot) : snapshot;  
 
 
#pragma warning disable 618  
            typeof(TypeHandlerCache<>).MakeGenericType(type).GetMethod("SetHandler", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { handler });  
            if(secondary != null)  
            {  
                typeof(TypeHandlerCache<>).MakeGenericType(secondary).GetMethod("SetHandler", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { handler });  
            }  
#pragma warning restore 618  
            if (handler == null)  
            {  
                newCopy.Remove(type);  
                if (secondary != null) newCopy.Remove(secondary);  
            }  
            else  
            {  
                newCopy[type] = handler;  
                if(secondary != null) newCopy[secondary] = handler;  
            }  
            typeHandlers = newCopy;  
        }  
  
  
        /// <summary>  
        /// Configure the specified type to be processed by a custom handler  
        /// </summary>  
        public static void AddTypeHandler<T>(TypeHandler<T> handler)  
        {  
            AddTypeHandlerImpl(typeof(T), handler, true);  
        }  
  
  
        /// <summary>  
        /// Not intended for direct usage  
        /// </summary>  
        [Obsolete("Not intended for direct usage", false)]  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]  
        public static class TypeHandlerCache<T>  
        {  
            /// <summary>  
            /// Not intended for direct usage  
            /// </summary>  
            [Obsolete("Not intended for direct usage", true)]  
            public static T Parse(object value)  
            {  
                return (T)handler.Parse(typeof(T), value);  
                  
            }  
  
  
            /// <summary>  
            /// Not intended for direct usage  
            /// </summary>  
            [Obsolete("Not intended for direct usage", true)]  
            public static void SetValue(IDbDataParameter parameter, object value)  
            {  
                handler.SetValue(parameter, value);  
            }  
  
  
            internal static void SetHandler(ITypeHandler handler)  
            {  
#pragma warning disable 618  
                TypeHandlerCache<T>.handler = handler;  
#pragma warning restore 618  
            }  
  
  
            private static ITypeHandler handler;  
        }  
  
  
        private static Dictionary<Type, ITypeHandler> typeHandlers = new Dictionary<Type, ITypeHandler>();  
  
  
        internal const string LinqBinary = "System.Data.Linq.Binary";  
  
  
        /// <summary>  
        /// Get the DbType that maps to a given value  
        /// </summary>  
        [Obsolete("This method is for internal use only"), Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]  
        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);  
  
  
        }  
        internal 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;  
            if (type.IsEnum && !typeMap.ContainsKey(type))  
            {  
                type = Enum.GetUnderlyingType(type);  
            }  
            if (typeMap.TryGetValue(type, out dbType))  
            {  
                return dbType;  
            }  
            if (type.FullName == LinqBinary)  
            {  
                return DbType.Binary;  
            }  
            if (typeof(IEnumerable).IsAssignableFrom(type))  
            {  
                return DynamicParameters.EnumerableMultiParameter;  
            }  
  
  
            if (typeHandlers.TryGetValue(type, out handler))  
            {  
                return DbType.Object;  
            }  
            switch (type.FullName)  
            {  
                case "Microsoft.SqlServer.Types.SqlGeography":  
                    AddTypeHandler(type, handler = new UdtTypeHandler("GEOGRAPHY"));  
                    return DbType.Object;  
                case "Microsoft.SqlServer.Types.SqlGeometry":  
                    AddTypeHandler(type, handler = new UdtTypeHandler("GEOMETRY"));  
                    return DbType.Object;  
                case "Microsoft.SqlServer.Types.SqlHierarchyId":  
                    AddTypeHandler(type, handler = new UdtTypeHandler("HIERARCHYID"));  
                    return DbType.Object;  
            }  
            if(demand)  
                throw new NotSupportedException(string.Format("The member {0} of type {1} cannot be used as a parameter value", name, type.FullName));  
            return DbType.Object;  
  
  
        }  
  
  
        /// <summary>  
        /// Identity of a cached query in Dapper, used for extensibility  
        /// </summary>  
        public partial class Identity : IEquatable<Identity>  
        {  
            internal Identity ForGrid(Type primaryType, int gridIndex)  
            {  
                return new Identity(sql, commandType, connectionString, primaryType, parametersType, null, gridIndex);  
            }  
  
  
            internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex)  
            {  
                return new Identity(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex);  
            }  
            /// <summary>  
            /// Create an identity for use with DynamicParameters, internal use only  
            /// </summary>  
            /// <param name="type"></param>  
            /// <returns></returns>  
            public Identity ForDynamicParameters(Type type)  
            {  
                return new Identity(sql, commandType, connectionString, this.type, type, null, -1);  
            }  
  
  
            internal Identity(string sql, CommandType? commandType, IDbConnection connection, Type type, Type parametersType, Type[] otherTypes)  
                : this(sql, commandType, connection.ConnectionString, type, parametersType, otherTypes, 0)  
            { }  
            private Identity(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, Type[] otherTypes, int gridIndex)  
            {  
                this.sql = sql;  
                this.commandType = commandType;  
                this.connectionString = connectionString;  
                this.type = type;  
                this.parametersType = parametersType;  
                this.gridIndex = gridIndex;  
                unchecked  
                {  
                    hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this  
                    hashCode = hashCode * 23 + commandType.GetHashCode();  
                    hashCode = hashCode * 23 + gridIndex.GetHashCode();  
                    hashCode = hashCode * 23 + (sql == null ? 0 : sql.GetHashCode());  
                    hashCode = hashCode * 23 + (type == null ? 0 : type.GetHashCode());  
                    if (otherTypes != null)  
                    {  
                        foreach (var t in otherTypes)  
                        {  
                            hashCode = hashCode * 23 + (t == null ? 0 : t.GetHashCode());  
                        }  
                    }  
                    hashCode = hashCode * 23 + (connectionString == null ? 0 : SqlMapper.connectionStringComparer.GetHashCode(connectionString));  
                    hashCode = hashCode * 23 + (parametersType == null ? 0 : parametersType.GetHashCode());  
                }  
            }  
  
  
            /// <summary>  
            ///   
            /// </summary>  
            /// <param name="obj"></param>  
            /// <returns></returns>  
            public override bool Equals(object obj)  
            {  
                return Equals(obj as Identity);  
            }  
            /// <summary>  
            /// The sql  
            /// </summary>  
            public readonly string sql;  
            /// <summary>  
            /// The command type   
            /// </summary>  
            public readonly CommandType? commandType;  
  
  
            /// <summary>  
            ///   
            /// </summary>  
            public readonly int hashCode, gridIndex;  
            /// <summary>  
            ///   
            /// </summary>  
            public readonly Type type;  
            /// <summary>  
            ///   
            /// </summary>  
            public readonly string connectionString;  
            /// <summary>  
            ///   
            /// </summary>  
            public readonly Type parametersType;  
            /// <summary>  
            ///   
            /// </summary>  
            /// <returns></returns>  
            public override int GetHashCode()  
            {  
                return hashCode;  
            }  
            /// <summary>  
            /// Compare 2 Identity objects  
            /// </summary>  
            /// <param name="other"></param>  
            /// <returns></returns>  
            public bool Equals(Identity other)  
            {  
                return  
                    other != null &&  
                    gridIndex == other.gridIndex &&  
                    type == other.type &&  
                    sql == other.sql &&  
                    commandType == other.commandType &&  
                    SqlMapper.connectionStringComparer.Equals(connectionString, other.connectionString) &&  
                    parametersType == other.parametersType;  
            }  
        }  
 
 
#if CSHARP30  
        /// <summary>  
        /// Execute parameterized SQL    
        /// </summary>  
        /// <returns>Number of rows affected</returns>  
        public static int Execute(this IDbConnection cnn, string sql, object param)  
        {  
            return Execute(cnn, sql, param, null, null, null);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL  
        /// </summary>  
        /// <returns>Number of rows affected</returns>  
        public static int Execute(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)  
        {  
            return Execute(cnn, sql, param, transaction, null, null);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL  
        /// </summary>  
        /// <returns>Number of rows affected</returns>  
        public static int Execute(this IDbConnection cnn, string sql, object param, CommandType commandType)  
        {  
            return Execute(cnn, sql, param, null, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL  
        /// </summary>  
        /// <returns>Number of rows affected</returns>  
        public static int Execute(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType commandType)  
        {  
            return Execute(cnn, sql, param, transaction, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL and return an <see cref="IDataReader"/>  
        /// </summary>  
        /// <returns>An <see cref="IDataReader"/> that can be used to iterate over the results of the SQL query.</returns>  
        public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, object param)  
        {  
            return ExecuteReader(cnn, sql, param, null, null, null);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL and return an <see cref="IDataReader"/>  
        /// </summary>  
        /// <returns>An <see cref="IDataReader"/> that can be used to iterate over the results of the SQL query.</returns>  
        public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)  
        {  
            return ExecuteReader(cnn, sql, param, transaction, null, null);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL and return an <see cref="IDataReader"/>  
        /// </summary>  
        /// <returns>An <see cref="IDataReader"/> that can be used to iterate over the results of the SQL query.</returns>  
        public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, object param, CommandType commandType)  
        {  
            return ExecuteReader(cnn, sql, param, null, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL and return an <see cref="IDataReader"/>  
        /// </summary>  
        /// <returns>An <see cref="IDataReader"/> that can be used to iterate over the results of the SQL query.</returns>  
        public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType commandType)  
        {  
            return ExecuteReader(cnn, sql, param, transaction, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Executes a query, returning the data typed as per T  
        /// </summary>  
        /// <returns>A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is  
        /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
        /// </returns>  
        public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param)  
        {  
            return Query<T>(cnn, sql, param, null, true, null, null);  
        }  
  
  
        /// <summary>  
        /// Executes a query, returning the data typed as per T  
        /// </summary>  
        /// <returns>A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is  
        /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
        /// </returns>  
        public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)  
        {  
            return Query<T>(cnn, sql, param, transaction, true, null, null);  
        }  
  
  
        /// <summary>  
        /// Executes a query, returning the data typed as per T  
        /// </summary>  
        /// <returns>A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is  
        /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
        /// </returns>  
        public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param, CommandType commandType)  
        {  
            return Query<T>(cnn, sql, param, null, true, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Executes a query, returning the data typed as per T  
        /// </summary>  
        /// <returns>A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is  
        /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
        /// </returns>  
        public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType commandType)  
        {  
            return Query<T>(cnn, sql, param, transaction, true, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Execute a command that returns multiple result sets, and access each in turn  
        /// </summary>  
        public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)  
        {  
            return QueryMultiple(cnn, sql, param, transaction, null, null);  
        }  
  
  
        /// <summary>  
        /// Execute a command that returns multiple result sets, and access each in turn  
        /// </summary>  
        public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, CommandType commandType)  
        {  
            return QueryMultiple(cnn, sql, param, null, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Execute a command that returns multiple result sets, and access each in turn  
        /// </summary>  
        public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType commandType)  
        {  
            return QueryMultiple(cnn, sql, param, transaction, null, commandType);  
        }  
#endif  
  
  
  
  
        /// <summary>  
        /// Execute parameterized SQL    
        /// </summary>  
        /// <returns>Number of rows affected</returns>  
        public static int Execute(  
#if CSHARP30  
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            var command = new CommandDefinition(sql, (object)param, transaction, commandTimeout, commandType, CommandFlags.Buffered);  
            return ExecuteImpl(cnn, ref command);  
        }  
        /// <summary>  
        /// Execute parameterized SQL    
        /// </summary>  
        /// <returns>Number of rows affected</returns>  
        public static int Execute(this IDbConnection cnn, CommandDefinition command)  
        {  
            return ExecuteImpl(cnn, ref command);  
        }  
  
  
  
  
        /// <summary>  
        /// Execute parameterized SQL that selects a single value  
        /// </summary>  
        /// <returns>The first cell selected</returns>  
        public static object ExecuteScalar(  
#if CSHARP30  
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            var command = new CommandDefinition(sql, (object)param, transaction, commandTimeout, commandType, CommandFlags.Buffered);  
            return 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>(  
#if CSHARP30  
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            var command = new CommandDefinition(sql, (object)param, transaction, commandTimeout, commandType, CommandFlags.Buffered);  
            return ExecuteScalarImpl<T>(cnn, ref command);  
        }  
  
  
        /// <summary>  
        /// 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);  
        }  
  
  
        /// <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);  
        }  
  
  
        private static IEnumerable GetMultiExec(object param)  
        {  
            return (param is IEnumerable  
                && !(param is string || param is IEnumerable<KeyValuePair<string, object>>  
                    )) ? (IEnumerable)param : null;  
        }  
  
  
        private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition command)  
        {  
            object param = command.Parameters;  
            IEnumerable multiExec = GetMultiExec(param);  
            Identity identity;  
            CacheInfo info = null;  
            if (multiExec != null)  
            {  
#if ASYNC  
                if((command.Flags & CommandFlags.Pipelined) != 0)  
                {  
                    // this includes all the code for concurrent/overlapped query  
                    return ExecuteMultiImplAsync(cnn, command, multiExec).Result;  
                }  
#endif  
                bool isFirst = true;  
                int total = 0;  
                bool wasClosed = cnn.State == ConnectionState.Closed;  
                try  
                {  
                    if (wasClosed) cnn.Open();  
                    using (var cmd = command.SetupCommand(cnn, null))  
                    {  
                        string masterSql = null;  
                        foreach (var obj in multiExec)  
                        {  
                            if (isFirst)  
                            {  
                                masterSql = cmd.CommandText;  
                                isFirst = false;  
                                identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType(), null);  
                                info = GetCacheInfo(identity, obj, command.AddToCache);  
                            }  
                            else  
                            {  
                                cmd.CommandText = masterSql; // because we do magic replaces on "in" etc  
                                cmd.Parameters.Clear(); // current code is Add-tastic  
                            }  
                            info.ParamReader(cmd, obj);  
                            total += cmd.ExecuteNonQuery();  
                        }  
                    }  
                    command.OnCompleted();  
                } finally  
                {  
                    if (wasClosed) cnn.Close();  
                }  
                return total;  
            }  
  
  
            // nice and simple  
            if (param != null)  
            {  
                identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType(), null);  
                info = GetCacheInfo(identity, param, command.AddToCache);  
            }  
            return ExecuteCommand(cnn, ref command, param == null ? null : info.ParamReader);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL and return an <see cref="IDataReader"/>  
        /// </summary>  
        /// <returns>An <see cref="IDataReader"/> that can be used to iterate over the results of the SQL query.</returns>  
        /// <remarks>  
        /// This is typically used when the results of a query are not processed by Dapper, for example, used to fill a <see cref="DataTable"/>  
        /// or <see cref="DataSet"/>.  
        /// </remarks>  
        /// <example>  
        /// <code>  
        /// <![CDATA[  
        /// DataTable table = new DataTable("MyTable");  
        /// using (var reader = ExecuteReader(cnn, sql, param))  
        /// {  
        ///     table.Load(reader);  
        /// }  
        /// ]]>  
        /// </code>  
        /// </example>  
        public static IDataReader ExecuteReader(  
#if CSHARP30  
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            var command = new CommandDefinition(sql, (object)param, transaction, commandTimeout, commandType, CommandFlags.Buffered);  
            IDbCommand dbcmd;  
            var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out dbcmd);  
            return new WrappedReader(dbcmd, reader);  
        }  
  
  
        /// <summary>  
        /// Execute parameterized SQL and return an <see cref="IDataReader"/>  
        /// </summary>  
        /// <returns>An <see cref="IDataReader"/> that can be used to iterate over the results of the SQL query.</returns>  
        /// <remarks>  
        /// This is typically used when the results of a query are not processed by Dapper, for example, used to fill a <see cref="DataTable"/>  
        /// or <see cref="DataSet"/>.  
        /// </remarks>  
        public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command)  
        {  
            IDbCommand dbcmd;  
            var reader = ExecuteReaderImpl(cnn, ref command, CommandBehavior.Default, out dbcmd);  
            return new WrappedReader(dbcmd, reader);  
        }  
        /// <summary>  
        /// Execute parameterized SQL and return an <see cref="IDataReader"/>  
        /// </summary>  
        /// <returns>An <see cref="IDataReader"/> that can be used to iterate over the results of the SQL query.</returns>  
        /// <remarks>  
        /// This is typically used when the results of a query are not processed by Dapper, for example, used to fill a <see cref="DataTable"/>  
        /// or <see cref="DataSet"/>.  
        /// </remarks>  
        public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)  
        {  
            IDbCommand dbcmd;  
            var reader = ExecuteReaderImpl(cnn, ref command, commandBehavior, out dbcmd);  
            return new WrappedReader(dbcmd, reader);  
        }  
 
 
#if !CSHARP30  
        /// <summary>  
        /// Return a list of dynamic objects, reader is closed after the call  
        /// </summary>  
        /// <remarks>Note: each row can be accessed via "dynamic", or by casting to an IDictionary<string,object></remarks>  
        public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)  
        {  
            return Query<DapperRow>(cnn, sql, param as object, transaction, buffered, commandTimeout, commandType);  
        }  
#else  
        /// <summary>  
        /// Return a list of dynamic objects, reader is closed after the call  
        /// </summary>  
        public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param)  
        {  
            return Query(cnn, sql, param, null, true, null, null);  
        }  
  
  
        /// <summary>  
        /// Return a list of dynamic objects, reader is closed after the call  
        /// </summary>  
        public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)  
        {  
            return Query(cnn, sql, param, transaction, true, null, null);  
        }  
  
  
        /// <summary>  
        /// Return a list of dynamic objects, reader is closed after the call  
        /// </summary>  
        public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, CommandType? commandType)  
        {  
            return Query(cnn, sql, param, null, true, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Return a list of dynamic objects, reader is closed after the call  
        /// </summary>  
        public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType? commandType)  
        {  
            return Query(cnn, sql, param, transaction, true, null, commandType);  
        }  
  
  
        /// <summary>  
        /// Return a list of dynamic objects, reader is closed after the call  
        /// </summary>  
        public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, bool buffered, int? commandTimeout, CommandType? commandType)  
        {  
            return Query<IDictionary<string, object>>(cnn, sql, param, transaction, buffered, commandTimeout, commandType);  
        }  
#endif  
  
  
        /// <summary>  
        /// Executes a query, returning the data typed as per T  
        /// </summary>  
        /// <remarks>the dynamic param may seem a bit odd, but this works around a major usability issue in vs, if it is Object vs completion gets annoying. Eg type new [space] get new object</remarks>  
        /// <returns>A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is  
        /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
        /// </returns>  
        public static IEnumerable<T> Query<T>(  
#if CSHARP30  
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, bool buffered, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            var command = new CommandDefinition(sql, (object)param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);  
            var data = QueryImpl<T>(cnn, command, typeof(T));  
            return command.Buffered ? data.ToList() : data;  
        }  
  
  
        /// <summary>  
        /// Executes a query, returning the data typed as per the Type suggested  
        /// </summary>  
        /// <returns>A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is  
        /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
        /// </returns>  
        public static IEnumerable<object> Query(  
#if CSHARP30  
this IDbConnection cnn, Type type, string sql, object param, IDbTransaction transaction, bool buffered, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null  
#endif  
        )  
        {  
            if (type == null) throw new ArgumentNullException("type");  
            var command = new CommandDefinition(sql, (object)param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);  
            var data = QueryImpl<object>(cnn, command, type);  
            return command.Buffered ? data.ToList() : data;  
        }  
        /// <summary>  
        /// Executes a query, returning the data typed as per T  
        /// </summary>  
        /// <remarks>the dynamic param may seem a bit odd, but this works around a major usability issue in vs, if it is Object vs completion gets annoying. Eg type new [space] get new object</remarks>  
        /// <returns>A sequence of data of the supplied type; if a basic type (int, string, etc) is queried then the data from the first column in assumed, otherwise an instance is  
        /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
        /// </returns>  
        public static IEnumerable<T> Query<T>(this IDbConnection cnn, CommandDefinition command)  
        {  
            var data = QueryImpl<T>(cnn, command, typeof(T));  
            return command.Buffered ? data.ToList() : data;  
        }  
  
  
  
  
  
  
        /// <summary>  
        /// Execute a command that returns multiple result sets, and access each in turn  
        /// </summary>  
        public static GridReader QueryMultiple(  
#if CSHARP30  
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType  
#else  
            this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            var command = new CommandDefinition(sql, (object)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);  
        }  
        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 == null ? null : param.GetType(), null);  
            CacheInfo info = GetCacheInfo(identity, param, command.AddToCache);  
  
  
            IDbCommand cmd = null;  
            IDataReader reader = null;  
            bool wasClosed = cnn.State == ConnectionState.Closed;  
            try  
            {  
                if (wasClosed) cnn.Open();  
                cmd = command.SetupCommand(cnn, info.ParamReader);  
                reader = cmd.ExecuteReader(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess);  
  
  
                var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters);  
                cmd = null; // now owned by result  
                wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader  
                // with the CloseConnection flag, so the reader will deal with the connection; we  
                // still need something in the "finally" to ensure that broken SQL still results  
                // in the connection closing itself  
                return result;  
            }  
            catch  
            {  
                if (reader != null)  
                {  
                    if (!reader.IsClosed) try { cmd.Cancel(); }  
                        catch { /* don't spoil the existing exception */ }  
                    reader.Dispose();  
                }  
                if (cmd != null) cmd.Dispose();  
                if (wasClosed) cnn.Close();  
                throw;  
            }  
        }  
  
  
        private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType)  
        {  
            object param = command.Parameters;  
            var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param == null ? null : param.GetType(), null);  
            var info = GetCacheInfo(identity, param, command.AddToCache);  
  
  
            IDbCommand cmd = null;  
            IDataReader reader = null;  
  
  
            bool wasClosed = cnn.State == ConnectionState.Closed;  
            try  
            {  
                cmd = command.SetupCommand(cnn, info.ParamReader);  
  
  
                if (wasClosed) cnn.Open();  
                reader = cmd.ExecuteReader(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess);  
                wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader  
                // with the CloseConnection flag, so the reader will deal with the connection; we  
                // still need something in the "finally" to ensure that broken SQL still results  
                // in the connection closing itself  
                var tuple = info.Deserializer;  
                int hash = GetColumnHash(reader);  
                if (tuple.Func == null || tuple.Hash != hash)  
                {  
                    if (reader.FieldCount == 0) //https://code.google.com/p/dapper-dot-net/issues/detail?id=57  
                        yield break;  
                    tuple = info.Deserializer = new DeserializerState(hash, GetDeserializer(effectiveType, reader, 0, -1, false));  
                    if(command.AddToCache) SetQueryCache(identity, info);  
                }  
  
  
                var func = tuple.Func;  
                var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType;  
                while (reader.Read())  
                {  
                    object val = func(reader);  
                    if (val == null || val is T) {  
                        yield return (T)val;  
                    } else {  
                        yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);  
                    }  
                }  
                while (reader.NextResult()) { }  
                // happy path; close the reader cleanly - no  
                // need for "Cancel" etc  
                reader.Dispose();  
                reader = null;  
  
  
                command.OnCompleted();  
            }  
            finally  
            {  
                if (reader != null)  
                {  
                    if (!reader.IsClosed) try { cmd.Cancel(); }  
                        catch { /* don't spoil the existing exception */ }  
                    reader.Dispose();  
                }  
                if (wasClosed) cnn.Close();  
                if (cmd != null) cmd.Dispose();  
            }  
        }  
  
  
        /// <summary>  
        /// Maps a query to objects  
        /// </summary>  
        /// <typeparam name="TFirst">The first type in the record set</typeparam>  
        /// <typeparam name="TSecond">The second type in the record set</typeparam>  
        /// <typeparam name="TReturn">The return type</typeparam>  
        /// <param name="cnn"></param>  
        /// <param name="sql"></param>  
        /// <param name="map"></param>  
        /// <param name="param"></param>  
        /// <param name="transaction"></param>  
        /// <param name="buffered"></param>  
        /// <param name="splitOn">The Field we should split and read the second object from (default: id)</param>  
        /// <param name="commandTimeout">Number of seconds before command execution timeout</param>  
        /// <param name="commandType">Is it a stored proc or a batch?</param>  
        /// <returns></returns>  
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(  
#if CSHARP30  
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            return MultiMap<TFirst, TSecond, DontMap, DontMap, DontMap, DontMap, DontMap, TReturn>(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType);  
        }  
  
  
        /// <summary>  
        /// Maps a query to objects  
        /// </summary>  
        /// <typeparam name="TFirst"></typeparam>  
        /// <typeparam name="TSecond"></typeparam>  
        /// <typeparam name="TThird"></typeparam>  
        /// <typeparam name="TReturn"></typeparam>  
        /// <param name="cnn"></param>  
        /// <param name="sql"></param>  
        /// <param name="map"></param>  
        /// <param name="param"></param>  
        /// <param name="transaction"></param>  
        /// <param name="buffered"></param>  
        /// <param name="splitOn">The Field we should split and read the second object from (default: id)</param>  
        /// <param name="commandTimeout">Number of seconds before command execution timeout</param>  
        /// <param name="commandType"></param>  
        /// <returns></returns>  
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(  
#if CSHARP30  
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            return MultiMap<TFirst, TSecond, TThird, DontMap, DontMap, DontMap, DontMap, TReturn>(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType);  
        }  
  
  
        /// <summary>  
        /// Perform a multi mapping query with 4 input parameters  
        /// </summary>  
        /// <typeparam name="TFirst"></typeparam>  
        /// <typeparam name="TSecond"></typeparam>  
        /// <typeparam name="TThird"></typeparam>  
        /// <typeparam name="TFourth"></typeparam>  
        /// <typeparam name="TReturn"></typeparam>  
        /// <param name="cnn"></param>  
        /// <param name="sql"></param>  
        /// <param name="map"></param>  
        /// <param name="param"></param>  
        /// <param name="transaction"></param>  
        /// <param name="buffered"></param>  
        /// <param name="splitOn"></param>  
        /// <param name="commandTimeout"></param>  
        /// <param name="commandType"></param>  
        /// <returns></returns>  
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TReturn>(  
#if CSHARP30  
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType  
#else  
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null  
#endif  
)  
        {  
            return MultiMap<TFirst, TSecond, TThird, TFourth, DontMap, DontMap, DontMap, TReturn>(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType);  
        }  
 
 
#if !CSHARP30  
        /// <summary>  
        /// Perform a multi mapping query with 5 input parameters  
        /// </summary>  
        /// <typeparam name="TFirst"></typeparam>  
        /// <typeparam name="TSecond"></typeparam>  
        /// <typeparam name="TThird"></typeparam>  
        /// <typeparam name="TFourth"></typeparam>  
        /// <typeparam name="TFifth"></typeparam>  
        /// <typeparam name="TReturn"></typeparam>  
        /// <param name="cnn"></param>  
        /// <param name="sql"></param>  
        /// <param name="map"></param>  
        /// <param name="param"></param>  
        /// <param name="transaction"></param>  
        /// <param name="buffered"></param>  
        /// <param name="splitOn"></param>  
        /// <param name="commandTimeout"></param>  
        /// <param name="commandType"></param>  
        /// <returns></returns>  
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(  
            this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null  
)  
        {  
            return MultiMap<TFirst, TSecond, TThird, TFourth, TFifth, DontMap, DontMap, TReturn>(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType);  
        }  
  
  
        /// <summary>  
        /// Perform a multi mapping query with 6 input parameters  
        /// </summary>  
        /// <typeparam name="TFirst"></typeparam>  
        /// <typeparam name="TSecond"></typeparam>  
        /// <typeparam name="TThird"></typeparam>  
        /// <typeparam name="TFourth"></typeparam>  
        /// <typeparam name="TFifth"></typeparam>  
        /// <typeparam name="TSixth"></typeparam>  
        /// <typeparam name="TReturn"></typeparam>  
        /// <param name="cnn"></param>  
        /// <param name="sql"></param>  
        /// <param name="map"></param>  
        /// <param name="param"></param>  
        /// <param name="transaction"></param>  
        /// <param name="buffered"></param>  
        /// <param name="splitOn"></param>  
        /// <param name="commandTimeout"></param>  
        /// <param name="commandType"></param>  
        /// <returns></returns>  
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn>(  
            this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null  
)  
        {  
            return MultiMap<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, DontMap, TReturn>(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType);  
        }  
  
  
  
  
        /// <summary>  
        /// Perform a multi mapping query with 7 input parameters  
        /// </summary>  
        /// <typeparam name="TFirst"></typeparam>  
        /// <typeparam name="TSecond"></typeparam>  
        /// <typeparam name="TThird"></typeparam>  
        /// <typeparam name="TFourth"></typeparam>  
        /// <typeparam name="TFifth"></typeparam>  
        /// <typeparam name="TSixth"></typeparam>  
        /// <typeparam name="TSeventh"></typeparam>  
        /// <typeparam name="TReturn"></typeparam>  
        /// <param name="cnn"></param>  
        /// <param name="sql"></param>  
        /// <param name="map"></param>  
        /// <param name="param"></param>  
        /// <param name="transaction"></param>  
        /// <param name="buffered"></param>  
        /// <param name="splitOn"></param>  
        /// <param name="commandTimeout"></param>  
        /// <param name="commandType"></param>  
        /// <returns></returns>  
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)  
        {  
            return MultiMap<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType);  
        }  
  
  
        /// <summary>  
        /// Perform a multi mapping query with arbitrary input parameters  
        /// </summary>  
        /// <typeparam name="TReturn">The return type</typeparam>  
        /// <param name="cnn"></param>  
        /// <param name="sql"></param>  
        /// <param name="types">array of types in the record set</param>  
        /// <param name="map"></param>  
        /// <param name="param"></param>  
        /// <param name="transaction"></param>  
        /// <param name="buffered"></param>  
        /// <param name="splitOn">The Field we should split and read the second object from (default: id)</param>  
        /// <param name="commandTimeout">Number of seconds before command execution timeout</param>  
        /// <param name="commandType">Is it a stored proc or a batch?</param>  
        /// <returns></returns>  
        public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string sql, Type[] types, Func<object[], TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)  
        {  
            var command = new CommandDefinition(sql, (object)param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);  
            var results = MultiMapImpl<TReturn>(cnn, command, types, map, splitOn, null, null, true);  
            return buffered ? results.ToList() : results;  
        }  
#endif  
        partial class DontMap { }  
        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, (object)param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None);  
            var results = MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(cnn, command, map, splitOn, null, null, true);  
            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)  
        {  
            object param = command.Parameters;  
            identity = identity ?? new Identity(command.CommandText, command.CommandType, cnn, typeof(TFirst), param == null ? null : param.GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) });  
            CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache);  
  
  
            IDbCommand ownedCommand = null;  
            IDataReader ownedReader = null;  
  
  
            bool wasClosed = cnn != null && cnn.State == ConnectionState.Closed;  
            try  
            {  
                if (reader == null)  
                {  
                    ownedCommand = command.SetupCommand(cnn, cinfo.ParamReader);  
                    if (wasClosed) cnn.Open();  
                    ownedReader = ownedCommand.ExecuteReader(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess);  
                    reader = ownedReader;  
                }  
                DeserializerState deserializer = default(DeserializerState);  
                Func<IDataReader, object>[] otherDeserializers = null;  
  
  
                int hash = GetColumnHash(reader);  
                if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash)  
                {  
                    var deserializers = GenerateDeserializers(new Type[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }, splitOn, reader);  
                    deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]);  
                    otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray();  
                    if(command.AddToCache) SetQueryCache(identity, cinfo);  
                }  
  
  
                Func<IDataReader, TReturn> mapIt = GenerateMapper<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(deserializer.Func, otherDeserializers, map);  
  
  
                if (mapIt != null)  
                {  
                    while (reader.Read())  
                    {  
                        yield return mapIt(reader);  
                    }  
                    if(finalize)  
                    {  
                        while (reader.NextResult()) { }  
                        command.OnCompleted();  
                    }                      
                }  
            }  
            finally  
            {  
                try  
                {  
                    if (ownedReader != null)  
                    {  
                        ownedReader.Dispose();  
                    }  
                }  
                finally  
                {  
                    if (ownedCommand != null)  
                    {  
                        ownedCommand.Dispose();  
                    }  
                    if (wasClosed) cnn.Close();  
                }  
            }  
        }  
  
  
        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)  
            {  
                throw new ArgumentException("you must provide at least one type to deserialize");  
            }  
  
  
            object param = command.Parameters;  
            identity = identity ?? new Identity(command.CommandText, command.CommandType, cnn, types[0], param == null ? null : param.GetType(), types);  
            CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache);  
  
  
            IDbCommand ownedCommand = null;  
            IDataReader ownedReader = null;  
  
  
            bool wasClosed = cnn != null && cnn.State == ConnectionState.Closed;  
            try  
            {  
                if (reader == null)  
                {  
                    ownedCommand = command.SetupCommand(cnn, cinfo.ParamReader);  
                    if (wasClosed) cnn.Open();  
                    ownedReader = ownedCommand.ExecuteReader();  
                    reader = ownedReader;  
                }  
                DeserializerState deserializer = default(DeserializerState);  
                Func<IDataReader, object>[] otherDeserializers = null;  
  
  
                int hash = GetColumnHash(reader);  
                if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash)  
                {  
                    var deserializers = GenerateDeserializers(types, splitOn, reader);  
                    deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]);  
                    otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray();  
                    SetQueryCache(identity, cinfo);  
                }  
  
  
                Func<IDataReader, TReturn> mapIt = GenerateMapper(types.Length, deserializer.Func, otherDeserializers, map);  
  
  
                if (mapIt != null)  
                {  
                    while (reader.Read())  
                    {  
                        yield return mapIt(reader);  
                    }  
                    if (finalize)  
                    {  
                        while (reader.NextResult()) { }  
                        command.OnCompleted();  
                    }  
                }  
            }  
            finally  
            {  
                try  
                {  
                    if (ownedReader != null)  
                    {  
                        ownedReader.Dispose();  
                    }  
                }  
                finally  
                {  
                    if (ownedCommand != null)  
                    {  
                        ownedCommand.Dispose();  
                    }  
                    if (wasClosed) cnn.Close();  
                }  
            }  
        }  
  
  
        private static Func<IDataReader, TReturn> GenerateMapper<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(Func<IDataReader, object> deserializer, Func<IDataReader, object>[] otherDeserializers, object map)  
        {  
            switch (otherDeserializers.Length)  
            {  
                case 1:  
                    return r => ((Func<TFirst, TSecond, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r));  
                case 2:  
                    return r => ((Func<TFirst, TSecond, TThird, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r));  
                case 3:  
                    return r => ((Func<TFirst, TSecond, TThird, TFourth, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r));  
#if !CSHARP30  
                case 4:  
                    return r => ((Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r));  
                case 5:  
                    return r => ((Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r), (TSixth)otherDeserializers[4](r));  
                case 6:  
                    return r => ((Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r), (TSixth)otherDeserializers[4](r), (TSeventh)otherDeserializers[5](r));  
#endif  
                default:  
                    throw new NotSupportedException();  
            }  
        }  
  
  
        private static Func<IDataReader, TReturn> GenerateMapper<TReturn>(int length, Func<IDataReader, object> deserializer, Func<IDataReader, object>[] otherDeserializers, Func<object[], TReturn> map)  
        {  
            return r =>  
            {  
                var objects = new object[length];  
                objects[0] = deserializer(r);  
  
  
                for (var i = 1; i < length; ++i)  
                {  
                    objects[i] = otherDeserializers[i - 1](r);  
                }  
  
  
                return map(objects);  
            };  
        }  
  
  
        private static Func<IDataReader, object>[] GenerateDeserializers(Type[] types, string splitOn, IDataReader reader)  
        {  
            var deserializers = new List<Func<IDataReader, object>>();  
            var splits = splitOn.Split(',').Select(s => s.Trim()).ToArray();  
                bool isMultiSplit = splits.Length > 1;  
            if (types.First() == typeof(Object))  
            {  
                // we go left to right for dynamic multi-mapping so that the madness of TestMultiMappingVariations  
                // is supported  
                bool first = true;  
                int currentPos = 0;  
                int splitIdx = 0;  
                string currentSplit = splits[splitIdx];  
                foreach (var type in types)  
                {  
                    if (type == typeof(DontMap))  
                    {  
                        break;  
                    }  
  
  
                    int splitPoint = GetNextSplitDynamic(currentPos, currentSplit, reader);  
                    if (isMultiSplit && splitIdx < splits.Length - 1)  
                    {  
                        currentSplit = splits[++splitIdx];  
                    }  
                    deserializers.Add((GetDeserializer(type, reader, currentPos, splitPoint - currentPos, !first)));  
                    currentPos = splitPoint;  
                    first = false;  
                }  
            }  
            else  
            {  
                // in this we go right to left through the data reader in order to cope with properties that are  
                // named the same as a subsequent primary key that we split on  
                int currentPos = reader.FieldCount;  
                int splitIdx = splits.Length - 1;  
                var currentSplit = splits[splitIdx];  
                for (var typeIdx = types.Length - 1; typeIdx >= 0; --typeIdx)  
                {  
                    var type = types[typeIdx];  
                    if (type == typeof (DontMap))  
                    {  
                        continue;  
                    }  
  
  
                    int splitPoint = 0;  
                    if (typeIdx > 0)  
                    {  
                        splitPoint = GetNextSplit(currentPos, currentSplit, reader);  
                        if (isMultiSplit && splitIdx > 0)  
                        {  
                            currentSplit = splits[--splitIdx];  
                        }  
                    }  
  
  
                    deserializers.Add((GetDeserializer(type, reader, splitPoint, currentPos - splitPoint, typeIdx > 0)));  
                    currentPos = splitPoint;  
                }  
  
  
                deserializers.Reverse();  
  
  
            }  
            return deserializers.ToArray();  
        }  
  
  
        private static int GetNextSplitDynamic(int startIdx, string splitOn, IDataReader reader)  
        {  
            if (startIdx == reader.FieldCount)  
            {  
                throw MultiMapException(reader);  
            }  
  
  
            if (splitOn == "*")  
            {  
                return ++startIdx;  
            }  
  
  
            for (var i = startIdx + 1; i < reader.FieldCount; ++i)  
            {  
                if (string.Equals(splitOn, reader.GetName(i), StringComparison.OrdinalIgnoreCase))  
                {  
                    return i;  
                }  
            }  
  
  
            return reader.FieldCount;  
        }  
  
  
        private static int GetNextSplit(int startIdx, string splitOn, IDataReader reader)  
        {  
            if (splitOn == "*")  
            {  
                return --startIdx;  
            }  
  
  
            for (var i = startIdx - 1; i > 0; --i)  
            {  
                if (string.Equals(splitOn, reader.GetName(i), StringComparison.OrdinalIgnoreCase))  
                {  
                    return i;  
                }  
            }  
  
  
            throw MultiMapException(reader);  
        }  
  
  
        private static CacheInfo GetCacheInfo(Identity identity, object exampleParameters, bool addToCache)  
        {  
            CacheInfo info;  
            if (!TryGetQueryCache(identity, out info))  
            {  
                info = new CacheInfo();  
                if (identity.parametersType != null)  
                {  
                    Action<IDbCommand, object> reader;  
                    if (exampleParameters is IDynamicParameters)  
                    {  
                        reader = (cmd, obj) => { ((IDynamicParameters)obj).AddParameters(cmd, identity); };  
                    }  
                    else if (exampleParameters is IEnumerable<KeyValuePair<string, object>>)  
                    {  
                        reader = (cmd, obj) =>  
                        {  
                            IDynamicParameters mapped = new DynamicParameters(obj);  
                            mapped.AddParameters(cmd, identity);  
                        };  
                    }  
                    else  
                    {  
                        var literals = GetLiteralTokens(identity.sql);  
                        reader = CreateParamInfoGenerator(identity, false, true, literals);  
                    }  
                    if((identity.commandType == null || identity.commandType == CommandType.Text) && ShouldPassByPosition(identity.sql))  
                    {  
                        var tail = reader;  
                        var sql = identity.sql;  
                        reader = (cmd, obj) =>  
                        {  
                            tail(cmd, obj);  
                            PassByPosition(cmd);  
                        };  
                    }  
                    info.ParamReader = reader;  
                }  
                if(addToCache) SetQueryCache(identity, info);  
            }  
            return info;  
        }  
  
  
        private static bool ShouldPassByPosition(string sql)  
        {  
            return sql != null && sql.IndexOf('?') >= 0 && pseudoPositional.IsMatch(sql);  
        }  
  
  
        private static void PassByPosition(IDbCommand cmd)  
        {  
            if (cmd.Parameters.Count == 0) return;  
  
  
            Dictionary<string, IDbDataParameter> parameters = new Dictionary<string, IDbDataParameter>(StringComparer.InvariantCulture);  
              
            foreach(IDbDataParameter param in cmd.Parameters)  
            {  
                if (!string.IsNullOrEmpty(param.ParameterName)) parameters[param.ParameterName] = param;  
            }  
            HashSet<string> consumed = new HashSet<string>(StringComparer.InvariantCulture);  
            bool firstMatch = true;  
            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))  
                {  
                    if(firstMatch)  
                    {  
                        firstMatch = false;  
                        cmd.Parameters.Clear(); // only clear if we are pretty positive that we've found this pattern successfully  
                    }  
                    // if found, return the anonymous token "?"  
                    cmd.Parameters.Add(param);  
                    parameters.Remove(key);  
                    consumed.Add(key);  
                    return "?";  
                }  
                else  
                {  
                    // otherwise, leave alone for simple debugging  
                    return match.Value;  
                }  
            });  
        }  
  
  
        private static Func<IDataReader, object> GetDeserializer(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)  
        {  
#if !CSHARP30  
            // dynamic is passed in as Object ... by c# design  
            if (type == typeof(object)  
                || type == typeof(DapperRow))  
            {  
                return GetDapperRowDeserializer(reader, startBound, length, returnNullIfFirstMissing);  
            }  
#else  
            if (type.IsAssignableFrom(typeof(Dictionary<string, object>)))  
            {  
                return GetDictionaryDeserializer(reader, startBound, length, returnNullIfFirstMissing);  
            }  
#endif  
            Type underlyingType = null;  
            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))  
                {  
                    return GetHandlerDeserializer(handler, type, startBound);  
                }  
                return GetTypeDeserializer(type, reader, startBound, length, returnNullIfFirstMissing);  
            }  
            return GetStructDeserializer(type, underlyingType ?? type, startBound);  
        }  
        static Func<IDataReader, object> GetHandlerDeserializer(ITypeHandler handler, Type type, int startBound)  
        {  
            return (IDataReader reader) =>  
                handler.Parse(type, reader.GetValue(startBound));  
        }  
 
 
#if !CSHARP30  
        private sealed partial class DapperTable  
        {  
            string[] fieldNames;  
            readonly Dictionary<string, int> fieldNameLookup;  
  
  
            internal string[] FieldNames { get { return fieldNames; } }  
  
  
            public DapperTable(string[] fieldNames)  
            {  
                if (fieldNames == null) throw new ArgumentNullException("fieldNames");  
                this.fieldNames = 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  
                for (int i = fieldNames.Length - 1; i >= 0; i--)  
                {  
                    string key = fieldNames[i];  
                    if (key != null) fieldNameLookup[key] = i;  
                }  
            }  
  
  
            internal int IndexOfName(string name)  
            {  
                int result;  
                return (name != null && fieldNameLookup.TryGetValue(name, out result)) ? result : -1;  
            }  
            internal int AddField(string name)  
            {  
                if (name == null) throw new ArgumentNullException("name");  
                if (fieldNameLookup.ContainsKey(name)) throw new InvalidOperationException("Field already exists: " + name);  
                int oldLen = fieldNames.Length;  
                Array.Resize(ref fieldNames, oldLen + 1); // yes, this is sub-optimal, but this is not the expected common case  
                fieldNames[oldLen] = name;  
                fieldNameLookup[name] = oldLen;  
                return oldLen;  
            }  
  
  
  
  
            internal bool FieldExists(string key)  
            {  
                return key != null && fieldNameLookup.ContainsKey(key);  
            }  
  
  
            public int FieldCount { get { return fieldNames.Length; } }  
        }  
  
  
        sealed partial 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) });  
  
  
            public DapperRowMetaObject(  
                System.Linq.Expressions.Expression expression,  
                System.Dynamic.BindingRestrictions restrictions  
                )  
                : base(expression, restrictions)  
            {  
            }  
  
  
            public DapperRowMetaObject(  
                System.Linq.Expressions.Expression expression,  
                System.Dynamic.BindingRestrictions restrictions,  
                object value  
                )  
                : base(expression, restrictions, value)  
            {  
            }  
  
  
            System.Dynamic.DynamicMetaObject CallMethod(  
                MethodInfo method,  
                System.Linq.Expressions.Expression[] parameters  
                )  
            {  
                var callMethod = new System.Dynamic.DynamicMetaObject(  
                    System.Linq.Expressions.Expression.Call(  
                        System.Linq.Expressions.Expression.Convert(Expression, LimitType),  
                        method,  
                        parameters),  
                    System.Dynamic.BindingRestrictions.GetTypeRestriction(Expression, LimitType)  
                    );  
                return callMethod;  
            }  
  
  
            public override System.Dynamic.DynamicMetaObject BindGetMember(System.Dynamic.GetMemberBinder binder)  
            {  
                var parameters = new System.Linq.Expressions.Expression[]  
                                     {  
                                         System.Linq.Expressions.Expression.Constant(binder.Name)  
                                     };  
  
  
                var callMethod = CallMethod(getValueMethod, parameters);  
  
  
                return callMethod;  
            }  
  
  
            // Needed for Visual basic dynamic support  
            public override System.Dynamic.DynamicMetaObject BindInvokeMember(System.Dynamic.InvokeMemberBinder binder, System.Dynamic.DynamicMetaObject[] args)  
            {  
                var parameters = new System.Linq.Expressions.Expression[]  
                                     {  
                                         System.Linq.Expressions.Expression.Constant(binder.Name)  
                                     };  
  
  
                var callMethod = CallMethod(getValueMethod, parameters);  
  
  
                return callMethod;  
            }  
  
  
            public override System.Dynamic.DynamicMetaObject BindSetMember(System.Dynamic.SetMemberBinder binder, System.Dynamic.DynamicMetaObject value)  
            {  
                var parameters = new System.Linq.Expressions.Expression[]  
                                     {  
                                         System.Linq.Expressions.Expression.Constant(binder.Name),  
                                         value.Expression,  
                                     };  
  
  
                var callMethod = CallMethod(setValueMethod, parameters);  
  
  
                return callMethod;  
            }  
        }  
  
  
        private sealed partial class DapperRow  
            : System.Dynamic.IDynamicMetaObjectProvider  
            , IDictionary<string, object>  
        {  
            readonly DapperTable table;  
            object[] values;  
  
  
            public DapperRow(DapperTable table, object[] values)  
            {  
                if (table == null) throw new ArgumentNullException("table");  
                if (values == null) throw new ArgumentNullException("values");  
                this.table = table;  
                this.values = values;  
            }  
            private sealed class DeadValue  
            {  
                public static readonly DeadValue Default = new DeadValue();  
                private DeadValue() { }  
            }  
            int ICollection<KeyValuePair<string, object>>.Count  
            {  
                get  
                {  
                    int count = 0;  
                    for (int i = 0; i < values.Length; i++)  
                    {  
                        if (!(values[i] is DeadValue)) count++;  
                    }  
                    return count;  
                }  
            }  
  
  
            public bool TryGetValue(string name, out object value)  
            {  
                var index = table.IndexOfName(name);  
                if (index < 0)  
                { // doesn't exist  
                    value = null;  
                    return false;  
                }  
                // exists, **even if** we don't have a value; consider table rows heterogeneous  
                value = index < values.Length ? values[index] : null;  
                if (value is DeadValue)  
                { // pretend it isn't here  
                    value = null;  
                    return false;  
                }  
                return true;  
            }  
  
  
            public override string ToString()  
            {  
                var sb = GetStringBuilder().Append("{DapperRow");  
                foreach (var kv in this)  
                {  
                    var value = kv.Value;  
                    sb.Append(", ").Append(kv.Key);  
                    if (value != null)  
                    {  
                        sb.Append(" = '").Append(kv.Value).Append('\'');  
                    }  
                    else  
                    {  
                        sb.Append(" = NULL");  
                    }  
                }  
  
  
                return sb.Append('}').__ToStringRecycle();  
            }  
  
  
            System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(  
                System.Linq.Expressions.Expression parameter)  
            {  
                return new DapperRowMetaObject(parameter, System.Dynamic.BindingRestrictions.Empty, this);  
            }  
  
  
            public IEnumerator<KeyValuePair<string, object>> GetEnumerator()  
            {  
                var names = table.FieldNames;  
                for (var i = 0; i < names.Length; i++)  
                {  
                    object value = i < values.Length ? values[i] : null;  
                    if (!(value is DeadValue))  
                    {  
                        yield return new KeyValuePair<string, object>(names[i], value);  
                    }  
                }  
            }  
  
  
            IEnumerator IEnumerable.GetEnumerator()  
            {  
                return GetEnumerator();  
            }  
 
 
#region Implementation of ICollection<KeyValuePair<string,object>>  
  
  
            void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)  
            {  
                IDictionary<string, object> dic = this;  
                dic.Add(item.Key, item.Value);  
            }  
  
  
            void ICollection<KeyValuePair<string, object>>.Clear()  
            { // removes values for **this row**, but doesn't change the fundamental table  
                for (int i = 0; i < values.Length; i++)  
                    values[i] = DeadValue.Default;  
            }  
  
  
            bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)  
            {  
                object value;  
                return TryGetValue(item.Key, out value) && Equals(value, item.Value);  
            }  
  
  
            void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)  
            {  
                foreach (var kv in this)  
                {  
                    array[arrayIndex++] = kv; // if they didn't leave enough space; not our fault  
                }  
            }  
  
  
            bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item)  
            {  
                IDictionary<string, object> dic = this;  
                return dic.Remove(item.Key);  
            }  
  
  
            bool ICollection<KeyValuePair<string, object>>.IsReadOnly  
            {  
                get { return false; }  
            }  
 
 
#endregion  
 
 
#region Implementation of IDictionary<string,object>  
  
  
            bool IDictionary<string, object>.ContainsKey(string key)  
            {  
                int index = table.IndexOfName(key);  
                if (index < 0 || index >= values.Length || values[index] is DeadValue) return false;  
                return true;  
            }  
  
  
            void IDictionary<string, object>.Add(string key, object value)  
            {  
                SetValue(key, value, true);  
            }  
  
  
            bool IDictionary<string, object>.Remove(string key)  
            {  
                int index = table.IndexOfName(key);  
                if (index < 0 || index >= values.Length || values[index] is DeadValue) return false;  
                values[index] = DeadValue.Default;  
                return true;  
            }  
  
  
            object IDictionary<string, object>.this[string key]  
            {  
                get { object val; TryGetValue(key, out val); return val; }  
                set { SetValue(key, value, false); }  
            }  
  
  
            public object SetValue(string key, object value)  
            {  
                return SetValue(key, value, false);  
            }  
            private object SetValue(string key, object value, bool isAdd)  
            {  
                if (key == null) throw new ArgumentNullException("key");  
                int index = table.IndexOfName(key);  
                if (index < 0)  
                {  
                    index = table.AddField(key);  
                }  
                else if (isAdd && index < values.Length && !(values[index] is DeadValue))  
                {  
                    // then semantically, this value already exists  
                    throw new ArgumentException("An item with the same key has already been added", "key");  
                }  
                int oldLength = values.Length;  
                if (oldLength <= index)  
                {  
                    // we'll assume they're doing lots of things, and  
                    // grow it to the full width of the table  
                    Array.Resize(ref values, table.FieldCount);  
                    for (int i = oldLength; i < values.Length; i++)  
                    {  
                        values[i] = DeadValue.Default;  
                    }  
                }  
                return values[index] = value;  
            }  
  
  
            ICollection<string> IDictionary<string, object>.Keys  
            {  
                get { return this.Select(kv => kv.Key).ToArray(); }  
            }  
  
  
            ICollection<object> IDictionary<string, object>.Values  
            {  
                get { return this.Select(kv => kv.Value).ToArray(); }  
            }  
 
 
#endregion  
        }  
#endif  
        private static Exception MultiMapException(IDataRecord reader)  
        {  
            bool hasFields = false;  
            try {  
                hasFields = reader != null && reader.FieldCount != 0;  
            } catch { }  
            if (hasFields)  
                return new ArgumentException("When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id", "splitOn");  
            else  
                return new InvalidOperationException("No columns were selected");  
        }  
         
#if !CSHARP30  
        internal static Func<IDataReader, object> GetDapperRowDeserializer(IDataRecord reader, int startBound, int length, bool returnNullIfFirstMissing)  
        {  
            var fieldCount = reader.FieldCount;  
            if (length == -1)  
            {  
                length = fieldCount - startBound;  
            }  
  
  
            if (fieldCount <= startBound)  
            {  
                throw MultiMapException(reader);  
            }  
  
  
            var effectiveFieldCount = Math.Min(fieldCount - startBound, length);  
  
  
            DapperTable table = null;  
  
  
            return  
                r =>  
                {  
                    if (table == null)  
                    {  
                        string[] names = new string[effectiveFieldCount];  
                        for (int i = 0; i < effectiveFieldCount; i++)  
                        {  
                            names[i] = r.GetName(i + startBound);  
                        }  
                        table = new DapperTable(names);  
                    }  
  
  
                    var values = new object[effectiveFieldCount];  
  
  
                    if (returnNullIfFirstMissing)  
                    {  
                        values[0] = r.GetValue(startBound);  
                        if (values[0] is DBNull)  
                        {  
                            return null;  
                        }  
                    }  
  
  
                    if (startBound == 0)  
                    {  
                        r.GetValues(values);  
                        for (int i = 0; i < values.Length; i++)  
                            if (values[i] is DBNull) values[i] = null;  
                    }  
                    else  
                    {  
                        var begin = returnNullIfFirstMissing ? 1 : 0;  
                        for (var iter = begin; iter < effectiveFieldCount; ++iter)  
                        {  
                            object obj = r.GetValue(iter + startBound);  
                            values[iter] = obj is DBNull ? null : obj;  
                        }  
                    }  
                    return new DapperRow(table, values);  
                };  
        }  
#else  
        internal static Func<IDataReader, object> GetDictionaryDeserializer(IDataRecord reader, int startBound, int length, bool returnNullIfFirstMissing)  
        {  
            var fieldCount = reader.FieldCount;  
            if (length == -1)  
            {  
                length = fieldCount - startBound;  
            }  
  
  
            if (fieldCount <= startBound)  
            {  
                throw MultiMapException(reader);  
            }  
  
  
            return  
                 r =>  
                 {  
                     IDictionary<string, object> row = new Dictionary<string, object>(length);  
                     for (var i = startBound; i < startBound + length; i++)  
                     {  
                         var tmp = r.GetValue(i);  
                         tmp = tmp == DBNull.Value ? null : tmp;  
                         row[r.GetName(i)] = tmp;  
                         if (returnNullIfFirstMissing && i == startBound && tmp == null)  
                         {  
                             return null;  
                         }  
                     }  
                     return row;  
                 };  
        }  
#endif  
        /// <summary>  
        /// Internal use only  
        /// </summary>  
        /// <param name="value"></param>  
        /// <returns></returns>  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]  
        [Obsolete("This method is for internal usage only", false)]  
        public static char ReadChar(object value)  
        {  
            if (value == null || value is DBNull) throw new ArgumentNullException("value");  
            string s = value as string;  
            if (s == null || s.Length != 1) throw new ArgumentException("A single-character was expected", "value");  
            return s[0];  
        }  
  
  
        /// <summary>  
        /// Internal use only  
        /// </summary>  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]  
        [Obsolete("This method is for internal usage only", false)]  
        public static char? ReadNullableChar(object value)  
        {  
            if (value == null || value is DBNull) return null;  
            string s = value as string;  
            if (s == null || s.Length != 1) throw new ArgumentException("A single-character was expected", "value");  
            return s[0];  
        }  
  
  
  
  
        /// <summary>  
        /// Internal use only  
        /// </summary>  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]  
        [Obsolete("This method is for internal usage only", true)]  
        public static IDbDataParameter FindOrAddParameter(IDataParameterCollection parameters, IDbCommand command, string name)  
        {  
            IDbDataParameter result;  
            if (parameters.Contains(name))  
            {  
                result = (IDbDataParameter)parameters[name];  
            }  
            else  
            {  
                result = command.CreateParameter();  
                result.ParameterName = name;  
                parameters.Add(result);  
            }  
            return result;  
        }  
  
  
        /// <summary>  
        /// Internal use only  
        /// </summary>  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]  
        [Obsolete("This method is for internal usage only", false)]  
        public static void PackListParameters(IDbCommand command, string namePrefix, object value)  
        {  
            // initially we tried TVP, however it performs quite poorly.  
            // keep in mind SQL support up to 2000 params easily in sp_executesql, needing more is rare  
  
  
            if (FeatureSupport.Get(command.Connection).Arrays)  
            {  
                var arrayParm = command.CreateParameter();  
                arrayParm.Value = value ?? DBNull.Value;  
                arrayParm.ParameterName = namePrefix;  
                command.Parameters.Add(arrayParm);  
            }  
            else  
            {  
                var list = value as IEnumerable;  
                var count = 0;  
                bool isString = value is IEnumerable<string>;  
                bool isDbString = value is IEnumerable<DbString>;  
                foreach (var item in list)  
                {  
                    count++;  
                    var listParam = command.CreateParameter();  
                    listParam.ParameterName = namePrefix + count;  
                    if (isString)  
                    {  
                        listParam.Size = DbString.DefaultLength;  
                        if (item != null && ((string)item).Length > DbString.DefaultLength)  
                        {  
                            listParam.Size = -1;  
                        }  
                    }  
                    if (isDbString && item as DbString != null)  
                    {  
                        var str = item as DbString;  
                        str.AddParameter(command, listParam.ParameterName);  
                    }  
                    else  
                    {  
                        listParam.Value = item ?? DBNull.Value;  
                        command.Parameters.Add(listParam);  
                    }  
                }  
  
  
                var regexIncludingUnknown = @"([?@:]" + Regex.Escape(namePrefix) + @")(?!\w)(\s+(?i)unknown(?-i))?";  
                if (count == 0)  
                {  
                    command.CommandText = Regex.Replace(command.CommandText, regexIncludingUnknown, match =>  
                    {  
                        var variableName = match.Groups[1].Value;  
                        if (match.Groups[2].Success)  
                        {  
                            // looks like an optimize hint; leave it alone!  
                            return match.Value;  
                        }  
                        else  
                        {  
                            return "(SELECT " + variableName + " WHERE 1 = 0)";  
                        }  
                    }, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant);                          
                    var dummyParam = command.CreateParameter();  
                    dummyParam.ParameterName = namePrefix;  
                    dummyParam.Value = DBNull.Value;  
                    command.Parameters.Add(dummyParam);  
                }  
                else  
                {  
                    command.CommandText = Regex.Replace(command.CommandText, regexIncludingUnknown, match =>  
                    {  
                        var variableName = match.Groups[1].Value;  
                        if (match.Groups[2].Success)  
                        {  
                            // looks like an optimize hint; expand it  
                            var suffix = match.Groups[2].Value;  
                                  
                            var sb = GetStringBuilder().Append(variableName).Append(1).Append(suffix);  
                            for (int i = 2; i <= count; i++)  
                            {  
                                sb.Append(',').Append(variableName).Append(i).Append(suffix);  
                            }  
                            return sb.__ToStringRecycle();  
                        }  
                        else  
                        {  
                            var sb = GetStringBuilder().Append('(').Append(variableName).Append(1);  
                            for (int i = 2; i <= count; i++)  
                            {  
                                sb.Append(',').Append(variableName).Append(i);  
                            }  
                            return sb.Append(')').__ToStringRecycle();  
                        }  
                    }, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant);  
                }  
            }  
  
  
        }  
  
  
        private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyInfo> parameters, string sql)  
        {  
            return parameters.Where(p => Regex.IsMatch(sql, @"[?@:]" + p.Name + "([^a-z0-9_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant));  
        }  
  
  
        // look for ? / @ / : *by itself*  
        static readonly Regex smellsLikeOleDb = new Regex(@"(?<![a-z0-9@_])[?@:](?![a-z0-9@_])", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled),  
            literalTokens = new Regex(@"(?<![a-z0-9_])\{=([a-z0-9_]+)\}", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled),  
            pseudoPositional = new Regex(@"\?([a-z_][a-z0-9_]*)\?", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);  
  
  
        /// <summary>  
        /// Represents a placeholder for a value that should be replaced as a literal value in the resulting sql  
        /// </summary>  
        internal struct LiteralToken  
        {  
            private readonly string token, member;  
            /// <summary>  
            /// The text in the original command that should be replaced  
            /// </summary>  
            public string Token { get { return token; } }  
  
  
            /// <summary>  
            /// The name of the member referred to by the token  
            /// </summary>  
            public string Member { get { return member; } }  
            internal LiteralToken(string token, string member)  
            {  
                this.token = token;  
                this.member = member;  
            }  
  
  
            internal static readonly IList<LiteralToken> None = new LiteralToken[0];  
        }  
  
  
        /// <summary>  
        /// Replace all literal tokens with their text form  
        /// </summary>  
        public static void ReplaceLiterals(this IParameterLookup parameters, IDbCommand command)  
        {  
            var tokens = GetLiteralTokens(command.CommandText);  
            if (tokens.Count != 0) ReplaceLiterals(parameters, command, tokens);  
        }  
  
  
        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>  
        [Obsolete("This is intended for internal usage only")]  
        public static string Format(object value)  
        {  
            if (value == null)  
            {  
                return "null";  
            }  
            else  
            {  
                switch (Type.GetTypeCode(value.GetType()))  
                {  
                    case TypeCode.DBNull:  
                        return "null";  
                    case TypeCode.Boolean:  
                        return ((bool)value) ? "1" : "0";  
                    case TypeCode.Byte:  
                        return ((byte)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.SByte:  
                        return ((sbyte)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.UInt16:  
                        return ((ushort)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.Int16:  
                        return ((short)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.UInt32:  
                        return ((uint)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.Int32:  
                        return ((int)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.UInt64:  
                        return ((ulong)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.Int64:  
                        return ((long)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.Single:  
                        return ((float)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.Double:  
                        return ((double)value).ToString(CultureInfo.InvariantCulture);  
                    case TypeCode.Decimal:  
                        return ((decimal)value).ToString(CultureInfo.InvariantCulture);  
                    default:  
                        var multiExec = GetMultiExec(value);  
                        if(multiExec != null)  
                        {  
                            StringBuilder sb = null;  
                            bool first = true;  
                            foreach (object subval in multiExec)  
                            {  
                                if(first)  
                                {  
                                    sb = GetStringBuilder().Append('(');  
                                    first = false;  
                                }  
                                else  
                                {  
                                    sb.Append(',');  
                                }  
                                sb.Append(Format(subval));  
                            }  
                            if(first)  
                            {  
                                return "(select null where 1=0)";  
                            }  
                            else  
                            {  
                                return sb.Append(')').__ToStringRecycle();  
                            }  
                        }  
                        throw new NotSupportedException(value.GetType().Name);  
                }  
            }  
        }  
  
  
  
  
        internal static void ReplaceLiterals(IParameterLookup parameters, IDbCommand command, IList<LiteralToken> tokens)  
        {  
            var sql = command.CommandText;  
            foreach (var token in tokens)  
            {  
                object value = parameters[token.Member];  
#pragma warning disable 0618  
                string text = Format(value);  
#pragma warning restore 0618  
                sql = sql.Replace(token.Token, text);  
            }  
            command.CommandText = sql;  
        }  
  
  
        internal static IList<LiteralToken> GetLiteralTokens(string sql)  
        {  
            if (string.IsNullOrEmpty(sql)) return LiteralToken.None;  
            if (!literalTokens.IsMatch(sql)) return LiteralToken.None;  
  
  
            var matches = literalTokens.Matches(sql);  
            var found = new HashSet<string>(StringComparer.InvariantCulture);  
            List<LiteralToken> list = new List<LiteralToken>(matches.Count);  
            foreach(Match match in matches)  
            {  
                string token = match.Value;  
                if(found.Add(match.Value))  
                {  
                    list.Add(new LiteralToken(token, match.Groups[1].Value));  
                }  
            }  
            return list.Count == 0 ? LiteralToken.None : list;  
        }  
  
  
        /// <summary>  
        /// Internal use only  
        /// </summary>  
        public static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity, bool checkForDuplicates, bool removeUnused)  
        {  
            return CreateParamInfoGenerator(identity, checkForDuplicates, removeUnused, GetLiteralTokens(identity.sql));  
        }  
  
  
        internal static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity, bool checkForDuplicates, bool removeUnused, IList<LiteralToken> literals)  
        {  
            Type type = identity.parametersType;  
              
            bool filterParams = false;  
            if (removeUnused && identity.commandType.GetValueOrDefault(CommandType.Text) == CommandType.Text)  
            {  
                filterParams = !smellsLikeOleDb.IsMatch(identity.sql);  
            }  
            var dm = new DynamicMethod(string.Format("ParamInfo{0}", Guid.NewGuid()), null, new[] { typeof(IDbCommand), typeof(object) }, type, true);  
  
  
            var il = dm.GetILGenerator();  
  
  
            bool isStruct = type.IsValueType;  
            bool haveInt32Arg1 = false;  
            il.Emit(OpCodes.Ldarg_1); // stack is now [untyped-param]  
            if (isStruct)  
            {  
                il.DeclareLocal(type.MakePointerType());  
                il.Emit(OpCodes.Unbox, type); // stack is now [typed-param]  
            }  
            else  
            {  
                il.DeclareLocal(type); // 0  
                il.Emit(OpCodes.Castclass, type); // stack is now [typed-param]  
            }  
            il.Emit(OpCodes.Stloc_0);// stack is now empty  
  
  
            il.Emit(OpCodes.Ldarg_0); // stack is now [command]  
            il.EmitCall(OpCodes.Callvirt, typeof(IDbCommand).GetProperty("Parameters").GetGetMethod(), null); // stack is now [parameters]  
  
  
            var propsArr = type.GetProperties().Where(p => p.GetIndexParameters().Length == 0).ToArray();  
            var ctors = type.GetConstructors();  
            ParameterInfo[] ctorParams;  
            IEnumerable<PropertyInfo> props = null;  
            // try to detect tuple patterns, e.g. anon-types, and use that to choose the order  
            // otherwise: alphabetical  
            if (ctors.Length == 1 && propsArr.Length == (ctorParams = ctors[0].GetParameters()).Length)  
            {  
                // check if reflection was kind enough to put everything in the right order for us  
                bool ok = true;  
                for (int i = 0; i < propsArr.Length; i++)  
                {  
                    if (!string.Equals(propsArr[i].Name, ctorParams[i].Name, StringComparison.InvariantCultureIgnoreCase))  
                    {  
                        ok = false;  
                        break;  
                    }  
                }  
                if(ok)  
                {  
                    // pre-sorted; the reflection gods have smiled upon us  
                    props = propsArr;  
                }  
                else { // might still all be accounted for; check the hard way  
                    var positionByName = new Dictionary<string,int>(StringComparer.InvariantCultureIgnoreCase);  
                    foreach(var param in ctorParams)  
                    {  
                        positionByName[param.Name] = param.Position;  
                    }  
                    if (positionByName.Count == propsArr.Length)  
                    {  
                        int[] positions = new int[propsArr.Length];  
                        ok = true;  
                        for (int i = 0; i < propsArr.Length; i++)  
                        {  
                            int pos;  
                            if (!positionByName.TryGetValue(propsArr[i].Name, out pos))  
                            {  
                                ok = false;  
                                break;  
                            }  
                            positions[i] = pos;  
                        }  
                        if (ok)  
                        {  
                            Array.Sort(positions, propsArr);  
                            props = propsArr;  
                        }  
                    }  
                }  
            }  
            if(props == null) props = propsArr.OrderBy(x => x.Name);  
            if (filterParams)  
            {  
                props = FilterParameters(props, identity.sql);  
            }  
  
  
            var callOpCode = isStruct ? OpCodes.Call : OpCodes.Callvirt;  
            foreach (var prop in props)  
            {  
                if (typeof(ICustomQueryParameter).IsAssignableFrom(prop.PropertyType))  
                {  
                    il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [typed-param]  
                    il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [custom]  
                    il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [custom] [command]  
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [custom] [command] [name]  
                    il.EmitCall(OpCodes.Callvirt, prop.PropertyType.GetMethod("AddParameter"), null); // stack is now [parameters]  
                    continue;  
                }  
                ITypeHandler handler;  
                DbType dbType = LookupDbType(prop.PropertyType, prop.Name, true, out handler);  
                if (dbType == DynamicParameters.EnumerableMultiParameter)  
                {  
                    // this actually represents special handling for list types;  
                    il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [command]  
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [command] [name]  
                    il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [command] [name] [typed-param]  
                    il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [command] [name] [typed-value]  
                    if (prop.PropertyType.IsValueType)  
                    {  
                        il.Emit(OpCodes.Box, prop.PropertyType); // stack is [parameters] [command] [name] [boxed-value]  
                    }  
                    il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod("PackListParameters"), null); // stack is [parameters]  
                    continue;  
                }  
                il.Emit(OpCodes.Dup); // stack is now [parameters] [parameters]  
  
  
                il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [parameters] [command]  
  
  
                if (checkForDuplicates)  
                {  
                    // need to be a little careful about adding; use a utility method  
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [parameters] [command] [name]  
                    il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod("FindOrAddParameter"), null); // stack is [parameters] [parameter]  
                }  
                else  
                {  
                    // no risk of duplicates; just blindly add  
                    il.EmitCall(OpCodes.Callvirt, typeof(IDbCommand).GetMethod("CreateParameter"), null);// stack is now [parameters] [parameters] [parameter]  
  
  
                    il.Emit(OpCodes.Dup);// stack is now [parameters] [parameters] [parameter] [parameter]  
                    il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [parameters] [parameter] [parameter] [name]  
                    il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty("ParameterName").GetSetMethod(), null);// stack is now [parameters] [parameters] [parameter]  
                }  
                if (dbType != DbType.Time && handler == null) // https://connect.microsoft.com/VisualStudio/feedback/details/381934/sqlparameter-dbtype-dbtype-time-sets-the-parameter-to-sqldbtype-datetime-instead-of-sqldbtype-time  
                {  
                    il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]  
                    if (dbType == DbType.Object && prop.PropertyType == typeof(object)) // includes dynamic  
                    {  
                        // look it up from the param value  
                        il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param]  
                        il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [object-value]  
                        il.Emit(OpCodes.Call, typeof(SqlMapper).GetMethod("GetDbType", BindingFlags.Static | BindingFlags.Public)); // stack is now [parameters] [[parameters]] [parameter] [parameter] [db-type]  
                    }  
                    else  
                    {  
                        // constant value; nice and simple  
                        EmitInt32(il, (int)dbType);// stack is now [parameters] [[parameters]] [parameter] [parameter] [db-type]  
                    }  
                    il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty("DbType").GetSetMethod(), null);// stack is now [parameters] [[parameters]] [parameter]  
                }  
  
  
                il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]  
                EmitInt32(il, (int)ParameterDirection.Input);// stack is now [parameters] [[parameters]] [parameter] [parameter] [dir]  
                il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty("Direction").GetSetMethod(), null);// stack is now [parameters] [[parameters]] [parameter]  
  
  
                il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]  
                il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param]  
                il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [typed-value]  
                bool checkForNull = true;  
                if (prop.PropertyType.IsValueType)  
                {  
                    il.Emit(OpCodes.Box, prop.PropertyType); // stack is [parameters] [[parameters]] [parameter] [parameter] [boxed-value]  
                    if (Nullable.GetUnderlyingType(prop.PropertyType) == null)  
                    {   // struct but not Nullable<T>; boxed value cannot be null  
                        checkForNull = false;  
                    }  
                }  
                if (checkForNull)  
                {  
                    if ((dbType == DbType.String || dbType == DbType.AnsiString) && !haveInt32Arg1)  
                    {  
                        il.DeclareLocal(typeof(int));  
                        haveInt32Arg1 = true;  
                    }  
                    // relative stack: [boxed value]  
                    il.Emit(OpCodes.Dup);// relative stack: [boxed value] [boxed value]  
                    Label notNull = il.DefineLabel();  
                    Label? allDone = (dbType == DbType.String || dbType == DbType.AnsiString) ? il.DefineLabel() : (Label?)null;  
                    il.Emit(OpCodes.Brtrue_S, notNull);  
                    // relative stack [boxed value = null]  
                    il.Emit(OpCodes.Pop); // relative stack empty  
                    il.Emit(OpCodes.Ldsfld, typeof(DBNull).GetField("Value")); // relative stack [DBNull]  
                    if (dbType == DbType.String || dbType == DbType.AnsiString)  
                    {  
                        EmitInt32(il, 0);  
                        il.Emit(OpCodes.Stloc_1);  
                    }  
                    if (allDone != null) il.Emit(OpCodes.Br_S, allDone.Value);  
                    il.MarkLabel(notNull);  
                    if (prop.PropertyType == typeof(string))  
                    {  
                        il.Emit(OpCodes.Dup); // [string] [string]  
                        il.EmitCall(OpCodes.Callvirt, typeof(string).GetProperty("Length").GetGetMethod(), null); // [string] [length]  
                        EmitInt32(il, DbString.DefaultLength); // [string] [length] [4000]  
                        il.Emit(OpCodes.Cgt); // [string] [0 or 1]  
                        Label isLong = il.DefineLabel(), lenDone = il.DefineLabel();  
                        il.Emit(OpCodes.Brtrue_S, isLong);  
                        EmitInt32(il, DbString.DefaultLength); // [string] [4000]  
                        il.Emit(OpCodes.Br_S, lenDone);  
                        il.MarkLabel(isLong);  
                        EmitInt32(il, -1); // [string] [-1]  
                        il.MarkLabel(lenDone);  
                        il.Emit(OpCodes.Stloc_1); // [string]   
                    }  
                    if (prop.PropertyType.FullName == LinqBinary)  
                    {  
                        il.EmitCall(OpCodes.Callvirt, prop.PropertyType.GetMethod("ToArray", BindingFlags.Public | BindingFlags.Instance), null);  
                    }  
                    if (allDone != null) il.MarkLabel(allDone.Value);  
                    // relative stack [boxed value or DBNull]  
                }  
  
  
                if (handler != null)  
                {  
#pragma warning disable 618  
                    il.Emit(OpCodes.Call, typeof(TypeHandlerCache<>).MakeGenericType(prop.PropertyType).GetMethod("SetValue")); // stack is now [parameters] [[parameters]] [parameter]  
#pragma warning restore 618  
                }  
                else  
                {  
                    il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty("Value").GetSetMethod(), null);// stack is now [parameters] [[parameters]] [parameter]  
                }  
  
  
                if (prop.PropertyType == typeof(string))  
                {  
                    var endOfSize = il.DefineLabel();  
                    // don't set if 0  
                    il.Emit(OpCodes.Ldloc_1); // [parameters] [[parameters]] [parameter] [size]  
                    il.Emit(OpCodes.Brfalse_S, endOfSize); // [parameters] [[parameters]] [parameter]  
  
  
                    il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]  
                    il.Emit(OpCodes.Ldloc_1); // stack is now [parameters] [[parameters]] [parameter] [parameter] [size]  
                    il.EmitCall(OpCodes.Callvirt, typeof(IDbDataParameter).GetProperty("Size").GetSetMethod(), null); // stack is now [parameters] [[parameters]] [parameter]  
  
  
                    il.MarkLabel(endOfSize);  
                }  
                if (checkForDuplicates)  
                {  
                    // stack is now [parameters] [parameter]  
                    il.Emit(OpCodes.Pop); // don't need parameter any more  
                }  
                else  
                {  
                    // stack is now [parameters] [parameters] [parameter]  
                    // blindly add  
                    il.EmitCall(OpCodes.Callvirt, typeof(IList).GetMethod("Add"), null); // stack is now [parameters]  
                    il.Emit(OpCodes.Pop); // IList.Add returns the new index (int); we don't care  
                }  
            }  
  
  
            // stack is currently [parameters]  
            il.Emit(OpCodes.Pop); // stack is now empty  
  
  
            if(literals.Count != 0 && propsArr != null)  
            {  
                il.Emit(OpCodes.Ldarg_0); // command  
                il.Emit(OpCodes.Ldarg_0); // command, command  
                var cmdText = typeof(IDbCommand).GetProperty("CommandText");  
                il.EmitCall(OpCodes.Callvirt, cmdText.GetGetMethod(), null); // command, sql  
                Dictionary<Type, LocalBuilder> locals = null;  
                LocalBuilder local = null;  
                foreach (var literal in literals)  
                {  
                    // find the best member, preferring case-sensitive  
                    PropertyInfo exact = null, fallback = null;  
                    string huntName = literal.Member;  
                    for(int i = 0; i < propsArr.Length;i++)  
                    {  
                        string thisName = propsArr[i].Name;  
                        if(string.Equals(thisName, huntName, StringComparison.InvariantCultureIgnoreCase))  
                        {  
                            fallback = propsArr[i];  
                            if(string.Equals(thisName, huntName, StringComparison.InvariantCulture))  
                            {  
                                exact = fallback;  
                                break;  
                            }  
                        }  
                    }  
                    var prop = exact ?? fallback;  
  
  
                    if(prop != null)  
                    {  
                        il.Emit(OpCodes.Ldstr, literal.Token);  
                        il.Emit(OpCodes.Ldloc_0); // command, sql, typed parameter  
                        il.EmitCall(callOpCode, prop.GetGetMethod(), null); // command, sql, typed value  
                        Type propType = prop.PropertyType;  
                        var typeCode = Type.GetTypeCode(propType);  
                        switch (typeCode)  
                        {  
                            case TypeCode.Boolean:  
                            case TypeCode.Byte:  
                            case TypeCode.SByte:  
                            case TypeCode.UInt16:  
                            case TypeCode.Int16:  
                            case TypeCode.UInt32:  
                            case TypeCode.Int32:  
                            case TypeCode.UInt64:  
                            case TypeCode.Int64:  
                            case TypeCode.Single:  
                            case TypeCode.Double:  
                            case TypeCode.Decimal:  
                                // need to stloc, ldloca, call  
                                // re-use existing locals (both the last known, and via a dictionary)  
                                var convert = GetToString(typeCode);  
                                if (local == null || local.LocalType != propType)  
                                {  
                                    if (locals == null)  
                                    {  
                                        locals = new Dictionary<Type, LocalBuilder>();  
                                        local = null;  
                                    }  
                                    else  
                                    {  
                                        if (!locals.TryGetValue(propType, out local)) local = null;  
                                    }  
                                    if (local == null)  
                                    {  
                                        local = il.DeclareLocal(propType);  
                                        locals.Add(propType, local);  
                                    }  
                                }  
                                il.Emit(OpCodes.Stloc, local); // command, sql  
                                il.Emit(OpCodes.Ldloca, local); // command, sql, ref-to-value  
                                il.EmitCall(OpCodes.Call, InvariantCulture, null); // command, sql, ref-to-value, culture  
                                il.EmitCall(OpCodes.Call, convert, null); // command, sql, string value  
                                break;  
                            default:  
                                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);  
                    }  
                }  
                il.EmitCall(OpCodes.Callvirt, cmdText.GetSetMethod(), null); // empty  
            }  
  
  
            il.Emit(OpCodes.Ret);  
            return (Action<IDbCommand, object>)dm.CreateDelegate(typeof(Action<IDbCommand, object>));  
        }  
        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 => Type.GetTypeCode(x), x => x.GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(IFormatProvider) }, null));  
        static MethodInfo GetToString(TypeCode typeCode)  
        {  
            MethodInfo method;  
            return toStrings.TryGetValue(typeCode, out method) ? method : null;  
        }  
        static readonly MethodInfo StringReplace = typeof(string).GetMethod("Replace", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string), typeof(string) }, null),  
            InvariantCulture = typeof(CultureInfo).GetProperty("InvariantCulture", BindingFlags.Public | BindingFlags.Static).GetGetMethod();  
  
  
        private static int ExecuteCommand(IDbConnection cnn, ref CommandDefinition command, Action<IDbCommand, object> paramReader)  
        {  
            IDbCommand cmd = null;  
            bool wasClosed = cnn.State == ConnectionState.Closed;  
            try  
            {  
                cmd = command.SetupCommand(cnn, paramReader);  
                if (wasClosed) cnn.Open();  
                int result = cmd.ExecuteNonQuery();  
                command.OnCompleted();  
                return result;  
            }  
            finally  
            {  
                if (wasClosed) cnn.Close();  
                if (cmd != null) cmd.Dispose();  
            }  
        }  
  
  
        private static T ExecuteScalarImpl<T>(IDbConnection cnn, ref CommandDefinition command)  
        {  
            Action<IDbCommand, object> paramReader = null;  
            object param = command.Parameters;  
            if (param != null)  
            {  
                var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType(), null);  
                paramReader = GetCacheInfo(identity, command.Parameters, command.AddToCache).ParamReader;  
            }  
  
  
            IDbCommand cmd = null;  
            bool wasClosed = cnn.State == ConnectionState.Closed;  
            object result;  
            try  
            {  
                cmd = command.SetupCommand(cnn, paramReader);  
                if (wasClosed) cnn.Open();  
                result =cmd.ExecuteScalar();  
                command.OnCompleted();  
            }  
            finally  
            {  
                if (wasClosed) cnn.Close();  
                if (cmd != null) cmd.Dispose();  
            }  
            return Parse<T>(result);  
        }  
  
  
        private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefinition command, CommandBehavior commandBehavior, out IDbCommand cmd)  
        {  
            Action<IDbCommand, object> paramReader = GetParameterReader(cnn, ref command);  
            cmd = null;  
            bool wasClosed = cnn.State == ConnectionState.Closed, disposeCommand = true;  
            try  
            {  
                cmd = command.SetupCommand(cnn, paramReader);  
                if (wasClosed) cnn.Open();  
                if (wasClosed) commandBehavior |= CommandBehavior.CloseConnection;  
                var reader = cmd.ExecuteReader(commandBehavior);  
                wasClosed = false; // don't dispose before giving it to them!  
                disposeCommand = false;  
                // note: command.FireOutputCallbacks(); would be useless here; parameters come at the **end** of the TDS stream  
                return reader;  
            }  
            finally  
            {  
                if (wasClosed) cnn.Close();  
                if (cmd != null && disposeCommand) cmd.Dispose();  
            }  
        }  
  
  
        private static Action<IDbCommand, object> GetParameterReader(IDbConnection cnn, ref CommandDefinition command)  
        {  
            object param = command.Parameters;  
            IEnumerable multiExec = GetMultiExec(param);  
            Identity identity;  
            CacheInfo info = null;  
            if (multiExec != null)  
            {  
                throw new NotSupportedException("MultiExec is not supported by ExecuteReader");  
            }  
  
  
            // nice and simple  
            if (param != null)  
            {  
                identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType(), null);  
                info = GetCacheInfo(identity, param, command.AddToCache);  
            }  
            var paramReader = info == null ? null : info.ParamReader;  
            return paramReader;  
        }  
  
  
        private static Func<IDataReader, object> GetStructDeserializer(Type type, Type effectiveType, int index)  
        {  
            // no point using special per-type handling here; it boils down to the same, plus not all are supported anyway (see: SqlDataReader.GetChar - not supported!)  
#pragma warning disable 618  
            if (type == typeof(char))  
            { // this *does* need special handling, though  
                return r => SqlMapper.ReadChar(r.GetValue(index));  
            }  
            if (type == typeof(char?))  
            {  
                return r => SqlMapper.ReadNullableChar(r.GetValue(index));  
            }  
            if (type.FullName == LinqBinary)  
            {  
                return r => Activator.CreateInstance(type, r.GetValue(index));  
            }  
#pragma warning restore 618  
  
  
            if (effectiveType.IsEnum)  
            {   // assume the value is returned as the correct type (int/byte/etc), but box back to the typed enum  
                return r =>  
                {  
                    var val = r.GetValue(index);  
                    if(val is float || val is double || val is decimal)  
                    {  
                        val = Convert.ChangeType(val, Enum.GetUnderlyingType(effectiveType), CultureInfo.InvariantCulture);  
                    }  
                    return val is DBNull ? null : Enum.ToObject(effectiveType, val);  
                };  
            }  
            ITypeHandler handler;  
            if(typeHandlers.TryGetValue(type, out handler))  
            {  
                return r =>  
                {  
                    var val = r.GetValue(index);  
                    return val is DBNull ? null : handler.Parse(type, val);  
                };  
            }  
            return r =>  
            {  
                var val = r.GetValue(index);  
                return val is DBNull ? null : val;  
            };  
        }  
  
  
        private static T Parse<T>(object value)  
        {  
            if (value == null || value is DBNull) return default(T);  
            if (value is T) return (T)value;  
            var type = typeof(T);  
            type = Nullable.GetUnderlyingType(type) ?? type;  
            if (type.IsEnum)  
            {  
                if (value is float || value is double || value is decimal)  
                {  
                    value = Convert.ChangeType(value, Enum.GetUnderlyingType(type), CultureInfo.InvariantCulture);  
                }  
                return (T)Enum.ToObject(type, value);  
            }  
            ITypeHandler handler;  
            if (typeHandlers.TryGetValue(type, out handler))  
            {  
                return (T)handler.Parse(type, value);  
            }  
            return (T)Convert.ChangeType(value, type, CultureInfo.InvariantCulture);  
        }  
  
  
        static readonly MethodInfo  
                    enumParse = typeof(Enum).GetMethod("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))  
                        .Select(p => p.GetGetMethod()).First();  
  
  
        /// <summary>  
        /// Gets type-map for the given type  
        /// </summary>  
        /// <returns>Type map implementation, DefaultTypeMap instance if no override present</returns>  
        public static ITypeMap GetTypeMap(Type type)  
        {  
            if (type == null) throw new ArgumentNullException("type");  
            var map = (ITypeMap)_typeMaps[type];  
            if (map == null)  
            {  
                lock (_typeMaps)  
                {   // double-checked; store this to avoid reflection next time we see this type  
                    // since multiple queries commonly use the same domain-entity/DTO/view-model type  
                    map = (ITypeMap)_typeMaps[type];  
                    if (map == null)  
                    {  
                        map = new DefaultTypeMap(type);  
                        _typeMaps[type] = map;  
                    }  
                }  
            }  
            return map;  
        }  
  
  
        // use Hashtable to get free lockless reading  
        private static readonly Hashtable _typeMaps = new Hashtable();  
  
  
        /// <summary>  
        /// Set custom mapping for type deserializers  
        /// </summary>  
        /// <param name="type">Entity type to override</param>  
        /// <param name="map">Mapping rules impementation, null to remove custom map</param>  
        public static void SetTypeMap(Type type, ITypeMap map)  
        {  
            if (type == null)  
                throw new ArgumentNullException("type");  
  
  
            if (map == null || map is DefaultTypeMap)  
            {  
                lock (_typeMaps)  
                {  
                    _typeMaps.Remove(type);  
                }  
            }  
            else  
            {  
                lock (_typeMaps)  
                {  
                    _typeMaps[type] = map;  
                }  
            }  
  
  
            PurgeQueryCacheByType(type);  
        }  
  
  
        /// <summary>  
        /// Internal use only  
        /// </summary>  
        /// <param name="type"></param>  
        /// <param name="reader"></param>  
        /// <param name="startBound"></param>  
        /// <param name="length"></param>  
        /// <param name="returnNullIfFirstMissing"></param>  
        /// <returns></returns>  
        public static Func<IDataReader, object> GetTypeDeserializer(  
#if CSHARP30  
Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing  
#else  
Type type, IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false  
#endif  
)  
        {  
  
  
            var dm = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), typeof(object), new[] { typeof(IDataReader) }, true);  
            var il = dm.GetILGenerator();  
            il.DeclareLocal(typeof(int));  
            il.DeclareLocal(type);  
            il.Emit(OpCodes.Ldc_I4_0);  
            il.Emit(OpCodes.Stloc_0);  
  
  
            if (length == -1)  
            {  
                length = reader.FieldCount - startBound;  
            }  
  
  
            if (reader.FieldCount <= startBound)  
            {  
                throw MultiMapException(reader);  
            }  
  
  
            var names = Enumerable.Range(startBound, length).Select(i => reader.GetName(i)).ToArray();  
  
  
            ITypeMap typeMap = GetTypeMap(type);  
  
  
            int index = startBound;  
  
  
            ConstructorInfo specializedConstructor = null;  
  
  
            bool supportInitialize = false;  
            if (type.IsValueType)  
            {  
                il.Emit(OpCodes.Ldloca_S, (byte)1);  
                il.Emit(OpCodes.Initobj, type);  
            }  
            else  
            {  
                var types = new Type[length];  
                for (int i = startBound; i < startBound + length; i++)  
                {  
                    types[i - startBound] = reader.GetFieldType(i);  
                }  
  
  
                var explicitConstr = typeMap.FindExplicitConstructor();  
                if (explicitConstr != null)  
                {  
                    var structLocals = new Dictionary<Type, LocalBuilder>();  
  
  
                    var consPs = explicitConstr.GetParameters();  
                    foreach(var p in consPs)  
                    {  
                        if(!p.ParameterType.IsValueType)  
                        {  
                            il.Emit(OpCodes.Ldnull);  
                        }  
                        else  
                        {  
                            LocalBuilder loc;  
                            if(!structLocals.TryGetValue(p.ParameterType, out loc))  
                            {  
                                structLocals[p.ParameterType] = loc = il.DeclareLocal(p.ParameterType);  
                            }  
  
  
                            il.Emit(OpCodes.Ldloca, (short)loc.LocalIndex);  
                            il.Emit(OpCodes.Initobj, p.ParameterType);  
                            il.Emit(OpCodes.Ldloca, (short)loc.LocalIndex);  
                            il.Emit(OpCodes.Ldobj, p.ParameterType);  
                        }  
                    }  
  
  
                    il.Emit(OpCodes.Newobj, explicitConstr);  
                    il.Emit(OpCodes.Stloc_1);  
                    supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type);  
                    if (supportInitialize)  
                    {  
                        il.Emit(OpCodes.Ldloc_1);  
                        il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod("BeginInit"), null);  
                    }  
                }  
                else  
                {  
                    var ctor = typeMap.FindConstructor(names, types);  
                    if (ctor == null)  
                    {  
                        string proposedTypes = "(" + string.Join(", ", types.Select((t, i) => t.FullName + " " + names[i]).ToArray()) + ")";  
                        throw new InvalidOperationException(string.Format("A parameterless default constructor or one matching signature {0} is required for {1} materialization", proposedTypes, type.FullName));  
                    }  
  
  
                    if (ctor.GetParameters().Length == 0)  
                    {  
                        il.Emit(OpCodes.Newobj, ctor);  
                        il.Emit(OpCodes.Stloc_1);  
                        supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type);  
                        if (supportInitialize)  
                        {  
                            il.Emit(OpCodes.Ldloc_1);  
                            il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod("BeginInit"), null);  
                        }  
                    }  
                    else  
                    {  
                        specializedConstructor = ctor;  
                    }  
                }  
            }  
  
  
            il.BeginExceptionBlock();  
            if (type.IsValueType)  
            {  
                il.Emit(OpCodes.Ldloca_S, (byte)1);// [target]  
            }  
            else if (specializedConstructor == null)  
            {  
                il.Emit(OpCodes.Ldloc_1);// [target]  
            }  
  
  
            var members = (specializedConstructor != null  
                ? names.Select(n => typeMap.GetConstructorParameter(specializedConstructor, n))  
                : names.Select(n => typeMap.GetMember(n))).ToList();  
  
  
            // stack is now [target]  
  
  
            bool first = true;  
            var allDone = il.DefineLabel();  
            int enumDeclareLocal = -1, valueCopyLocal = il.DeclareLocal(typeof(object)).LocalIndex;  
            foreach (var item in members)  
            {  
                if (item != null)  
                {  
                    if (specializedConstructor == null)  
                        il.Emit(OpCodes.Dup); // stack is now [target][target]  
                    Label isDbNullLabel = il.DefineLabel();  
                    Label finishLabel = il.DefineLabel();  
  
  
                    il.Emit(OpCodes.Ldarg_0); // stack is now [target][target][reader]  
                    EmitInt32(il, index); // stack is now [target][target][reader][index]  
                    il.Emit(OpCodes.Dup);// stack is now [target][target][reader][index][index]  
                    il.Emit(OpCodes.Stloc_0);// stack is now [target][target][reader][index]  
                    il.Emit(OpCodes.Callvirt, getItem); // stack is now [target][target][value-as-object]  
                    il.Emit(OpCodes.Dup); // stack is now [target][target][value-as-object][value-as-object]  
                    StoreLocal(il, valueCopyLocal);  
                    Type colType = reader.GetFieldType(index);  
                    Type memberType = item.MemberType;  
  
  
                    if (memberType == typeof(char) || memberType == typeof(char?))  
                    {  
                        il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod(  
                            memberType == typeof(char) ? "ReadChar" : "ReadNullableChar", BindingFlags.Static | BindingFlags.Public), null); // stack is now [target][target][typed-value]  
                    }  
                    else  
                    {  
                        il.Emit(OpCodes.Dup); // stack is now [target][target][value][value]  
                        il.Emit(OpCodes.Isinst, typeof(DBNull)); // stack is now [target][target][value-as-object][DBNull or null]  
                        il.Emit(OpCodes.Brtrue_S, isDbNullLabel); // stack is now [target][target][value-as-object]  
  
  
                        // unbox nullable enums as the primitive, i.e. byte etc  
  
  
                        var nullUnderlyingType = Nullable.GetUnderlyingType(memberType);  
                        var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum ? nullUnderlyingType : memberType;  
  
  
                        if (unboxType.IsEnum)  
                        {  
                            Type numericType = Enum.GetUnderlyingType(unboxType);  
                            if(colType == typeof(string))  
                            {  
                                if (enumDeclareLocal == -1)  
                                {  
                                    enumDeclareLocal = il.DeclareLocal(typeof(string)).LocalIndex;  
                                }  
                                il.Emit(OpCodes.Castclass, typeof(string)); // stack is now [target][target][string]  
                                StoreLocal(il, enumDeclareLocal); // stack is now [target][target]  
                                il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [target][target][enum-type-token]  
                                il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"), null);// stack is now [target][target][enum-type]  
                                LoadLocal(il, enumDeclareLocal); // stack is now [target][target][enum-type][string]  
                                il.Emit(OpCodes.Ldc_I4_1); // stack is now [target][target][enum-type][string][true]  
                                il.EmitCall(OpCodes.Call, enumParse, null); // stack is now [target][target][enum-as-object]  
                                il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [target][target][typed-value]  
                            }  
                            else  
                            {  
                                FlexibleConvertBoxedFromHeadOfStack(il, colType, unboxType, numericType);  
                            }  
  
  
                            if (nullUnderlyingType != null)  
                            {  
                                il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType })); // stack is now [target][target][typed-value]  
                            }  
                        }  
                        else if (memberType.FullName == LinqBinary)  
                        {  
                            il.Emit(OpCodes.Unbox_Any, typeof(byte[])); // stack is now [target][target][byte-array]  
                            il.Emit(OpCodes.Newobj, memberType.GetConstructor(new Type[] { typeof(byte[]) }));// stack is now [target][target][binary]  
                        }  
                        else  
                        {  
                            TypeCode dataTypeCode = Type.GetTypeCode(colType), unboxTypeCode = Type.GetTypeCode(unboxType);  
                            bool hasTypeHandler;  
                            if ((hasTypeHandler = typeHandlers.ContainsKey(unboxType)) || colType == unboxType || dataTypeCode == unboxTypeCode || dataTypeCode == Type.GetTypeCode(nullUnderlyingType))  
                            {  
                                if (hasTypeHandler)  
                                {  
#pragma warning disable 618  
                                    il.EmitCall(OpCodes.Call, typeof(TypeHandlerCache<>).MakeGenericType(unboxType).GetMethod("Parse"), null); // stack is now [target][target][typed-value]  
#pragma warning restore 618  
                                }  
                                else  
                                {  
                                    il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [target][target][typed-value]  
                                }  
                            }  
                            else  
                            {  
                                // not a direct match; need to tweak the unbox  
                                FlexibleConvertBoxedFromHeadOfStack(il, colType, nullUnderlyingType ?? unboxType, null);  
                                if (nullUnderlyingType != null)  
                                {  
                                    il.Emit(OpCodes.Newobj, unboxType.GetConstructor(new[] { nullUnderlyingType })); // stack is now [target][target][typed-value]  
                                }  
  
  
                            }  
  
  
                        }  
                    }  
                    if (specializedConstructor == null)  
                    {  
                        // Store the value in the property/field  
                        if (item.Property != null)  
                        {  
                            if (type.IsValueType)  
                            {  
                                il.Emit(OpCodes.Call, DefaultTypeMap.GetPropertySetter(item.Property, type)); // stack is now [target]  
                            }  
                            else  
                            {  
                                il.Emit(OpCodes.Callvirt, DefaultTypeMap.GetPropertySetter(item.Property, type)); // stack is now [target]  
                            }  
                        }  
                        else  
                        {  
                            il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]  
                        }  
                    }  
  
  
                    il.Emit(OpCodes.Br_S, finishLabel); // stack is now [target]  
  
  
                    il.MarkLabel(isDbNullLabel); // incoming stack: [target][target][value]  
                    if (specializedConstructor != null)  
                    {  
                        il.Emit(OpCodes.Pop);  
                        if (item.MemberType.IsValueType)  
                        {  
                            int localIndex = il.DeclareLocal(item.MemberType).LocalIndex;  
                            LoadLocalAddress(il, localIndex);  
                            il.Emit(OpCodes.Initobj, item.MemberType);  
                            LoadLocal(il, localIndex);  
                        }  
                        else  
                        {  
                            il.Emit(OpCodes.Ldnull);  
                        }  
                    }  
                    else  
                    {  
                        il.Emit(OpCodes.Pop); // stack is now [target][target]  
                        il.Emit(OpCodes.Pop); // stack is now [target]  
                    }  
  
  
                    if (first && returnNullIfFirstMissing)  
                    {  
                        il.Emit(OpCodes.Pop);  
                        il.Emit(OpCodes.Ldnull); // stack is now [null]  
                        il.Emit(OpCodes.Stloc_1);  
                        il.Emit(OpCodes.Br, allDone);  
                    }  
  
  
                    il.MarkLabel(finishLabel);  
                }  
                first = false;  
                index += 1;  
            }  
            if (type.IsValueType)  
            {  
                il.Emit(OpCodes.Pop);  
            }  
            else  
            {  
                if (specializedConstructor != null)  
                {  
                    il.Emit(OpCodes.Newobj, specializedConstructor);  
                }  
                il.Emit(OpCodes.Stloc_1); // stack is empty  
                if (supportInitialize)  
                {  
                    il.Emit(OpCodes.Ldloc_1);  
                    il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod("EndInit"), null);  
                }  
            }  
            il.MarkLabel(allDone);  
            il.BeginCatchBlock(typeof(Exception)); // stack is Exception  
            il.Emit(OpCodes.Ldloc_0); // stack is Exception, index  
            il.Emit(OpCodes.Ldarg_0); // stack is Exception, index, reader  
            LoadLocal(il, valueCopyLocal); // stack is Exception, index, reader, value  
            il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod("ThrowDataException"), null);  
            il.EndExceptionBlock();  
  
  
            il.Emit(OpCodes.Ldloc_1); // stack is [rval]  
            if (type.IsValueType)  
            {  
                il.Emit(OpCodes.Box, type);  
            }  
            il.Emit(OpCodes.Ret);  
  
  
            return (Func<IDataReader, object>)dm.CreateDelegate(typeof(Func<IDataReader, object>));  
        }  
  
  
        private static void FlexibleConvertBoxedFromHeadOfStack(ILGenerator il, Type from, Type to, Type via)  
        {  
            MethodInfo op;  
            if(from == (via ?? to))  
            {  
                il.Emit(OpCodes.Unbox_Any, to); // stack is now [target][target][typed-value]  
            }  
            else if ((op = GetOperator(from,to)) != null)  
            {  
                // this is handy for things like decimal <===> double  
                il.Emit(OpCodes.Unbox_Any, from); // stack is now [target][target][data-typed-value]  
                il.Emit(OpCodes.Call, op); // stack is now [target][target][typed-value]  
            }  
            else  
            {  
                bool handled = false;  
                OpCode opCode = default(OpCode);  
                switch (Type.GetTypeCode(from))  
                {  
                    case TypeCode.Boolean:  
                    case TypeCode.Byte:  
                    case TypeCode.SByte:  
                    case TypeCode.Int16:  
                    case TypeCode.UInt16:  
                    case TypeCode.Int32:  
                    case TypeCode.UInt32:  
                    case TypeCode.Int64:  
                    case TypeCode.UInt64:  
                    case TypeCode.Single:  
                    case TypeCode.Double:  
                        handled = true;  
                        switch (Type.GetTypeCode(via ?? to))  
                        {  
                            case TypeCode.Byte:  
                                opCode = OpCodes.Conv_Ovf_I1_Un; break;  
                            case TypeCode.SByte:  
                                opCode = OpCodes.Conv_Ovf_I1; break;  
                            case TypeCode.UInt16:  
                                opCode = OpCodes.Conv_Ovf_I2_Un; break;  
                            case TypeCode.Int16:  
                                opCode = OpCodes.Conv_Ovf_I2; break;  
                            case TypeCode.UInt32:  
                                opCode = OpCodes.Conv_Ovf_I4_Un; break;  
                            case TypeCode.Boolean: // boolean is basically an int, at least at this level  
                            case TypeCode.Int32:  
                                opCode = OpCodes.Conv_Ovf_I4; break;  
                            case TypeCode.UInt64:  
                                opCode = OpCodes.Conv_Ovf_I8_Un; break;  
                            case TypeCode.Int64:  
                                opCode = OpCodes.Conv_Ovf_I8; break;  
                            case TypeCode.Single:  
                                opCode = OpCodes.Conv_R4; break;  
                            case TypeCode.Double:  
                                opCode = OpCodes.Conv_R8; break;  
                            default:  
                                handled = false;  
                                break;  
                        }  
                        break;  
                }  
                if (handled)  
                {  
                    il.Emit(OpCodes.Unbox_Any, from); // stack is now [target][target][col-typed-value]  
                    il.Emit(opCode); // stack is now [target][target][typed-value]  
                    if (to == typeof(bool))  
                    { // compare to zero; I checked "csc" - this is the trick it uses; nice  
                        il.Emit(OpCodes.Ldc_I4_0);  
                        il.Emit(OpCodes.Ceq);  
                        il.Emit(OpCodes.Ldc_I4_0);  
                        il.Emit(OpCodes.Ceq);  
                    }  
                }  
                else  
                {  
                    il.Emit(OpCodes.Ldtoken, via ?? to); // stack is now [target][target][value][member-type-token]  
                    il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"), null); // stack is now [target][target][value][member-type]  
                    il.EmitCall(OpCodes.Call, typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(Type) }), null); // stack is now [target][target][boxed-member-type-value]  
                    il.Emit(OpCodes.Unbox_Any, to); // stack is now [target][target][typed-value]  
                }  
            }              
        }  
  
  
        static MethodInfo GetOperator(Type from, Type to)  
        {  
            if (to == null) return null;  
            MethodInfo[] fromMethods, toMethods;  
            return ResolveOperator(fromMethods = from.GetMethods(BindingFlags.Static | BindingFlags.Public), from, to, "op_Implicit")  
                ?? ResolveOperator(toMethods = to.GetMethods(BindingFlags.Static | BindingFlags.Public), from, to, "op_Implicit")  
                ?? ResolveOperator(fromMethods, from, to, "op_Explicit")  
                ?? ResolveOperator(toMethods, from, to, "op_Explicit");  
  
  
        }  
        static MethodInfo ResolveOperator(MethodInfo[] methods, Type from, Type to, string name)  
        {  
            for (int i = 0; i < methods.Length; i++)  
            {  
                if (methods[i].Name != name || methods[i].ReturnType != to) continue;  
                var args = methods[i].GetParameters();  
                if (args.Length != 1 || args[0].ParameterType != from) continue;  
                return methods[i];  
            }  
            return null;  
        }  
  
  
        private static void LoadLocal(ILGenerator il, int index)  
        {  
            if (index < 0 || index >= short.MaxValue) throw new ArgumentNullException("index");  
            switch (index)  
            {  
                case 0: il.Emit(OpCodes.Ldloc_0); break;  
                case 1: il.Emit(OpCodes.Ldloc_1); break;  
                case 2: il.Emit(OpCodes.Ldloc_2); break;  
                case 3: il.Emit(OpCodes.Ldloc_3); break;  
                default:  
                    if (index <= 255)  
                    {  
                        il.Emit(OpCodes.Ldloc_S, (byte)index);  
                    }  
                    else  
                    {  
                        il.Emit(OpCodes.Ldloc, (short)index);  
                    }  
                    break;  
            }  
        }  
        private static void StoreLocal(ILGenerator il, int index)  
        {  
            if (index < 0 || index >= short.MaxValue) throw new ArgumentNullException("index");  
            switch (index)  
            {  
                case 0: il.Emit(OpCodes.Stloc_0); break;  
                case 1: il.Emit(OpCodes.Stloc_1); break;  
                case 2: il.Emit(OpCodes.Stloc_2); break;  
                case 3: il.Emit(OpCodes.Stloc_3); break;  
                default:  
                    if (index <= 255)  
                    {  
                        il.Emit(OpCodes.Stloc_S, (byte)index);  
                    }  
                    else  
                    {  
                        il.Emit(OpCodes.Stloc, (short)index);  
                    }  
                    break;  
            }  
        }  
        private static void LoadLocalAddress(ILGenerator il, int index)  
        {  
            if (index < 0 || index >= short.MaxValue) throw new ArgumentNullException("index");  
  
  
            if (index <= 255)  
            {  
                il.Emit(OpCodes.Ldloca_S, (byte)index);  
            }  
            else  
            {  
                il.Emit(OpCodes.Ldloca, (short)index);  
            }  
        }  
        /// <summary>  
        /// Throws a data exception, only used internally  
        /// </summary>  
        [Obsolete("Intended for internal use only")]  
        public static void ThrowDataException(Exception ex, int index, IDataReader reader, object value)  
        {  
            Exception toThrow;  
            try  
            {  
                string name = "(n/a)", formattedValue = "(n/a)";  
                if (reader != null && index >= 0 && index < reader.FieldCount)  
                {  
                    name = reader.GetName(index);  
                    try  
                    {  
                        if (value == null || value is DBNull)  
                        {  
                            formattedValue = "<null>";  
                        }  
                        else  
                        {  
                            formattedValue = Convert.ToString(value) + " - " + Type.GetTypeCode(value.GetType());  
                        }  
                    }  
                    catch (Exception valEx)  
                    {  
                        formattedValue = valEx.Message;  
                    }  
                }  
                toThrow = new DataException(string.Format("Error parsing column {0} ({1}={2})", index, name, formattedValue), ex);  
            }  
            catch  
            { // throw the **original** exception, wrapped as DataException  
                toThrow = new DataException(ex.Message, ex);  
            }  
            throw toThrow;  
        }  
        private static void EmitInt32(ILGenerator il, int value)  
        {  
            switch (value)  
            {  
                case -1: il.Emit(OpCodes.Ldc_I4_M1); break;  
                case 0: il.Emit(OpCodes.Ldc_I4_0); break;  
                case 1: il.Emit(OpCodes.Ldc_I4_1); break;  
                case 2: il.Emit(OpCodes.Ldc_I4_2); break;  
                case 3: il.Emit(OpCodes.Ldc_I4_3); break;  
                case 4: il.Emit(OpCodes.Ldc_I4_4); break;  
                case 5: il.Emit(OpCodes.Ldc_I4_5); break;  
                case 6: il.Emit(OpCodes.Ldc_I4_6); break;  
                case 7: il.Emit(OpCodes.Ldc_I4_7); break;  
                case 8: il.Emit(OpCodes.Ldc_I4_8); break;  
                default:  
                    if (value >= -128 && value <= 127)  
                    {  
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);  
                    }  
                    else  
                    {  
                        il.Emit(OpCodes.Ldc_I4, value);  
                    }  
                    break;  
            }  
        }  
  
  
  
  
        /// <summary>  
        /// Key used to indicate the type name associated with a DataTable  
        /// </summary>  
        private const string DataTableTypeNameKey = "dapper:TypeName";  
  
  
        /// <summary>  
        /// How should connection strings be compared for equivalence? Defaults to StringComparer.Ordinal.  
        /// Providing a custom implementation can be useful for allowing multi-tenancy databases with identical  
        /// schema to share strategies. Note that usual equivalence rules apply: any equivalent connection strings  
        /// <b>MUST</b> yield the same hash-code.  
        /// </summary>  
        public static IEqualityComparer<string> ConnectionStringComparer  
        {  
            get { return connectionStringComparer; }  
            set { connectionStringComparer = value ?? StringComparer.Ordinal; }  
        }  
        private static IEqualityComparer<string> connectionStringComparer = StringComparer.Ordinal;  
  
  
  
  
        /// <summary>  
        /// The grid reader provides interfaces for reading multiple result sets from a Dapper query   
        /// </summary>  
        public partial class GridReader : IDisposable  
        {  
            private IDataReader reader;  
            private IDbCommand command;  
            private Identity identity;  
  
  
            internal GridReader(IDbCommand command, IDataReader reader, Identity identity, SqlMapper.IParameterCallbacks callbacks)  
            {  
                this.command = command;  
                this.reader = reader;  
                this.identity = identity;  
                this.callbacks = callbacks;  
            }  
 
 
#if !CSHARP30  
  
  
            /// <summary>  
            /// 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<string,object></remarks>  
            public IEnumerable<dynamic> Read(bool buffered = true)  
            {  
                return ReadImpl<dynamic>(typeof(DapperRow), buffered);  
            }  
#endif  
 
 
#if CSHARP30  
            /// <summary>  
            /// Read the next grid of results  
            /// </summary>  
            public IEnumerable<T> Read<T>()  
            {  
                return Read<T>(true);  
            }  
#endif  
            /// <summary>  
            /// Read the next grid of results  
            /// </summary>  
#if CSHARP30  
            public IEnumerable<T> Read<T>(bool buffered)  
#else  
            public IEnumerable<T> Read<T>(bool buffered = true)  
#endif  
            {  
                return ReadImpl<T>(typeof(T), buffered);  
            }  
  
  
            /// <summary>  
            /// Read the next grid of results  
            /// </summary>  
#if CSHARP30  
            public IEnumerable<object> Read(Type type, bool buffered)  
#else  
            public IEnumerable<object> Read(Type type, bool buffered = true)  
#endif  
            {  
                if (type == null) throw new ArgumentNullException("type");  
                return ReadImpl<object>(type, buffered);  
            }  
  
  
            private IEnumerable<T> ReadImpl<T>(Type type, bool buffered)  
            {  
                if (reader == null) throw new ObjectDisposedException(GetType().FullName, "The reader has been disposed; this can happen after all data has been consumed");  
                if (consumed) throw new InvalidOperationException("Query results must be consumed in the correct order, and each result can only be consumed once");  
                var typedIdentity = identity.ForGrid(type, gridIndex);  
                CacheInfo cache = GetCacheInfo(typedIdentity, null, true);  
                var deserializer = cache.Deserializer;  
  
  
                int hash = GetColumnHash(reader);  
                if (deserializer.Func == null || deserializer.Hash != hash)  
                {  
                    deserializer = new DeserializerState(hash, GetDeserializer(type, reader, 0, -1, false));  
                    cache.Deserializer = deserializer;  
                }  
                consumed = true;  
                var result = ReadDeferred<T>(gridIndex, deserializer.Func, typedIdentity);  
                return buffered ? result.ToList() : 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[] {   
                    typeof(TFirst),   
                    typeof(TSecond),  
                    typeof(TThird),  
                    typeof(TFourth),  
                    typeof(TFifth),  
                    typeof(TSixth),  
                    typeof(TSeventh)  
                }, gridIndex);  
                try  
                {  
                    foreach (var r in SqlMapper.MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, default(CommandDefinition), func, splitOn, reader, identity, false))  
                    {  
                        yield return r;  
                    }  
                }  
                finally  
                {  
                    NextResult();  
                }  
            }  
 
 
#if CSHARP30  
            /// <summary>  
            /// Read multiple objects from a single record set on the grid  
            /// </summary>  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TReturn>(Func<TFirst, TSecond, TReturn> func, string splitOn)  
            {  
                return Read<TFirst, TSecond, TReturn>(func, splitOn, true);  
            }  
#endif  
            /// <summary>  
            /// Read multiple objects from a single record set on the grid  
            /// </summary>  
#if CSHARP30  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TReturn>(Func<TFirst, TSecond, TReturn> func, string splitOn, bool buffered)  
#else  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TReturn>(Func<TFirst, TSecond, TReturn> func, string splitOn = "id", bool buffered = true)  
#endif  
            {  
                var result = MultiReadInternal<TFirst, TSecond, DontMap, DontMap, DontMap, DontMap, DontMap, TReturn>(func, splitOn);  
                return buffered ? result.ToList() : result;  
            }  
 
 
#if CSHARP30  
            /// <summary>  
            /// Read multiple objects from a single record set on the grid  
            /// </summary>  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TReturn>(Func<TFirst, TSecond, TThird, TReturn> func, string splitOn)  
            {  
                return Read<TFirst, TSecond, TThird, TReturn>(func, splitOn, true);  
            }  
#endif  
            /// <summary>  
            /// Read multiple objects from a single record set on the grid  
            /// </summary>  
#if CSHARP30  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TReturn>(Func<TFirst, TSecond, TThird, TReturn> func, string splitOn, bool buffered)  
#else  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TReturn>(Func<TFirst, TSecond, TThird, TReturn> func, string splitOn = "id", bool buffered = true)  
#endif  
            {  
                var result = MultiReadInternal<TFirst, TSecond, TThird, DontMap, DontMap, DontMap, DontMap, TReturn>(func, splitOn);  
                return buffered ? result.ToList() : result;  
            }  
 
 
#if CSHARP30  
            /// <summary>  
            /// Read multiple objects from a single record set on the grid  
            /// </summary>  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TFourth, TReturn>(Func<TFirst, TSecond, TThird, TFourth, TReturn> func, string splitOn)  
            {  
                return Read<TFirst, TSecond, TThird, TFourth, TReturn>(func, splitOn, true);  
            }  
#endif  
  
  
            /// <summary>  
            /// Read multiple objects from a single record set on the grid  
            /// </summary>  
#if CSHARP30  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TFourth, TReturn>(Func<TFirst, TSecond, TThird, TFourth, TReturn> func, string splitOn, bool buffered)  
#else  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TFourth, TReturn>(Func<TFirst, TSecond, TThird, TFourth, TReturn> func, string splitOn = "id", bool buffered = true)  
#endif  
            {  
                var result = MultiReadInternal<TFirst, TSecond, TThird, TFourth, DontMap, DontMap, DontMap, TReturn>(func, splitOn);  
                return buffered ? result.ToList() : result;  
            }  
 
 
 
 
 
 
#if !CSHARP30  
            /// <summary>  
            /// Read multiple objects from a single record set on the grid  
            /// </summary>  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn> func, string splitOn = "id", bool buffered = true)  
            {  
                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>  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn>(Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn> func, string splitOn = "id", bool buffered = true)  
            {  
                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>  
            public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn> func, string splitOn = "id", bool buffered = true)  
            {  
                var result = MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(func, splitOn);  
                return buffered ? result.ToList() : result;  
            }  
#endif  
  
  
            private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, object> deserializer, Identity typedIdentity)  
            {  
                try  
                {  
                    while (index == gridIndex && reader.Read())  
                    {  
                        yield return (T)deserializer(reader);  
                    }  
                }  
                finally // finally so that First etc progresses things even when multiple rows  
                {  
                    if (index == gridIndex)  
                    {  
                        NextResult();  
                    }  
                }  
            }  
            private int gridIndex, readCount;  
            private bool consumed;  
            private SqlMapper.IParameterCallbacks callbacks;  
  
  
            /// <summary>  
            /// Has the underlying reader been consumed?  
            /// </summary>  
            public bool IsConsumed  
            {  
                get  
                {  
                    return consumed;  
                }  
            }  
            private void NextResult()  
            {  
                if (reader.NextResult())  
                {  
                    readCount++;  
                    gridIndex++;  
                    consumed = false;  
                }  
                else  
                {  
                    // happy path; close the reader cleanly - no  
                    // need for "Cancel" etc  
                    reader.Dispose();  
                    reader = null;  
                    if (callbacks != null) callbacks.OnCompleted();  
                    Dispose();  
                }  
            }  
            /// <summary>  
            /// Dispose the grid, closing and disposing both the underlying reader and command.  
            /// </summary>  
            public void Dispose()  
            {  
                if (reader != null)  
                {  
                    if (!reader.IsClosed && command != null) command.Cancel();  
                    reader.Dispose();  
                    reader = null;  
                }  
                if (command != null)  
                {  
                    command.Dispose();  
                    command = null;  
                }  
            }  
        }  
  
  
        /// <summary>  
        /// Used to pass a DataTable as a TableValuedParameter  
        /// </summary>  
        public static ICustomQueryParameter AsTableValuedParameter(this DataTable table, string typeName  
#if !CSHARP30  
            = null  
#endif  
            )  
        {  
            return new TableValuedParameter(table, typeName);  
        }  
  
  
        /// <summary>  
        /// Associate a DataTable with a type name  
        /// </summary>  
        public static void SetTypeName(this DataTable table, string typeName)  
        {  
            if (table != null)  
            {  
                if (string.IsNullOrEmpty(typeName))  
                    table.ExtendedProperties.Remove(DataTableTypeNameKey);  
                else  
                    table.ExtendedProperties[DataTableTypeNameKey] = typeName;  
            }  
        }  
  
  
        /// <summary>  
        /// Fetch the type name associated with a DataTable  
        /// </summary>  
        public static string GetTypeName(this DataTable table)  
        {  
            return table == null ? null : table.ExtendedProperties[DataTableTypeNameKey] as string;  
        }  
  
  
  
  
        // one per thread  
        [ThreadStatic]  
        private static StringBuilder perThreadStringBuilderCache;  
        private static StringBuilder GetStringBuilder()  
        {  
            var tmp = perThreadStringBuilderCache;  
            if (tmp != null)  
            {  
                perThreadStringBuilderCache = null;  
                tmp.Length = 0;  
                return tmp;  
            }  
            return new StringBuilder();  
        }  
  
  
        private static string __ToStringRecycle(this StringBuilder obj)  
        {  
            if (obj == null) return "";  
            var s = obj.ToString();  
            if(perThreadStringBuilderCache == null)  
            {  
                perThreadStringBuilderCache = obj;  
            }  
            return s;  
        }  
    }  
  
  
    /// <summary>  
    /// A bag of parameters that can be passed to the Dapper Query and Execute methods  
    /// </summary>  
    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 member]  
        {  
            get  
            {  
                ParamInfo param;  
                return parameters.TryGetValue(member, out param) ? param.Value : null;  
            }  
        }  
  
  
        partial class ParamInfo  
        {  
            public string Name { get; set; }  
            public object Value { get; set; }  
            public ParameterDirection ParameterDirection { get; set; }  
            public DbType? DbType { get; set; }  
            public int? Size { get; set; }  
            public IDbDataParameter AttachedParam { get; set; }  
            internal Action<object, DynamicParameters> OutputCallback { get; set; }  
            internal object OutputTarget { get; set; }  
            internal bool CameFromTemplate { get; set; }  
        }  
  
  
        /// <summary>  
        /// construct a dynamic parameter bag  
        /// </summary>  
        public DynamicParameters()  
        {  
            RemoveUnused = true;  
        }  
  
  
        /// <summary>  
        /// construct a dynamic parameter bag  
        /// </summary>  
        /// <param name="template">can be an anonymous type or a DynamicParameters bag</param>  
        public DynamicParameters(object template)  
        {  
            RemoveUnused = true;  
            AddDynamicParams(template);  
        }  
  
  
        /// <summary>  
        /// Append a whole object full of params to the dynamic  
        /// EG: AddDynamicParams(new {A = 1, B = 2}) // will add property A and B to the dynamic  
        /// </summary>  
        /// <param name="param"></param>  
        public void AddDynamicParams(object param)  
        {  
            var obj = param as object;  
            if (obj != null)  
            {  
                var subDynamic = obj as DynamicParameters;  
                if (subDynamic == null)  
                {  
                    var dictionary = obj as IEnumerable<KeyValuePair<string, object>>;  
                    if (dictionary == null)  
                    {  
                        templates = templates ?? new List<object>();  
                        templates.Add(obj);  
                    }  
                    else  
                    {  
                        foreach (var kvp in dictionary)  
                        {  
                            Add(kvp.Key, kvp.Value, null, null, null);  
                        }  
                    }  
                }  
                else  
                {  
                    if (subDynamic.parameters != null)  
                    {  
                        foreach (var kvp in subDynamic.parameters)  
                        {  
                            parameters.Add(kvp.Key, kvp.Value);  
                        }  
                    }  
  
  
                    if (subDynamic.templates != null)  
                    {  
                        templates = templates ?? new List<object>();  
                        foreach (var t in subDynamic.templates)  
                        {  
                            templates.Add(t);  
                        }  
                    }  
                }  
            }  
        }  
  
  
        /// <summary>  
        /// Add a parameter to this dynamic parameter list  
        /// </summary>  
        /// <param name="name"></param>  
        /// <param name="value"></param>  
        /// <param name="dbType"></param>  
        /// <param name="direction"></param>  
        /// <param name="size"></param>  
        public void Add(  
#if CSHARP30  
string name, object value, DbType? dbType, ParameterDirection? direction, int? size  
#else  
string name, object value = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null  
#endif  
)  
        {  
            parameters[Clean(name)] = new ParamInfo() { Name = name, Value = value, ParameterDirection = direction ?? ParameterDirection.Input, DbType = dbType, Size = size };  
        }  
  
  
        static string Clean(string name)  
        {  
            if (!string.IsNullOrEmpty(name))  
            {  
                switch (name[0])  
                {  
                    case '@':  
                    case ':':  
                    case '?':  
                        return name.Substring(1);  
                }  
            }  
            return name;  
        }  
  
  
        void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Identity identity)  
        {  
            AddParameters(command, identity);  
        }  
  
  
        /// <summary>  
        /// If true, the command-text is inspected and only values that are clearly used are included on the connection  
        /// </summary>  
        public bool RemoveUnused { get; set; }  
  
  
        /// <summary>  
        /// Add all the parameters needed to the command just before it executes  
        /// </summary>  
        /// <param name="command">The raw command prior to execution</param>  
        /// <param name="identity">Information about the query</param>  
        protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)  
        {  
            var literals = SqlMapper.GetLiteralTokens(identity.sql);  
  
  
            if (templates != null)  
            {  
                foreach (var template in templates)  
                {  
                    var newIdent = identity.ForDynamicParameters(template.GetType());  
                    Action<IDbCommand, object> appender;  
  
  
                    lock (paramReaderCache)  
                    {  
                        if (!paramReaderCache.TryGetValue(newIdent, out appender))  
                        {  
                            appender = SqlMapper.CreateParamInfoGenerator(newIdent, true, RemoveUnused, literals);  
                            paramReaderCache[newIdent] = appender;  
                        }  
                    }  
  
  
                    appender(command, template);  
                }  
  
  
                // The parameters were added to the command, but not the   
                // DynamicParameters until now.  
                foreach (IDbDataParameter param in command.Parameters)  
                {  
                    // If someone makes a DynamicParameters with a template,  
                    // then explicitly adds a parameter of a matching name,  
                    // it will already exist in 'parameters'.  
                    if (!parameters.ContainsKey(param.ParameterName))   
                    {   
                        parameters.Add(param.ParameterName, new ParamInfo  
                        {  
                            AttachedParam = param,  
                            CameFromTemplate = true,  
                            DbType = param.DbType,  
                            Name = param.ParameterName,  
                            ParameterDirection = param.Direction,  
                            Size = param.Size,  
                            Value = param.Value  
                        });  
                    }  
                }  
  
  
                // Now that the parameters are added to the command, let's place our output callbacks  
                var tmp = outputCallbacks;  
                if (tmp != null)  
                {  
                    foreach (var generator in tmp)  
                    {  
                        generator();  
                    }  
                }  
            }  
  
  
            foreach (var param in parameters.Values)  
            {  
                if (param.CameFromTemplate) continue;  
  
  
                var dbType = param.DbType;  
                var val = param.Value;  
                string name = Clean(param.Name);  
                var isCustomQueryParameter = val is SqlMapper.ICustomQueryParameter;  
  
  
                SqlMapper.ITypeHandler handler = null;  
                if (dbType == null && val != null && !isCustomQueryParameter) dbType = SqlMapper.LookupDbType(val.GetType(), name, true, out handler);  
                if (dbType == DynamicParameters.EnumerableMultiParameter)  
                {  
#pragma warning disable 612, 618  
                    SqlMapper.PackListParameters(command, name, val);  
#pragma warning restore 612, 618  
                }  
                else if (isCustomQueryParameter)  
                {  
                    ((SqlMapper.ICustomQueryParameter)val).AddParameter(command, name);  
                }  
                else  
                {  
  
  
                    bool add = !command.Parameters.Contains(name);  
                    IDbDataParameter p;  
                    if (add)  
                    {  
                        p = command.CreateParameter();  
                        p.ParameterName = name;  
                    }  
                    else  
                    {  
                        p = (IDbDataParameter)command.Parameters[name];  
                    }  
  
  
                    p.Direction = param.ParameterDirection;  
                    if (handler == null)  
                    {  
                        p.Value = val ?? DBNull.Value;  
                        if (dbType != null && p.DbType != dbType)  
                        {  
                            p.DbType = dbType.Value;  
                        }  
                        var s = val as string;  
                        if (s != null)  
                        {  
                            if (s.Length <= DbString.DefaultLength)  
                            {  
                                p.Size = DbString.DefaultLength;  
                            }  
                        }  
                        if (param.Size != null)  
                        {  
                            p.Size = param.Size.Value;  
                        }                          
                    }  
                    else  
                    {  
                        if (dbType != null) p.DbType = dbType.Value;  
                        if (param.Size != null) p.Size = param.Size.Value;  
                        handler.SetValue(p, val ?? DBNull.Value);  
                    }  
  
  
                    if (add)  
                    {  
                        command.Parameters.Add(p);  
                    }  
                    param.AttachedParam = p;  
                }  
            }  
  
  
            // note: most non-priveleged implementations would use: this.ReplaceLiterals(command);  
            if(literals.Count != 0) SqlMapper.ReplaceLiterals(this, command, literals);  
        }  
  
  
        /// <summary>  
        /// All the names of the param in the bag, use Get to yank them out  
        /// </summary>  
        public IEnumerable<string> ParameterNames  
        {  
            get  
            {  
                return parameters.Select(p => p.Key);  
            }  
        }  
  
  
  
  
        /// <summary>  
        /// Get the value of a parameter  
        /// </summary>  
        /// <typeparam name="T"></typeparam>  
        /// <param name="name"></param>  
        /// <returns>The value, note DBNull.Value is not returned, instead the value is returned as null</returns>  
        public T Get<T>(string name)  
        {  
            var val = parameters[Clean(name)].AttachedParam.Value;  
            if (val == DBNull.Value)  
            {  
                if (default(T) != null)  
                {  
                    throw new ApplicationException("Attempting to cast a DBNull to a non nullable type!");  
                }  
                return default(T);  
            }  
            return (T)val;  
        }  
  
  
        /// <summary>  
        /// Allows you to automatically populate a target property/field from output parameters. It actually  
        /// creates an InputOutput parameter, so you can still pass data in.   
        /// </summary>  
        /// <typeparam name="T"></typeparam>  
        /// <param name="target">The object whose property/field you wish to populate.</param>  
        /// <param name="expression">A MemberExpression targeting a property/field of the target (or descendant thereof.)</param>  
        /// <param name="dbType"></param>  
        /// <param name="size">The size to set on the parameter. Defaults to 0, or DbString.DefaultLength in case of strings.</param>  
        /// <returns>The DynamicParameters instance</returns>  
#if CSHARP30  
        public DynamicParameters Output<T>(T target, Expression<Func<T, object>> expression, DbType? dbType, int? size)  
#else  
        public DynamicParameters Output<T>(T target, Expression<Func<T, object>> expression, DbType? dbType = null, int? size = null)  
#endif  
        {  
            var failMessage = "Expression must be a property/field chain off of a(n) {0} instance";  
            failMessage = string.Format(failMessage, typeof(T).Name);  
            Action @throw = () => { throw new InvalidOperationException(failMessage); };  
  
  
            // Is it even a MemberExpression?  
            var lastMemberAccess = expression.Body as MemberExpression;  
  
  
            if (lastMemberAccess == null ||  
                (lastMemberAccess.Member.MemberType != MemberTypes.Property &&  
                lastMemberAccess.Member.MemberType != MemberTypes.Field))  
            {  
                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();  
            }  
  
  
            // Does the chain consist of MemberExpressions leading to a ParameterExpression of type T?  
            MemberExpression diving = lastMemberAccess;  
            ParameterExpression constant = null;  
            // Retain a list of member names and the member expressions so we can rebuild the chain.  
            List<string> names = new List<string>();  
            List<MemberExpression> chain = new List<MemberExpression>();  
  
  
            do  
            {  
                // Insert the names in the right order so expression   
                // "Post.Author.Name" becomes parameter "PostAuthorName"  
                names.Insert(0, diving.Member.Name);  
                chain.Insert(0, diving);  
  
  
                constant = diving.Expression as ParameterExpression;  
                diving = diving.Expression as MemberExpression;  
  
  
                if (constant != null &&  
                    constant.Type == typeof(T))  
                {  
                    break;  
                }  
                else if (diving == null ||  
                    (diving.Member.MemberType != MemberTypes.Property &&  
                    diving.Member.MemberType != MemberTypes.Field))  
                {  
                    @throw();  
                }  
            }  
            while (diving != null);  
  
  
            var dynamicParamName = string.Join(string.Empty, names.ToArray());  
  
  
            // Before we get all emitty...  
            var lookup = string.Join("|", names.ToArray());  
  
  
            var cache = CachedOutputSetters<T>.Cache;  
            var setter = (Action<object, DynamicParameters>)cache[lookup];  
  
  
            if (setter != null) goto MAKECALLBACK;  
  
  
            // Come on let's build a method, let's build it, let's build it now!  
            var dm = new DynamicMethod(string.Format("ExpressionParam{0}", Guid.NewGuid()), null, new[] { typeof(object), this.GetType() }, true);  
            var il = dm.GetILGenerator();  
  
  
            il.Emit(OpCodes.Ldarg_0); // [object]  
            il.Emit(OpCodes.Castclass, typeof(T));    // [T]  
  
  
            // Count - 1 to skip the last member access  
            var i = 0;  
            for (; i < (chain.Count - 1); i++)  
            {  
                var member = chain[0].Member;  
  
  
                if (member.MemberType == MemberTypes.Property)  
                {  
                    var get = ((PropertyInfo)member).GetGetMethod(true);  
                    il.Emit(OpCodes.Callvirt, get); // [Member{i}]  
                }  
                else // Else it must be a field!  
                {  
                    il.Emit(OpCodes.Ldfld, ((FieldInfo)member)); // [Member{i}]  
                }  
            }  
  
  
            var paramGetter = this.GetType().GetMethod("Get", new Type[] { typeof(string) }).MakeGenericMethod(lastMemberAccess.Type);  
  
  
            il.Emit(OpCodes.Ldarg_1); // [target] [DynamicParameters]  
            il.Emit(OpCodes.Ldstr, dynamicParamName); // [target] [DynamicParameters] [ParamName]  
            il.Emit(OpCodes.Callvirt, paramGetter); // [target] [value], it's already typed thanks to generic method  
              
            // GET READY  
            var lastMember = lastMemberAccess.Member;  
            if (lastMember.MemberType == MemberTypes.Property)  
            {  
                var set = ((PropertyInfo)lastMember).GetSetMethod(true);  
                il.Emit(OpCodes.Callvirt, set); // SET  
            }  
            else  
            {  
                il.Emit(OpCodes.Stfld, ((FieldInfo)lastMember)); // SET  
            }  
  
  
            il.Emit(OpCodes.Ret); // GO  
  
  
            setter = (Action<object, DynamicParameters>)dm.CreateDelegate(typeof(Action<object, DynamicParameters>));  
            lock (cache)  
            {  
                cache[lookup] = setter;  
            }  
  
  
            // Queue the preparation to be fired off when adding parameters to the DbCommand  
            MAKECALLBACK:  
            (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 (this.parameters.TryGetValue(dynamicParamName, out parameter))  
                {  
                    parameter.ParameterDirection = parameter.AttachedParam.Direction = ParameterDirection.InputOutput;  
  
  
                    if (parameter.AttachedParam.Size == 0)  
                    {  
                        parameter.Size = parameter.AttachedParam.Size = sizeToSet;  
                    }  
                }  
                else  
                {  
                    SqlMapper.ITypeHandler handler;  
                    dbType = (!dbType.HasValue) ? SqlMapper.LookupDbType(targetMemberType, targetMemberType.Name, true, out handler) : dbType;  
  
  
                    // CameFromTemplate property would not apply here because this new param  
                    // Still needs to be added to the command  
                    this.Add(dynamicParamName, expression.Compile().Invoke(target), null, ParameterDirection.InputOutput, sizeToSet);  
                }  
  
  
                parameter = this.parameters[dynamicParamName];  
                parameter.OutputCallback = setter;  
                parameter.OutputTarget = target;  
            });  
  
  
            return this;  
        }  
  
  
        private List<Action> outputCallbacks;  
  
  
        private readonly Dictionary<string, Action<object, DynamicParameters>> cachedOutputSetters = new Dictionary<string,Action<object,DynamicParameters>>();  
  
  
        internal static class CachedOutputSetters<T>  
        {  
            public static readonly Hashtable Cache = new Hashtable();  
        }  
  
  
        void SqlMapper.IParameterCallbacks.OnCompleted()  
        {  
            foreach (var param in (from p in parameters select p.Value))  
            {  
                if (param.OutputCallback != null) param.OutputCallback(param.OutputTarget, this);  
            }  
        }  
    }  
  
  
    sealed class DataTableHandler : Dapper.SqlMapper.ITypeHandler  
    {  
        public object Parse(Type destinationType, object value)  
        {  
            throw new NotImplementedException();  
        }  
  
  
        public void SetValue(IDbDataParameter parameter, object value)  
        {  
            TableValuedParameter.Set(parameter, value as DataTable, null);  
        }  
    }  
  
  
    /// <summary>  
    /// Used to pass a DataTable as a TableValuedParameter  
    /// </summary>  
    sealed partial class TableValuedParameter : Dapper.SqlMapper.ICustomQueryParameter  
    {  
        private readonly DataTable table;  
        private readonly string typeName;  
  
  
        /// <summary>  
        /// Create a new instance of TableValuedParameter  
        /// </summary>  
        public TableValuedParameter(DataTable table) : this(table, null) { }  
        /// <summary>  
        /// Create a new instance of TableValuedParameter  
        /// </summary>  
        public TableValuedParameter(DataTable table, string typeName)  
        {  
            this.table = table;  
            this.typeName = typeName;  
        }  
        static readonly Action<System.Data.SqlClient.SqlParameter, string> setTypeName;  
        static TableValuedParameter()  
        {  
            var prop = typeof(System.Data.SqlClient.SqlParameter).GetProperty("TypeName", BindingFlags.Instance | BindingFlags.Public);  
            if(prop != null && prop.PropertyType == typeof(string) && prop.CanWrite)  
            {  
                setTypeName = (Action<System.Data.SqlClient.SqlParameter, string>)  
                    Delegate.CreateDelegate(typeof(Action<System.Data.SqlClient.SqlParameter, string>), prop.GetSetMethod());  
            }  
        }  
        void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string name)  
        {  
            var param = command.CreateParameter();  
            param.ParameterName = name;  
            Set(param, table, typeName);  
            command.Parameters.Add(param);  
        }  
        internal static void Set(IDbDataParameter parameter, DataTable table, string typeName)  
        {  
            parameter.Value = (object)table ?? DBNull.Value;  
            if (string.IsNullOrEmpty(typeName) && table != null)  
            {  
                typeName = SqlMapper.GetTypeName(table);  
            }  
            if (!string.IsNullOrEmpty(typeName))  
            {  
                var sqlParam = parameter as System.Data.SqlClient.SqlParameter;  
                if (sqlParam != null)  
                {  
                    if (setTypeName != null) setTypeName(sqlParam, typeName);  
                    sqlParam.SqlDbType = SqlDbType.Structured;  
                }  
            }  
        }  
    }  
    /// <summary>  
    /// This class represents a SQL string, it can be used if you need to denote your parameter is a Char vs VarChar vs nVarChar vs nChar  
    /// </summary>  
    sealed partial class DbString : Dapper.SqlMapper.ICustomQueryParameter  
    {  
        /// <summary>  
        /// A value to set the default value of strings  
        /// going through Dapper. Default is 4000, any value larger than this  
        /// field will not have the default value applied.  
        /// </summary>  
        public const int DefaultLength = 4000;  
  
  
        /// <summary>  
        /// Create a new DbString  
        /// </summary>  
        public DbString() { Length = -1; }  
        /// <summary>  
        /// Ansi vs Unicode   
        /// </summary>  
        public bool IsAnsi { get; set; }  
        /// <summary>  
        /// Fixed length   
        /// </summary>  
        public bool IsFixedLength { get; set; }  
        /// <summary>  
        /// Length of the string -1 for max  
        /// </summary>  
        public int Length { get; set; }  
        /// <summary>  
        /// The value of the string  
        /// </summary>  
        public string Value { get; set; }  
        /// <summary>  
        /// Add the parameter to the command... internal use only  
        /// </summary>  
        /// <param name="command"></param>  
        /// <param name="name"></param>  
        public void AddParameter(IDbCommand command, string name)  
        {  
            if (IsFixedLength && Length == -1)  
            {  
                throw new InvalidOperationException("If specifying IsFixedLength,  a Length must also be specified");  
            }  
            var param = command.CreateParameter();  
            param.ParameterName = name;  
            param.Value = (object)Value ?? DBNull.Value;  
            if (Length == -1 && Value != null && Value.Length <= DefaultLength)  
            {  
                param.Size = DefaultLength;  
            }  
            else  
            {  
                param.Size = Length;  
            }  
            param.DbType = IsAnsi ? (IsFixedLength ? DbType.AnsiStringFixedLength : DbType.AnsiString) : (IsFixedLength ? DbType.StringFixedLength : DbType.String);  
            command.Parameters.Add(param);  
        }  
    }  
  
  
    /// <summary>  
    /// Handles variances in features per DBMS  
    /// </summary>  
    partial class FeatureSupport  
    {  
        private static readonly FeatureSupport  
            @default = new FeatureSupport(false),  
            postgres = new FeatureSupport(true);  
  
  
        /// <summary>  
        /// Gets the feature set based on the passed connection  
        /// </summary>  
        public static FeatureSupport Get(IDbConnection connection)  
        {  
            string name = connection == null ? null : connection.GetType().Name;  
            if (string.Equals(name, "npgsqlconnection", StringComparison.InvariantCultureIgnoreCase)) return postgres;  
            return @default;  
        }  
        private FeatureSupport(bool arrays)  
        {  
            Arrays = arrays;  
        }  
        /// <summary>  
        /// True if the db supports array columns e.g. Postgresql  
        /// </summary>  
        public bool Arrays { get; private set; }  
    }  
  
  
    /// <summary>  
    /// Represents simple member map for one of target parameter or property or field to source DataReader column  
    /// </summary>  
    sealed partial class SimpleMemberMap : SqlMapper.IMemberMap  
    {  
        private readonly string _columnName;  
        private readonly PropertyInfo _property;  
        private readonly FieldInfo _field;  
        private readonly ParameterInfo _parameter;  
  
  
        /// <summary>  
        /// Creates instance for simple property mapping  
        /// </summary>  
        /// <param name="columnName">DataReader column name</param>  
        /// <param name="property">Target property</param>  
        public SimpleMemberMap(string columnName, PropertyInfo property)  
        {  
            if (columnName == null)  
                throw new ArgumentNullException("columnName");  
  
  
            if (property == null)  
                throw new ArgumentNullException("property");  
  
  
            _columnName = columnName;  
            _property = property;  
        }  
  
  
        /// <summary>  
        /// Creates instance for simple field mapping  
        /// </summary>  
        /// <param name="columnName">DataReader column name</param>  
        /// <param name="field">Target property</param>  
        public SimpleMemberMap(string columnName, FieldInfo field)  
        {  
            if (columnName == null)  
                throw new ArgumentNullException("columnName");  
  
  
            if (field == null)  
                throw new ArgumentNullException("field");  
  
  
            _columnName = columnName;  
            _field = field;  
        }  
  
  
        /// <summary>  
        /// Creates instance for simple constructor parameter mapping  
        /// </summary>  
        /// <param name="columnName">DataReader column name</param>  
        /// <param name="parameter">Target constructor parameter</param>  
        public SimpleMemberMap(string columnName, ParameterInfo parameter)  
        {  
            if (columnName == null)  
                throw new ArgumentNullException("columnName");  
  
  
            if (parameter == null)  
                throw new ArgumentNullException("parameter");  
  
  
            _columnName = columnName;  
            _parameter = parameter;  
        }  
  
  
        /// <summary>  
        /// DataReader column name  
        /// </summary>  
        public string ColumnName  
        {  
            get { return _columnName; }  
        }  
  
  
        /// <summary>  
        /// Target member type  
        /// </summary>  
        public Type MemberType  
        {  
            get  
            {  
                if (_field != null)  
                    return _field.FieldType;  
  
  
                if (_property != null)  
                    return _property.PropertyType;  
  
  
                if (_parameter != null)  
                    return _parameter.ParameterType;  
  
  
                return null;  
            }  
        }  
  
  
        /// <summary>  
        /// Target property  
        /// </summary>  
        public PropertyInfo Property  
        {  
            get { return _property; }  
        }  
  
  
        /// <summary>  
        /// Target field  
        /// </summary>  
        public FieldInfo Field  
        {  
            get { return _field; }  
        }  
  
  
        /// <summary>  
        /// Target constructor parameter  
        /// </summary>  
        public ParameterInfo Parameter  
        {  
            get { return _parameter; }  
        }  
    }  
  
  
    /// <summary>  
    /// Represents default type mapping strategy used by Dapper  
    /// </summary>  
    sealed partial class DefaultTypeMap : SqlMapper.ITypeMap  
    {  
        private readonly List<FieldInfo> _fields;  
        private readonly List<PropertyInfo> _properties;  
        private readonly Type _type;  
  
  
        /// <summary>  
        /// Creates default type map  
        /// </summary>  
        /// <param name="type">Entity type</param>  
        public DefaultTypeMap(Type type)  
        {  
            if (type == null)  
                throw new ArgumentNullException("type");  
  
  
            _fields = GetSettableFields(type);  
            _properties = GetSettableProps(type);  
            _type = type;  
        }  
  
  
        internal static MethodInfo GetPropertySetter(PropertyInfo propertyInfo, Type type)  
        {  
            return propertyInfo.DeclaringType == type ?  
                propertyInfo.GetSetMethod(true) :  
                propertyInfo.DeclaringType.GetProperty(  
                   propertyInfo.Name,  
                   BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,  
                   Type.DefaultBinder,  
                   propertyInfo.PropertyType,  
                   propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray(),  
                   null).GetSetMethod(true);  
        }  
  
  
        internal static List<PropertyInfo> GetSettableProps(Type t)  
        {  
            return t  
                  .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)  
                  .Where(p => GetPropertySetter(p, t) != null)  
                  .ToList();  
        }  
  
  
        internal static List<FieldInfo> GetSettableFields(Type t)  
        {  
            return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList();  
        }  
  
  
        /// <summary>  
        /// Finds best constructor  
        /// </summary>  
        /// <param name="names">DataReader column names</param>  
        /// <param name="types">DataReader column types</param>  
        /// <returns>Matching constructor or default one</returns>  
        public ConstructorInfo FindConstructor(string[] names, Type[] types)  
        {  
            var constructors = _type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);  
            foreach (ConstructorInfo ctor in constructors.OrderBy(c => c.IsPublic ? 0 : (c.IsPrivate ? 2 : 1)).ThenBy(c => c.GetParameters().Length))  
            {  
                ParameterInfo[] ctorParameters = ctor.GetParameters();  
                if (ctorParameters.Length == 0)  
                    return ctor;  
  
  
                if (ctorParameters.Length != types.Length)  
                    continue;  
  
  
                int i = 0;  
                for (; i < ctorParameters.Length; i++)  
                {  
                    if (!String.Equals(ctorParameters[i].Name, names[i], StringComparison.OrdinalIgnoreCase))  
                        break;  
                    if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary)  
                        continue;  
                    var unboxedType = Nullable.GetUnderlyingType(ctorParameters[i].ParameterType) ?? ctorParameters[i].ParameterType;  
                    if (unboxedType != types[i]  
                        && !(unboxedType.IsEnum && Enum.GetUnderlyingType(unboxedType) == types[i])  
                        && !(unboxedType == typeof(char) && types[i] == typeof(string)))  
                        break;  
                }  
  
  
                if (i == ctorParameters.Length)  
                    return ctor;  
            }  
  
  
            return null;  
        }  
  
  
        /// <summary>  
        /// Returns the constructor, if any, that has the ExplicitConstructorAttribute on it.  
        /// </summary>  
        public ConstructorInfo FindExplicitConstructor()  
        {  
            var constructors = _type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);  
            var withAttr = constructors.Where(c => c.GetCustomAttributes(typeof(ExplicitConstructorAttribute), true).Length > 0).ToList();  
  
  
            if (withAttr.Count == 1)  
            {  
                return withAttr[0];  
            }  
  
  
            return null;  
        }  
  
  
        /// <summary>  
        /// Gets mapping for constructor parameter  
        /// </summary>  
        /// <param name="constructor">Constructor to resolve</param>  
        /// <param name="columnName">DataReader column name</param>  
        /// <returns>Mapping implementation</returns>  
        public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)  
        {  
            var parameters = constructor.GetParameters();  
  
  
            return new SimpleMemberMap(columnName, parameters.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)));  
        }  
  
  
        /// <summary>  
        /// Gets member mapping for column  
        /// </summary>  
        /// <param name="columnName">DataReader column name</param>  
        /// <returns>Mapping implementation</returns>  
        public SqlMapper.IMemberMap GetMember(string columnName)  
        {  
            var property = _properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))  
               ?? _properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));  
  
  
            if (property == null && MatchNamesWithUnderscores)  
            {  
                property = _properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))  
                    ?? _properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));  
            }  
  
  
            if (property != null)  
                return new SimpleMemberMap(columnName, property);  
  
  
            var field = _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))  
               ?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));  
  
  
            if (field == null && MatchNamesWithUnderscores)  
            {  
                field = _fields.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))  
                    ?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));  
            }  
  
  
            if (field != null)  
                return new SimpleMemberMap(columnName, field);  
  
  
            return null;  
        }  
        /// <summary>  
        /// Should column names like User_Id be allowed to match properties/fields like UserId ?  
        /// </summary>  
        public static bool MatchNamesWithUnderscores { get; set; }  
    }  
  
  
      
  
  
    /// <summary>  
    /// Implements custom property mapping by user provided criteria (usually presence of some custom attribute with column to member mapping)  
    /// </summary>  
    sealed partial class CustomPropertyTypeMap : SqlMapper.ITypeMap  
    {  
        private readonly Type _type;  
        private readonly Func<Type, string, PropertyInfo> _propertySelector;  
  
  
        /// <summary>  
        /// Creates custom property mapping  
        /// </summary>  
        /// <param name="type">Target entity type</param>  
        /// <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("type");  
  
  
            if (propertySelector == null)  
                throw new ArgumentNullException("propertySelector");  
  
  
            _type = type;  
            _propertySelector = propertySelector;  
        }  
  
  
        /// <summary>  
        /// Always returns default constructor  
        /// </summary>  
        /// <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]);  
        }  
  
  
        /// <summary>  
        /// Always returns null  
        /// </summary>  
        /// <returns></returns>  
        public ConstructorInfo FindExplicitConstructor()  
        {  
            return null;  
        }  
  
  
        /// <summary>  
        /// Not implemented as far as default constructor used for all cases  
        /// </summary>  
        /// <param name="constructor"></param>  
        /// <param name="columnName"></param>  
        /// <returns></returns>  
        public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)  
        {  
            throw new NotSupportedException();  
        }  
  
  
        /// <summary>  
        /// Returns property based on selector strategy  
        /// </summary>  
        /// <param name="columnName">DataReader column name</param>  
        /// <returns>Poperty member map</returns>  
        public SqlMapper.IMemberMap GetMember(string columnName)  
        {  
            var prop = _propertySelector(_type, columnName);  
            return prop != null ? new SimpleMemberMap(columnName, prop) : null;  
        }  
    }  
  
  
    internal class WrappedReader : IDataReader, IWrappedDataReader  
    {  
        private IDataReader reader;  
        private IDbCommand cmd;  
  
  
        public IDataReader Reader  
        {  
            get  
            {  
                var tmp = reader;  
                if (tmp == null) throw new ObjectDisposedException(GetType().Name);  
                return tmp;  
            }  
        }  
        IDbCommand IWrappedDataReader.Command  
        {  
            get  
            {  
                var tmp = cmd;  
                if (tmp == null) throw new ObjectDisposedException(GetType().Name);  
                return tmp;  
            }  
        }  
        public WrappedReader(IDbCommand cmd, IDataReader reader)  
        {  
            this.cmd = cmd;  
            this.reader = reader;  
        }  
  
  
        void IDataReader.Close()  
        {  
            if(reader != null) reader.Close();  
        }  
  
  
        int IDataReader.Depth  
        {  
            get { return Reader.Depth; }  
        }  
  
  
        DataTable IDataReader.GetSchemaTable()  
        {  
            return Reader.GetSchemaTable();  
        }  
  
  
        bool IDataReader.IsClosed  
        {  
            get { return reader == null ? true : reader.IsClosed; }  
        }  
  
  
        bool IDataReader.NextResult()  
        {  
            return Reader.NextResult();  
        }  
  
  
        bool IDataReader.Read()  
        {  
            return Reader.Read();  
        }  
  
  
        int IDataReader.RecordsAffected  
        {  
            get { return Reader.RecordsAffected; }  
        }  
  
  
        void IDisposable.Dispose()  
        {  
            if (reader != null) reader.Close();  
            if (reader != null) reader.Dispose();  
            reader = null;  
            if (cmd != null) cmd.Dispose();  
            cmd = null;  
        }  
  
  
        int IDataRecord.FieldCount  
        {  
            get { return Reader.FieldCount; }  
        }  
  
  
        bool IDataRecord.GetBoolean(int i)  
        {  
            return Reader.GetBoolean(i);  
        }  
  
  
        byte IDataRecord.GetByte(int i)  
        {  
            return Reader.GetByte(i);  
        }  
  
  
        long IDataRecord.GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)  
        {  
            return Reader.GetBytes(i, fieldOffset, buffer, bufferoffset, length);  
        }  
  
  
        char IDataRecord.GetChar(int i)  
        {  
            return Reader.GetChar(i);  
        }  
  
  
        long IDataRecord.GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)  
        {  
            return Reader.GetChars(i, fieldoffset, buffer, bufferoffset, length);  
        }  
  
  
        IDataReader IDataRecord.GetData(int i)  
        {  
            return Reader.GetData(i);  
        }  
  
  
        string IDataRecord.GetDataTypeName(int i)  
        {  
            return Reader.GetDataTypeName(i);  
        }  
  
  
        DateTime IDataRecord.GetDateTime(int i)  
        {  
            return Reader.GetDateTime(i);  
        }  
  
  
        decimal IDataRecord.GetDecimal(int i)  
        {  
            return Reader.GetDecimal(i);  
        }  
  
  
        double IDataRecord.GetDouble(int i)  
        {  
            return Reader.GetDouble(i);  
        }  
  
  
        Type IDataRecord.GetFieldType(int i)  
        {  
            return Reader.GetFieldType(i);  
        }  
  
  
        float IDataRecord.GetFloat(int i)  
        {  
            return Reader.GetFloat(i);  
        }  
  
  
        Guid IDataRecord.GetGuid(int i)  
        {  
            return Reader.GetGuid(i);  
        }  
  
  
        short IDataRecord.GetInt16(int i)  
        {  
            return Reader.GetInt16(i);  
        }  
  
  
        int IDataRecord.GetInt32(int i)  
        {  
            return Reader.GetInt32(i);  
        }  
  
  
        long IDataRecord.GetInt64(int i)  
        {  
            return Reader.GetInt64(i);  
        }  
  
  
        string IDataRecord.GetName(int i)  
        {  
            return Reader.GetName(i);  
        }  
  
  
        int IDataRecord.GetOrdinal(string name)  
        {  
            return Reader.GetOrdinal(name);  
        }  
  
  
        string IDataRecord.GetString(int i)  
        {  
            return Reader.GetString(i);  
        }  
  
  
        object IDataRecord.GetValue(int i)  
        {  
            return Reader.GetValue(i);  
        }  
  
  
        int IDataRecord.GetValues(object[] values)  
        {  
            return Reader.GetValues(values);  
        }  
  
  
        bool IDataRecord.IsDBNull(int i)  
        {  
            return Reader.IsDBNull(i);  
        }  
  
  
        object IDataRecord.this[string name]  
        {  
            get { return Reader[name]; }  
        }  
  
  
        object IDataRecord.this[int i]  
        {  
            get { return Reader[i]; }  
        }  
    }  
  
  
    /// <summary>  
    /// Describes a reader that controls the lifetime of both a command and a reader,  
    /// exposing the downstream command/reader as properties.  
    /// </summary>  
    public interface IWrappedDataReader : IDataReader  
    {  
        /// <summary>  
        /// Obtain the underlying reader  
        /// </summary>  
        IDataReader Reader { get; }  
        /// <summary>  
        /// Obtain the underlying command  
        /// </summary>  
        IDbCommand Command { get; }  
    }  
  
  
    /// <summary>  
    /// Tell Dapper to use an explicit constructor, passing nulls or 0s for all parameters  
    /// </summary>  
    [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]  
    public sealed class ExplicitConstructorAttribute : Attribute  
    {  
  
  
    }  
  
  
    // Define DAPPER_MAKE_PRIVATE if you reference Dapper by source  
    // and you like to make the Dapper types private (in order to avoid  
    // conflicts with other projects that also reference Dapper by source)  
#if !DAPPER_MAKE_PRIVATE  
  
  
    public partial class SqlMapper  
    {  
    }  
  
  
    public partial class DynamicParameters  
    {  
  
  
    }  
  
  
    public partial class DbString  
    {  
  
  
    }  
  
  
      
    public partial class SimpleMemberMap  
    {  
  
  
    }  
  
  
    public partial class DefaultTypeMap  
    {  
  
  
    }  
  
  
    public partial class CustomPropertyTypeMap  
    {  
  
  
    }  
  
  
    public partial class FeatureSupport  
    {  
  
  
    }  
 
 
#endif  
  
  
}