Dapper的完整扩展

真心想说:其实。。。我不想用Dapper,如果OrmLite.Net支持参数化的话,也就没Dapper的什么事情了,对于OrmLite.Net只能做后续跟踪......

这个其实是看了Dapper作者的扩展后觉得不爽,然后自己按照他的设计思路重写了代码,只支持单个数据的增删改查,根据Expression来查的真心无能为力......

另外作者似乎已经支持了属性、字段等与数据库中的映射.....

具体包含了

1、对字符串的扩展

2、对主键的定义,支持单或多主键,当单主键并且类型为数字时,认为该主键为自增列

3、对表名的定义

 

实际代码如下:

DapperExtensions部分

[csharp]   view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Data;  
  6. using System.Collections.Concurrent;  
  7. using System.Reflection;  
  8.   
  9. namespace Dapper  
  10. {  
  11.     /// <summary>  
  12.     /// Dapper扩展POCO信息类,为应用此扩展,在原Dapper的第1965行增加了对此类的应用  
  13.     /// </summary>  
  14.     public class DapperPocoInfo  
  15.     {  
  16.         private Type _type;  
  17.         private ConcurrentDictionary<string, KeyValuePair<DbType, int>> _stringColumns  
  18.             = new ConcurrentDictionary<string, KeyValuePair<DbType, int>>();  
  19.         private IEnumerable<PropertyInfo> _typeProperties;  
  20.         private IList<PropertyInfo> _keyProperties = new List<PropertyInfo>();  
  21.         private IEnumerable<PropertyInfo> _defaultKeyPropeties;  
  22.         private string _tableName;  
  23.         /// <summary>  
  24.         /// 对应表名  
  25.         /// </summary>  
  26.         public string TableName  
  27.         {  
  28.             get  
  29.             {  
  30.                 if (string.IsNullOrWhiteSpace(this._tableName))  
  31.                 {  
  32.                     this._tableName = this._type.Name;  
  33.                 }  
  34.                 return this._tableName;  
  35.             }  
  36.             set  
  37.             {  
  38.                 this._tableName = value;  
  39.             }  
  40.         }  
  41.         /// <summary>  
  42.         /// 所有Public的属性集合  
  43.         /// </summary>  
  44.         public IEnumerable<PropertyInfo> TypeProperties  
  45.         {  
  46.             get { return this._typeProperties; }  
  47.         }  
  48.         /// <summary>  
  49.         /// 获取主键集合,如果主键数量大于1,则认为是联合主键,等于0认为不存在主键,等于1并且类型为数字型则认为自增主键  
  50.         /// </summary>  
  51.         /// <returns></returns>  
  52.         public IEnumerable<PropertyInfo> KeyProperties  
  53.         {  
  54.             get  
  55.             {  
  56.                 if (this._keyProperties.Count == 0)  
  57.                 {//如果未设定KeyProperties,则默认认为第一个后缀为ID的PropertyInfo为主键  
  58.                     if (this._defaultKeyPropeties == null)  
  59.                     {  
  60.                         this._defaultKeyPropeties = this._typeProperties.Where(p => p.Name.ToLower().EndsWith("id")).Take(1).ToArray();  
  61.                     }  
  62.                     return this._defaultKeyPropeties;  
  63.                 }  
  64.                 else  
  65.                 {  
  66.                     return this._keyProperties;  
  67.                 }  
  68.             }  
  69.         }  
  70.         /// <summary>  
  71.         /// .oct  
  72.         /// </summary>  
  73.         /// <param name="type"></param>  
  74.         internal DapperPocoInfo(Type type)  
  75.         {  
  76.             if (type == null)  
  77.             {  
  78.                 throw new ArgumentNullException();  
  79.             }  
  80.             this._type = type;  
  81.             this._typeProperties = type.GetProperties();  
  82.         }  
  83.         /// <summary>  
  84.         /// 添加字符串参数化映射  
  85.         /// </summary>  
  86.         /// <param name="propertyName">属性名</param>  
  87.         /// <param name="dbType">必须为AnsiString、AnsiStringFixedLength、String、StringFixedLength</param>  
  88.         /// <param name="len">值范围为1~8000</param>  
  89.         public virtual void AddStringColumnMap(string propertyName, DbType dbType = DbType.AnsiString, int len = 50)  
  90.         {  
  91.             this.GetProperty(propertyName);  
  92.             if (len <= 0 || len > 8000)  
  93.             {//长度范围1~8000,此处暂时对应sql,如果其它关系型数据库长度范围与此不一致,可继承修改  
  94.                 throw new ArgumentException("The param len's value must between 1 and 8000.");  
  95.             }  
  96.             if (dbType != DbType.AnsiString && dbType != DbType.AnsiStringFixedLength && dbType != DbType.String && dbType != DbType.StringFixedLength)  
  97.             {  
  98.                 return;  
  99.             }  
  100.             this._stringColumns.TryAdd(propertyName, new KeyValuePair<DbType, int>(dbType, len));  
  101.         }  
  102.         /// <summary>  
  103.         /// 获取字符串映射  
  104.         /// </summary>  
  105.         /// <param name="propertyName"></param>  
  106.         /// <returns></returns>  
  107.         public KeyValuePair<DbType, int>? GetStringColumnMap(string propertyName)  
  108.         {  
  109.             KeyValuePair<DbType, int> kvp;  
  110.             if (this._stringColumns.TryGetValue(propertyName, out kvp))  
  111.             {  
  112.                 return kvp;  
  113.             }  
  114.             return null;  
  115.         }  
  116.         private PropertyInfo GetProperty(string propertyName)  
  117.         {  
  118.             if (string.IsNullOrWhiteSpace(propertyName))  
  119.             {  
  120.                 throw new ArgumentNullException("propertyName can not be null or empty value");  
  121.             }  
  122.             PropertyInfo pi = this._typeProperties.Where(p => p.Name.ToLower() == propertyName.ToLower()).FirstOrDefault();  
  123.             if (pi == null)  
  124.             {  
  125.                 throw new ArgumentOutOfRangeException(string.Format("The class '{0}' does not contains property '{1}'."this._type.FullName, propertyName));  
  126.             }  
  127.             return pi;  
  128.         }  
  129.         /// <summary>  
  130.         /// 添加主键映射  
  131.         /// </summary>  
  132.         /// <param name="propertyName"></param>  
  133.         public void AddKeyMap(string propertyName)  
  134.         {  
  135.             var pi = this.GetProperty(propertyName);  
  136.             if (this._keyProperties.Where(p => p.Name == pi.Name).FirstOrDefault() == null)  
  137.             {  
  138.                 this._keyProperties.Add(pi);  
  139.                 this._unWriteKey = null;//赋值时取消已经确认的是否可写键值  
  140.             }  
  141.         }  
  142.         /// <summary>  
  143.         /// 不需要插入数据的主键类型,除了Guid,其它均认为自增  
  144.         /// </summary>  
  145.         private static Type[] UnWriteTypes = { typeof(int), typeof(short), typeof(long), typeof(byte), typeof(Guid) };  
  146.         private bool? _unWriteKey;  
  147.         /// <summary>  
  148.         /// 主键是否可写  
  149.         /// </summary>  
  150.         /// <returns></returns>  
  151.         public bool IsUnWriteKey()  
  152.         {  
  153.             if (!this._unWriteKey.HasValue)  
  154.             {  
  155.                 this._unWriteKey = false;  
  156.                 IList<PropertyInfo> keys = this.KeyProperties.ToList();  
  157.                 if (keys.Count == 1)  
  158.                 {  
  159.                     this._unWriteKey = UnWriteTypes.Contains(keys[0].PropertyType);  
  160.                 }  
  161.             }  
  162.             return this._unWriteKey.Value;  
  163.         }  
  164.     }  
  165.     /// <summary>  
  166.     /// Dapper扩展类  
  167.     /// </summary>  
  168.     public static class DapperExtensions  
  169.     {  
  170.         private static ConcurrentDictionary<RuntimeTypeHandle, DapperPocoInfo> PocoInfos  
  171.             = new ConcurrentDictionary<RuntimeTypeHandle, DapperPocoInfo>();  
  172.         /// <summary>  
  173.         /// 已实现的ISqlAdapter集合  
  174.         /// </summary>  
  175.         private static readonly Dictionary<string, ISqlAdapter> AdapterDictionary  
  176.             = new Dictionary<string, ISqlAdapter>() {  
  177.             {"sqlconnection"new MsSqlServerAdapter()}  
  178.             };  
  179.   
  180.         public static DapperPocoInfo GetPocoInfo<T>()  
  181.             where T : class  
  182.         {  
  183.             return GetPocoInfo(typeof(T));  
  184.         }  
  185.         public static DapperPocoInfo GetPocoInfo(this Type type)  
  186.         {  
  187.             DapperPocoInfo pi;  
  188.             RuntimeTypeHandle hd = type.TypeHandle;  
  189.             if (!PocoInfos.TryGetValue(hd, out pi))  
  190.             {  
  191.                 pi = new DapperPocoInfo(type);  
  192.                 PocoInfos[hd] = pi;  
  193.             }  
  194.             return pi;  
  195.         }  
  196.   
  197.         public static ISqlAdapter GetSqlAdapter(this IDbConnection connection)  
  198.         {  
  199.             string name = connection.GetType().Name.ToLower();  
  200.             ISqlAdapter adapter;  
  201.             if (!AdapterDictionary.TryGetValue(name, out adapter))  
  202.             {  
  203.                 throw new NotImplementedException(string.Format("Unknow sql connection '{0}'", name));  
  204.             }  
  205.             return adapter;  
  206.         }  
  207.   
  208.         /// <summary>  
  209.         /// 新增数据,如果T只有一个主键,且新增的主键为数字,则会将新增的主键赋值给entity相应的字段,如果为多主键,或主键不是数字和Guid,则主键需输入  
  210.         /// 如果要进行匿名类型新增,因为匿名类型无法赋值,需调用ISqlAdapter的Insert,由数据库新增的主键需自己写方法查询  
  211.         /// </summary>  
  212.         /// <typeparam name="T"></typeparam>  
  213.         /// <param name="connection"></param>  
  214.         /// <param name="entity"></param>  
  215.         /// <param name="transaction"></param>  
  216.         /// <param name="commandTimeout"></param>  
  217.         /// <returns></returns>  
  218.         public static bool Insert<T>(this IDbConnection connection, T entity, IDbTransaction transaction = nullint? commandTimeout = null)  
  219.             where T : class  
  220.         {  
  221.             ISqlAdapter adapter = GetSqlAdapter(connection);  
  222.             return adapter.Insert<T>(connection, entity, transaction, commandTimeout);  
  223.         }  
  224.         /// <summary>  
  225.         /// 更新数据,如果entity为T,则全字段更新,如果为匿名类型,则修改包含的字段,但匿名类型必须包含主键对应的字段  
  226.         /// </summary>  
  227.         /// <typeparam name="T"></typeparam>  
  228.         /// <param name="connection"></param>  
  229.         /// <param name="entity"></param>  
  230.         /// <param name="transaction"></param>  
  231.         /// <param name="commandTimeout"></param>  
  232.         /// <returns></returns>  
  233.         public static bool Update<T>(this IDbConnection connection, object entity, IDbTransaction transaction = nullint? commandTimeout = null)  
  234.             where T : class  
  235.         {  
  236.             ISqlAdapter adapter = GetSqlAdapter(connection);  
  237.             return adapter.UpdateByKey<T>(connection, entity, transaction, commandTimeout);  
  238.         }  
  239.         /// <summary>  
  240.         /// 删除数据,支持匿名,但匿名类型必须包含主键对应的字段  
  241.         /// </summary>  
  242.         /// <typeparam name="T"></typeparam>  
  243.         /// <param name="connection"></param>  
  244.         /// <param name="param"></param>  
  245.         /// <param name="transaction"></param>  
  246.         /// <param name="commandTimeout"></param>  
  247.         /// <returns></returns>  
  248.         public static bool DeleteByKey<T>(this IDbConnection connection, object param, IDbTransaction transaction = nullint? commandTimeout = null)  
  249.             where T : class  
  250.         {  
  251.             ISqlAdapter adapter = GetSqlAdapter(connection);  
  252.             return adapter.DeleteByKey<T>(connection, param, transaction, commandTimeout);  
  253.         }  
  254.         /// <summary>  
  255.         /// 查询数据,支持匿名,但匿名类型必须包含主键对应的字段  
  256.         /// </summary>  
  257.         /// <typeparam name="T"></typeparam>  
  258.         /// <param name="connection"></param>  
  259.         /// <param name="param"></param>  
  260.         /// <param name="transaction"></param>  
  261.         /// <param name="commandTimeout"></param>  
  262.         /// <returns></returns>  
  263.         public static T QueryByKey<T>(this IDbConnection connection, object param, IDbTransaction transaction = nullint? commandTimeout = null)  
  264.             where T : class  
  265.         {  
  266.             ISqlAdapter adapter = GetSqlAdapter(connection);  
  267.             return adapter.QueryByKey<T>(connection, param, transaction, commandTimeout);  
  268.         }  
  269.         /// <summary>  
  270.         /// 获取最后新增的ID值,仅对Indentity有效  
  271.         /// </summary>  
  272.         /// <typeparam name="T"></typeparam>  
  273.         /// <param name="connection"></param>  
  274.         /// <returns></returns>  
  275.         public static long GetLastInsertIndentityID<T>(this IDbConnection connection)  
  276.             where T : class  
  277.         {  
  278.             ISqlAdapter adapter = GetSqlAdapter(connection);  
  279.             return adapter.GetLastInsertID<T>(connection);  
  280.         }  
  281.     }  
  282.   
  283.     public interface ISqlAdapter  
  284.     {  
  285.         string GetFullQueryByKeySql(Type type);  
  286.         string GetFullInsertSql(Type type);  
  287.         string GetFullUpdateByKeySql(Type type);  
  288.         string GetDeleteByKeySql(Type type);  
  289.         bool Insert<T>(IDbConnection connection, object entity, IDbTransaction transaction, int? commandTimeout)  
  290.             where T : class;  
  291.         bool UpdateByKey<T>(IDbConnection connection, object entity, IDbTransaction transaction, int? commandTimeout)  
  292.             where T : class;  
  293.         bool DeleteByKey<T>(IDbConnection connection, object param, IDbTransaction transaction, int? commandTimeout)  
  294.             where T : class;  
  295.         T QueryByKey<T>(IDbConnection connection, object param, IDbTransaction transaction, int? commandTimeout)  
  296.             where T : class;  
  297.         long GetLastInsertID<T>(IDbConnection connection)  
  298.             where T : class;  
  299.     }  
  300.   
  301.     internal class BasicSql  
  302.     {  
  303.         public string FullQueryByKeySql { getset; }  
  304.         public string FullInsertSql { getset; }  
  305.         public string FullUpdateByKeySql { getset; }  
  306.         public string DeleteByKeySql { getset; }  
  307.     }  
  308.   
  309.     public class MsSqlServerAdapter : ISqlAdapter  
  310.     {  
  311.         private static ConcurrentDictionary<RuntimeTypeHandle, BasicSql> BasicSqls  
  312.             = new ConcurrentDictionary<RuntimeTypeHandle, BasicSql>();  
  313.         private static readonly char SqlParameterChar = '@';  
  314.   
  315.         internal MsSqlServerAdapter() { }  
  316.   
  317.         private string GetParameterName(PropertyInfo pi)  
  318.         {  
  319.             return string.Format("{0}{1}", SqlParameterChar, pi.Name);  
  320.         }  
  321.         private BasicSql GetBasicSql(Type type)  
  322.         {  
  323.             BasicSql basicSql;  
  324.             RuntimeTypeHandle hd = type.TypeHandle;  
  325.             if (!BasicSqls.TryGetValue(hd, out basicSql))  
  326.             {  
  327.                 basicSql = new BasicSql();  
  328.                 BasicSqls[hd] = basicSql;  
  329.             }  
  330.             return basicSql;  
  331.         }  
  332.         private void AppendKeyParameter(StringBuilder tmp, IEnumerable<PropertyInfo> keys)  
  333.         {  
  334.             if (keys.Any())  
  335.             {  
  336.                 tmp.AppendLine(" WHERE");  
  337.                 foreach (PropertyInfo key in keys)  
  338.                 {  
  339.                     tmp.Append(key.Name);  
  340.                     tmp.Append("=");  
  341.                     tmp.Append(this.GetParameterName(key));  
  342.                     tmp.Append(" AND ");  
  343.                 }  
  344.                 tmp.Remove(tmp.Length - 5, 5);  
  345.             }  
  346.         }  
  347.         public string GetFullQueryByKeySql(Type type)  
  348.         {  
  349.             BasicSql basicSql = this.GetBasicSql(type);  
  350.             if (string.IsNullOrEmpty(basicSql.FullQueryByKeySql))  
  351.             {  
  352.                 DapperPocoInfo dpi = type.GetPocoInfo();  
  353.                 StringBuilder tmp = new StringBuilder();  
  354.                 tmp.Append("SELECT * FROM ");  
  355.                 tmp.Append(dpi.TableName);  
  356.                 tmp.Append(" (NOLOCK) ");  
  357.                 this.AppendKeyParameter(tmp, dpi.KeyProperties);  
  358.                 basicSql.FullQueryByKeySql = tmp.ToString();  
  359.             }  
  360.             return basicSql.FullQueryByKeySql;  
  361.         }  
  362.   
  363.         public string GetFullInsertSql(Type type)  
  364.         {  
  365.             BasicSql basicSql = this.GetBasicSql(type);  
  366.             if (string.IsNullOrEmpty(basicSql.FullInsertSql))  
  367.             {  
  368.                 DapperPocoInfo dpi = type.GetPocoInfo();  
  369.                 basicSql.FullInsertSql = this.GetInsertSql(dpi, dpi.TypeProperties);  
  370.             }  
  371.             return basicSql.FullInsertSql;  
  372.         }  
  373.   
  374.         private string GetInsertSql(DapperPocoInfo dpi, IEnumerable<PropertyInfo> props)  
  375.         {  
  376.             StringBuilder tmp = new StringBuilder();  
  377.             tmp.Append("INSERT INTO ");  
  378.             tmp.AppendLine(dpi.TableName);  
  379.             tmp.Append('(');  
  380.   
  381.             IEnumerable<PropertyInfo> valueProps = props;  
  382.             if (dpi.IsUnWriteKey())  
  383.             {  
  384.                 valueProps = this.GetExceptProps(props, dpi.KeyProperties);  
  385.             }  
  386.   
  387.             this.AppendColumnList(tmp, valueProps, '\0');  
  388.             tmp.Append(')');  
  389.             tmp.AppendLine(" VALUES ");  
  390.             tmp.Append('(');  
  391.             this.AppendColumnList(tmp, valueProps, SqlParameterChar);  
  392.             tmp.Append(')');  
  393.   
  394.             return tmp.ToString();  
  395.         }  
  396.         private void AppendColumnList(StringBuilder tmp, IEnumerable<PropertyInfo> valueProps, char addChar)  
  397.         {  
  398.             foreach (PropertyInfo p in valueProps)  
  399.             {  
  400.                 tmp.Append(addChar);  
  401.                 tmp.Append(p.Name);  
  402.                 tmp.Append(',');  
  403.             }  
  404.             tmp.Remove(tmp.Length - 1, 1);  
  405.         }  
  406.         private IEnumerable<PropertyInfo> GetExceptProps(IEnumerable<PropertyInfo> props1, IEnumerable<PropertyInfo> props2)  
  407.         {  
  408.             //return props1.Except(props2, new EqualityCompareProperty()).ToArray();  
  409.             IList<PropertyInfo> list = new List<PropertyInfo>();  
  410.             foreach (PropertyInfo pi in props1)  
  411.             {  
  412.                 string name = pi.Name.ToLower();  
  413.                 if (!props2.Any(p => p.Name.ToLower() == name))  
  414.                 {  
  415.                     list.Add(pi);  
  416.                 }  
  417.             }  
  418.             return list;  
  419.         }  
  420.         private string GetUpdateSql(DapperPocoInfo dpi, IEnumerable<PropertyInfo> props)  
  421.         {  
  422.             StringBuilder tmp = new StringBuilder();  
  423.             tmp.Append("UPDATE ");  
  424.             tmp.AppendLine(dpi.TableName);  
  425.             tmp.Append("SET ");  
  426.             IEnumerable<PropertyInfo> valueProps = this.GetExceptProps(props, dpi.KeyProperties);  
  427.             foreach (PropertyInfo p in valueProps)  
  428.             {  
  429.                 tmp.Append(p.Name);  
  430.                 tmp.Append('=');  
  431.                 tmp.Append(SqlParameterChar);  
  432.                 tmp.Append(p.Name);  
  433.                 tmp.Append(',');  
  434.             }  
  435.             tmp.Remove(tmp.Length - 1, 1);  
  436.             tmp.AppendLine();  
  437.             this.AppendKeyParameter(tmp, dpi.KeyProperties);  
  438.             return tmp.ToString();  
  439.         }  
  440.   
  441.         public string GetFullUpdateByKeySql(Type type)  
  442.         {  
  443.             BasicSql basicSql = this.GetBasicSql(type);  
  444.             if (string.IsNullOrEmpty(basicSql.FullUpdateByKeySql))  
  445.             {  
  446.                 DapperPocoInfo dpi = type.GetPocoInfo();  
  447.                 basicSql.FullUpdateByKeySql = this.GetUpdateSql(dpi, dpi.TypeProperties);  
  448.             }  
  449.             return basicSql.FullUpdateByKeySql;  
  450.         }  
  451.   
  452.         public string GetDeleteByKeySql(Type type)  
  453.         {  
  454.             BasicSql basicSql = this.GetBasicSql(type);  
  455.             if (string.IsNullOrEmpty(basicSql.DeleteByKeySql))  
  456.             {  
  457.                 DapperPocoInfo dpi = type.GetPocoInfo();  
  458.                 StringBuilder tmp = new StringBuilder();  
  459.                 tmp.Append("DELETE FROM ");  
  460.                 tmp.AppendLine(dpi.TableName);  
  461.                 this.AppendKeyParameter(tmp, dpi.KeyProperties);  
  462.                 basicSql.DeleteByKeySql = tmp.ToString();  
  463.             }  
  464.             return basicSql.DeleteByKeySql;  
  465.         }  
  466.   
  467.         public bool Insert<T>(IDbConnection connection, object entity, IDbTransaction transaction = nullint? commandTimeout = null) where T : class  
  468.         {  
  469.             Type type = typeof(T);  
  470.             string insertSql;  
  471.             Type entityType = entity.GetType();  
  472.             DapperPocoInfo dpi = type.GetPocoInfo();  
  473.             if (entityType.IsAssignableFrom(type))  
  474.             {  
  475.                 insertSql = this.GetFullInsertSql(type);  
  476.             }  
  477.             else  
  478.             {  
  479.                 insertSql = this.GetInsertSql(dpi, entityType.GetProperties());  
  480.             }  
  481.   
  482.             if (connection.Execute<T>(insertSql, entity, transaction, commandTimeout) > 0)  
  483.             {  
  484.                 if (entityType.IsAssignableFrom(type) && dpi.IsUnWriteKey())  
  485.                 {  
  486.                     PropertyInfo key = dpi.KeyProperties.First();  
  487.                     if (key.PropertyType != typeof(Guid))  
  488.                     {  
  489.                         var idValue = this.GetLastInsertID(connection, dpi, transaction, commandTimeout);  
  490.                         key.SetValue(entity, idValue, null);  
  491.                     }  
  492.                 }  
  493.                 return true;  
  494.             }  
  495.             return false;  
  496.         }  
  497.   
  498.         public bool UpdateByKey<T>(IDbConnection connection, object entity, IDbTransaction transaction = nullint? commandTimeout = null) where T : class  
  499.         {  
  500.             Type type = typeof(T);  
  501.             string updateSql;  
  502.             Type entityType = entity.GetType();  
  503.             DapperPocoInfo dpi = type.GetPocoInfo();  
  504.             if (entityType.IsAssignableFrom(type))  
  505.             {  
  506.                 updateSql = this.GetFullUpdateByKeySql(type);  
  507.             }  
  508.             else  
  509.             {  
  510.                 updateSql = this.GetUpdateSql(dpi, entityType.GetProperties());  
  511.             }  
  512.             return connection.Execute<T>(updateSql, entity, transaction, commandTimeout) > 0;  
  513.         }  
  514.   
  515.         public bool DeleteByKey<T>(IDbConnection connection, object param, IDbTransaction transaction = nullint? commandTimeout = null) where T : class  
  516.         {  
  517.             string deleteSql = this.GetDeleteByKeySql(typeof(T));  
  518.             return connection.Execute<T>(deleteSql, param, transaction: transaction, commandTimeout: commandTimeout) > 0;  
  519.         }  
  520.   
  521.         public T QueryByKey<T>(IDbConnection connection, object param, IDbTransaction transaction = nullint? commandTimeout = null) where T : class  
  522.         {  
  523.             string querySql = this.GetFullQueryByKeySql(typeof(T));  
  524.             return connection.Query<T>(querySql, param, transaction: transaction, commandTimeout: commandTimeout).FirstOrDefault();  
  525.         }  
  526.   
  527.         private object GetLastInsertID(IDbConnection connection, DapperPocoInfo dpi, IDbTransaction transaction = nullint? commandTimeout = null)  
  528.         {  
  529.             var r = connection.Query("SELECT IDENT_CURRENT('" + dpi.TableName + "') ID", transaction: transaction, commandTimeout: commandTimeout);  
  530.             return Convert.ChangeType(r.First().ID, dpi.KeyProperties.First().PropertyType);  
  531.         }  
  532.   
  533.         public long GetLastInsertID<T>(IDbConnection connection)  
  534.             where T : class  
  535.         {  
  536.             DapperPocoInfo dpi = typeof(T).GetPocoInfo();  
  537.             return Convert.ToInt64(this.GetLastInsertID(connection, dpi));  
  538.         }  
  539.     }  
  540. }  

 

原Dapper部分,在1965行开始做了些修改:

[csharp]   view plain copy
  1. /* 
  2.  License: http://www.apache.org/licenses/LICENSE-2.0  
  3.  Home page: http://code.google.com/p/dapper-dot-net/ 
  4.  
  5.  Note: to build on C# 3.0 + .NET 3.5, include the CSHARP30 compiler symbol (and yes, 
  6.  I know the difference between language and runtime versions; this is a compromise). 
  7.  */  
  8.   
  9. using System;  
  10. using System.Collections;  
  11. using System.Collections.Generic;  
  12. using System.ComponentModel;  
  13. using System.Data;  
  14. using System.Linq;  
  15. using System.Reflection;  
  16. using System.Reflection.Emit;  
  17. using System.Text;  
  18. using System.Threading;  
  19. using System.Text.RegularExpressions;  
  20. using System.Diagnostics;  
  21.   
  22.   
  23. namespace Dapper  
  24. {  
  25.     /// <summary>  
  26.     /// Dapper, a light weight object mapper for ADO.NET  
  27.     /// </summary>  
  28.     static partial class SqlMapper  
  29.     {  
  30.         /// <summary>  
  31.         /// Implement this interface to pass an arbitrary db specific set of parameters to Dapper  
  32.         /// </summary>  
  33.         public partial interface IDynamicParameters  
  34.         {  
  35.             /// <summary>  
  36.             /// Add all the parameters needed to the command just before it executes  
  37.             /// </summary>  
  38.             /// <param name="command">The raw command prior to execution</param>  
  39.             /// <param name="identity">Information about the query</param>  
  40.             void AddParameters(IDbCommand command, Identity identity);  
  41.         }  
  42.   
  43.         /// <summary>  
  44.         /// Implement this interface to pass an arbitrary db specific parameter to Dapper  
  45.         /// </summary>  
  46.         public interface ICustomQueryParameter  
  47.         {  
  48.             /// <summary>  
  49.             /// Add the parameter needed to the command before it executes  
  50.             /// </summary>  
  51.             /// <param name="command">The raw command prior to execution</param>  
  52.             /// <param name="name">Parameter name</param>  
  53.             void AddParameter(IDbCommand command, string name);  
  54.         }  
  55.   
  56.         /// <summary>  
  57.         /// Implement this interface to change default mapping of reader columns to type memebers  
  58.         /// </summary>  
  59.         public interface ITypeMap  
  60.         {  
  61.             /// <summary>  
  62.             /// Finds best constructor  
  63.             /// </summary>  
  64.             /// <param name="names">DataReader column names</param>  
  65.             /// <param name="types">DataReader column types</param>  
  66.             /// <returns>Matching constructor or default one</returns>  
  67.             ConstructorInfo FindConstructor(string[] names, Type[] types);  
  68.   
  69.             /// <summary>  
  70.             /// Gets mapping for constructor parameter  
  71.             /// </summary>  
  72.             /// <param name="constructor">Constructor to resolve</param>  
  73.             /// <param name="columnName">DataReader column name</param>  
  74.             /// <returns>Mapping implementation</returns>  
  75.             IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName);  
  76.   
  77.             /// <summary>  
  78.             /// Gets member mapping for column  
  79.             /// </summary>  
  80.             /// <param name="columnName">DataReader column name</param>  
  81.             /// <returns>Mapping implementation</returns>  
  82.             IMemberMap GetMember(string columnName);  
  83.         }  
  84.   
  85.         /// <summary>  
  86.         /// Implements this interface to provide custom member mapping  
  87.         /// </summary>  
  88.         public interface IMemberMap  
  89.         {  
  90.             /// <summary>  
  91.             /// Source DataReader column name  
  92.             /// </summary>  
  93.             string ColumnName { get; }  
  94.   
  95.             /// <summary>  
  96.             ///  Target member type  
  97.             /// </summary>  
  98.             Type MemberType { get; }  
  99.   
  100.             /// <summary>  
  101.             /// Target property  
  102.             /// </summary>  
  103.             PropertyInfo Property { get; }  
  104.   
  105.             /// <summary>  
  106.             /// Target field  
  107.             /// </summary>  
  108.             FieldInfo Field { get; }  
  109.   
  110.             /// <summary>  
  111.             /// Target constructor parameter  
  112.             /// </summary>  
  113.             ParameterInfo Parameter { get; }  
  114.         }  
  115.   
  116.         static Link<Type, Action<IDbCommand, bool>> bindByNameCache;  
  117.         static Action<IDbCommand, bool> GetBindByName(Type commandType)  
  118.         {  
  119.             if (commandType == nullreturn null// GIGO  
  120.             Action<IDbCommand, bool> action;  
  121.             if (Link<Type, Action<IDbCommand, bool>>.TryGet(bindByNameCache, commandType, out action))  
  122.             {  
  123.                 return action;  
  124.             }  
  125.             var prop = commandType.GetProperty("BindByName", BindingFlags.Public | BindingFlags.Instance);  
  126.             action = null;  
  127.             ParameterInfo[] indexers;  
  128.             MethodInfo setter;  
  129.             if (prop != null && prop.CanWrite && prop.PropertyType == typeof(bool)  
  130.                 && ((indexers = prop.GetIndexParameters()) == null || indexers.Length == 0)  
  131.                 && (setter = prop.GetSetMethod()) != null  
  132.                 )  
  133.             {  
  134.                 var method = new DynamicMethod(commandType.Name + "_BindByName"nullnew Type[] { typeof(IDbCommand), typeof(bool) });  
  135.                 var il = method.GetILGenerator();  
  136.                 il.Emit(OpCodes.Ldarg_0);  
  137.                 il.Emit(OpCodes.Castclass, commandType);  
  138.                 il.Emit(OpCodes.Ldarg_1);  
  139.                 il.EmitCall(OpCodes.Callvirt, setter, null);  
  140.                 il.Emit(OpCodes.Ret);  
  141.                 action = (Action<IDbCommand, bool>)method.CreateDelegate(typeof(Action<IDbCommand, bool>));  
  142.             }  
  143.             // cache it              
  144.             Link<Type, Action<IDbCommand, bool>>.TryAdd(ref bindByNameCache, commandType, ref action);  
  145.             return action;  
  146.         }  
  147.         /// <summary>  
  148.         /// This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example),  
  149.         /// and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE**  
  150.         /// equality. The type is fully thread-safe.  
  151.         /// </summary>  
  152.         partial class Link<TKey, TValue> where TKey : class  
  153.         {  
  154.             public static bool TryGet(Link<TKey, TValue> link, TKey key, out TValue value)  
  155.             {  
  156.                 while (link != null)  
  157.                 {  
  158.                     if ((object)key == (object)link.Key)  
  159.                     {  
  160.                         value = link.Value;  
  161.                         return true;  
  162.                     }  
  163.                     link = link.Tail;  
  164.                 }  
  165.                 value = default(TValue);  
  166.                 return false;  
  167.             }  
  168.             public static bool TryAdd(ref Link<TKey, TValue> head, TKey key, ref TValue value)  
  169.             {  
  170.                 bool tryAgain;  
  171.                 do  
  172.                 {  
  173.                     var snapshot = Interlocked.CompareExchange(ref head, nullnull);  
  174.                     TValue found;  
  175.                     if (TryGet(snapshot, key, out found))  
  176.                     { // existing match; report the existing value instead  
  177.                         value = found;  
  178.                         return false;  
  179.                     }  
  180.                     var newNode = new Link<TKey, TValue>(key, value, snapshot);  
  181.                     // did somebody move our cheese?  
  182.                     tryAgain = Interlocked.CompareExchange(ref head, newNode, snapshot) != snapshot;  
  183.                 } while (tryAgain);  
  184.                 return true;  
  185.             }  
  186.             private Link(TKey key, TValue value, Link<TKey, TValue> tail)  
  187.             {  
  188.                 Key = key;  
  189.                 Value = value;  
  190.                 Tail = tail;  
  191.             }  
  192.             public TKey Key { getprivate set; }  
  193.             public TValue Value { getprivate set; }  
  194.             public Link<TKey, TValue> Tail { getprivate set; }  
  195.         }  
  196.         partial class CacheInfo  
  197.         {  
  198.             public DeserializerState Deserializer { getset; }  
  199.             public Func<IDataReader, object>[] OtherDeserializers { getset; }  
  200.             public Action<IDbCommand, object> ParamReader { getset; }  
  201.             private int hitCount;  
  202.             public int GetHitCount() { return Interlocked.CompareExchange(ref hitCount, 0, 0); }  
  203.             public void RecordHit() { Interlocked.Increment(ref hitCount); }  
  204.         }  
  205.         static int GetColumnHash(IDataReader reader)  
  206.         {  
  207.             unchecked  
  208.             {  
  209.                 int colCount = reader.FieldCount, hash = colCount;  
  210.                 for (int i = 0; i < colCount; i++)  
  211.                 {   // binding code is only interested in names - not types  
  212.                     object tmp = reader.GetName(i);  
  213.                     hash = (hash * 31) + (tmp == null ? 0 : tmp.GetHashCode());  
  214.                 }  
  215.                 return hash;  
  216.             }  
  217.         }  
  218.         struct DeserializerState  
  219.         {  
  220.             public readonly int Hash;  
  221.             public readonly Func<IDataReader, object> Func;  
  222.   
  223.             public DeserializerState(int hash, Func<IDataReader, object> func)  
  224.             {  
  225.                 Hash = hash;  
  226.                 Func = func;  
  227.             }  
  228.         }  
  229.   
  230.         /// <summary>  
  231.         /// Called if the query cache is purged via PurgeQueryCache  
  232.         /// </summary>  
  233.         public static event EventHandler QueryCachePurged;  
  234.         private static void OnQueryCachePurged()  
  235.         {  
  236.             var handler = QueryCachePurged;  
  237.             if (handler != null) handler(null, EventArgs.Empty);  
  238.         }  
  239. #if CSHARP30  
  240.         private static readonly Dictionary<Identity, CacheInfo> _queryCache = new Dictionary<Identity, CacheInfo>();  
  241.         // note: conflicts between readers and writers are so short-lived that it isn't worth the overhead of  
  242.         // ReaderWriterLockSlim etc; a simple lock is faster  
  243.         private static void SetQueryCache(Identity key, CacheInfo value)  
  244.         {  
  245.             lock (_queryCache) { _queryCache[key] = value; }  
  246.         }  
  247.         private static bool TryGetQueryCache(Identity key, out CacheInfo value)  
  248.         {  
  249.             lock (_queryCache) { return _queryCache.TryGetValue(key, out value); }  
  250.         }  
  251.         private static void PurgeQueryCacheByType(Type type)  
  252.         {  
  253.             lock (_queryCache)  
  254.             {  
  255.                 var toRemove = _queryCache.Keys.Where(id => id.type == type).ToArray();  
  256.                 foreach (var key in toRemove)  
  257.                     _queryCache.Remove(key);  
  258.             }  
  259.         }  
  260.         /// <summary>  
  261.         /// Purge the query cache   
  262.         /// </summary>  
  263.         public static void PurgeQueryCache()  
  264.         {  
  265.             lock (_queryCache)  
  266.             {  
  267.                 _queryCache.Clear();  
  268.             }  
  269.             OnQueryCachePurged();  
  270.         }  
  271. #else  
  272.         static readonly System.Collections.Concurrent.ConcurrentDictionary<Identity, CacheInfo> _queryCache = new System.Collections.Concurrent.ConcurrentDictionary<Identity, CacheInfo>();  
  273.         private static void SetQueryCache(Identity key, CacheInfo value)  
  274.         {  
  275.             if (Interlocked.Increment(ref collect) == COLLECT_PER_ITEMS)  
  276.             {  
  277.                 CollectCacheGarbage();  
  278.             }  
  279.             _queryCache[key] = value;  
  280.         }  
  281.   
  282.         private static void CollectCacheGarbage()  
  283.         {  
  284.             try  
  285.             {  
  286.                 foreach (var pair in _queryCache)  
  287.                 {  
  288.                     if (pair.Value.GetHitCount() <= COLLECT_HIT_COUNT_MIN)  
  289.                     {  
  290.                         CacheInfo cache;  
  291.                         _queryCache.TryRemove(pair.Key, out cache);  
  292.                     }  
  293.                 }  
  294.             }  
  295.   
  296.             finally  
  297.             {  
  298.                 Interlocked.Exchange(ref collect, 0);  
  299.             }  
  300.         }  
  301.   
  302.         private const int COLLECT_PER_ITEMS = 1000, COLLECT_HIT_COUNT_MIN = 0;  
  303.         private static int collect;  
  304.         private static bool TryGetQueryCache(Identity key, out CacheInfo value)  
  305.         {  
  306.             if (_queryCache.TryGetValue(key, out value))  
  307.             {  
  308.                 value.RecordHit();  
  309.                 return true;  
  310.             }  
  311.             value = null;  
  312.             return false;  
  313.         }  
  314.   
  315.         /// <summary>  
  316.         /// Purge the query cache   
  317.         /// </summary>  
  318.         public static void PurgeQueryCache()  
  319.         {  
  320.             _queryCache.Clear();  
  321.             OnQueryCachePurged();  
  322.         }  
  323.   
  324.         private static void PurgeQueryCacheByType(Type type)  
  325.         {  
  326.             foreach (var entry in _queryCache)  
  327.             {  
  328.                 CacheInfo cache;  
  329.                 if (entry.Key.type == type)  
  330.                     _queryCache.TryRemove(entry.Key, out cache);  
  331.             }  
  332.         }  
  333.   
  334.         /// <summary>  
  335.         /// Return a count of all the cached queries by dapper  
  336.         /// </summary>  
  337.         /// <returns></returns>  
  338.         public static int GetCachedSQLCount()  
  339.         {  
  340.             return _queryCache.Count;  
  341.         }  
  342.   
  343.         /// <summary>  
  344.         /// Return a list of all the queries cached by dapper  
  345.         /// </summary>  
  346.         /// <param name="ignoreHitCountAbove"></param>  
  347.         /// <returns></returns>  
  348.         public static IEnumerable<Tuple<stringstringint>> GetCachedSQL(int ignoreHitCountAbove = int.MaxValue)  
  349.         {  
  350.             var data = _queryCache.Select(pair => Tuple.Create(pair.Key.connectionString, pair.Key.sql, pair.Value.GetHitCount()));  
  351.             if (ignoreHitCountAbove < int.MaxValue) data = data.Where(tuple => tuple.Item3 <= ignoreHitCountAbove);  
  352.             return data;  
  353.         }  
  354.   
  355.         /// <summary>  
  356.         /// Deep diagnostics only: find any hash collisions in the cache  
  357.         /// </summary>  
  358.         /// <returns></returns>  
  359.         public static IEnumerable<Tuple<intint>> GetHashCollissions()  
  360.         {  
  361.             var counts = new Dictionary<intint>();  
  362.             foreach (var key in _queryCache.Keys)  
  363.             {  
  364.                 int count;  
  365.                 if (!counts.TryGetValue(key.hashCode, out count))  
  366.                 {  
  367.                     counts.Add(key.hashCode, 1);  
  368.                 }  
  369.                 else  
  370.                 {  
  371.                     counts[key.hashCode] = count + 1;  
  372.                 }  
  373.             }  
  374.             return from pair in counts  
  375.                    where pair.Value > 1  
  376.                    select Tuple.Create(pair.Key, pair.Value);  
  377.   
  378.         }  
  379. #endif  
  380.   
  381.   
  382.         static readonly Dictionary<Type, DbType> typeMap;  
  383.   
  384.         static SqlMapper()  
  385.         {  
  386.             typeMap = new Dictionary<Type, DbType>();  
  387.             typeMap[typeof(byte)] = DbType.Byte;  
  388.             typeMap[typeof(sbyte)] = DbType.SByte;  
  389.             typeMap[typeof(short)] = DbType.Int16;  
  390.             typeMap[typeof(ushort)] = DbType.UInt16;  
  391.             typeMap[typeof(int)] = DbType.Int32;  
  392.             typeMap[typeof(uint)] = DbType.UInt32;  
  393.             typeMap[typeof(long)] = DbType.Int64;  
  394.             typeMap[typeof(ulong)] = DbType.UInt64;  
  395.             typeMap[typeof(float)] = DbType.Single;  
  396.             typeMap[typeof(double)] = DbType.Double;  
  397.             typeMap[typeof(decimal)] = DbType.Decimal;  
  398.             typeMap[typeof(bool)] = DbType.Boolean;  
  399.             typeMap[typeof(string)] = DbType.String;  
  400.             typeMap[typeof(char)] = DbType.StringFixedLength;  
  401.             typeMap[typeof(Guid)] = DbType.Guid;  
  402.             typeMap[typeof(DateTime)] = DbType.DateTime;  
  403.             typeMap[typeof(DateTimeOffset)] = DbType.DateTimeOffset;  
  404.             typeMap[typeof(TimeSpan)] = DbType.Time;  
  405.             typeMap[typeof(byte[])] = DbType.Binary;  
  406.             typeMap[typeof(byte?)] = DbType.Byte;  
  407.             typeMap[typeof(sbyte?)] = DbType.SByte;  
  408.             typeMap[typeof(short?)] = DbType.Int16;  
  409.             typeMap[typeof(ushort?)] = DbType.UInt16;  
  410.             typeMap[typeof(int?)] = DbType.Int32;  
  411.             typeMap[typeof(uint?)] = DbType.UInt32;  
  412.             typeMap[typeof(long?)] = DbType.Int64;  
  413.             typeMap[typeof(ulong?)] = DbType.UInt64;  
  414.             typeMap[typeof(float?)] = DbType.Single;  
  415.             typeMap[typeof(double?)] = DbType.Double;  
  416.             typeMap[typeof(decimal?)] = DbType.Decimal;  
  417.             typeMap[typeof(bool?)] = DbType.Boolean;  
  418.             typeMap[typeof(char?)] = DbType.StringFixedLength;  
  419.             typeMap[typeof(Guid?)] = DbType.Guid;  
  420.             typeMap[typeof(DateTime?)] = DbType.DateTime;  
  421.             typeMap[typeof(DateTimeOffset?)] = DbType.DateTimeOffset;  
  422.             typeMap[typeof(TimeSpan?)] = DbType.Time;  
  423.             typeMap[typeof(Object)] = DbType.Object;  
  424.         }  
  425.         /// <summary>  
  426.         /// Configire the specified type to be mapped to a given db-type  
  427.         /// </summary>  
  428.         public static void AddTypeMap(Type type, DbType dbType)  
  429.         {  
  430.             typeMap[type] = dbType;  
  431.         }  
  432.   
  433.         internal const string LinqBinary = "System.Data.Linq.Binary";  
  434.         internal static DbType LookupDbType(Type type, string name)  
  435.         {  
  436.             DbType dbType;  
  437.             var nullUnderlyingType = Nullable.GetUnderlyingType(type);  
  438.             if (nullUnderlyingType != null) type = nullUnderlyingType;  
  439.             if (type.IsEnum && !typeMap.ContainsKey(type))  
  440.             {  
  441.                 type = Enum.GetUnderlyingType(type);  
  442.             }  
  443.             if (typeMap.TryGetValue(type, out dbType))  
  444.             {  
  445.                 return dbType;  
  446.             }  
  447.             if (type.FullName == LinqBinary)  
  448.             {  
  449.                 return DbType.Binary;  
  450.             }  
  451.             if (typeof(IEnumerable).IsAssignableFrom(type))  
  452.             {  
  453.                 return DynamicParameters.EnumerableMultiParameter;  
  454.             }  
  455.   
  456.   
  457.             throw new NotSupportedException(string.Format("The member {0} of type {1} cannot be used as a parameter value", name, type));  
  458.         }  
  459.   
  460.   
  461.         /// <summary>  
  462.         /// Identity of a cached query in Dapper, used for extensability  
  463.         /// </summary>  
  464.         public partial class Identity : IEquatable<Identity>  
  465.         {  
  466.             internal Identity ForGrid(Type primaryType, int gridIndex)  
  467.             {  
  468.                 return new Identity(sql, commandType, connectionString, primaryType, parametersType, null, gridIndex);  
  469.             }  
  470.   
  471.             internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex)  
  472.             {  
  473.                 return new Identity(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex);  
  474.             }  
  475.             /// <summary>  
  476.             /// Create an identity for use with DynamicParameters, internal use only  
  477.             /// </summary>  
  478.             /// <param name="type"></param>  
  479.             /// <returns></returns>  
  480.             public Identity ForDynamicParameters(Type type)  
  481.             {  
  482.                 return new Identity(sql, commandType, connectionString, this.type, type, null, -1);  
  483.             }  
  484.   
  485.             internal Identity(string sql, CommandType? commandType, IDbConnection connection, Type type, Type parametersType, Type[] otherTypes)  
  486.                 : this(sql, commandType, connection.ConnectionString, type, parametersType, otherTypes, 0)  
  487.             { }  
  488.             private Identity(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, Type[] otherTypes, int gridIndex)  
  489.             {  
  490.                 this.sql = sql;  
  491.                 this.commandType = commandType;  
  492.                 this.connectionString = connectionString;  
  493.                 this.type = type;  
  494.                 this.parametersType = parametersType;  
  495.                 this.gridIndex = gridIndex;  
  496.                 unchecked  
  497.                 {  
  498.                     hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this  
  499.                     hashCode = hashCode * 23 + commandType.GetHashCode();  
  500.                     hashCode = hashCode * 23 + gridIndex.GetHashCode();  
  501.                     hashCode = hashCode * 23 + (sql == null ? 0 : sql.GetHashCode());  
  502.                     hashCode = hashCode * 23 + (type == null ? 0 : type.GetHashCode());  
  503.                     if (otherTypes != null)  
  504.                     {  
  505.                         foreach (var t in otherTypes)  
  506.                         {  
  507.                             hashCode = hashCode * 23 + (t == null ? 0 : t.GetHashCode());  
  508.                         }  
  509.                     }  
  510.                     hashCode = hashCode * 23 + (connectionString == null ? 0 : SqlMapper.connectionStringComparer.GetHashCode(connectionString));  
  511.                     hashCode = hashCode * 23 + (parametersType == null ? 0 : parametersType.GetHashCode());  
  512.                 }  
  513.             }  
  514.   
  515.             /// <summary>  
  516.             ///   
  517.             /// </summary>  
  518.             /// <param name="obj"></param>  
  519.             /// <returns></returns>  
  520.             public override bool Equals(object obj)  
  521.             {  
  522.                 return Equals(obj as Identity);  
  523.             }  
  524.             /// <summary>  
  525.             /// The sql  
  526.             /// </summary>  
  527.             public readonly string sql;  
  528.             /// <summary>  
  529.             /// The command type   
  530.             /// </summary>  
  531.             public readonly CommandType? commandType;  
  532.   
  533.             /// <summary>  
  534.             ///   
  535.             /// </summary>  
  536.             public readonly int hashCode, gridIndex;  
  537.             /// <summary>  
  538.             ///   
  539.             /// </summary>  
  540.             public readonly Type type;  
  541.             /// <summary>  
  542.             ///   
  543.             /// </summary>  
  544.             public readonly string connectionString;  
  545.             /// <summary>  
  546.             ///   
  547.             /// </summary>  
  548.             public readonly Type parametersType;  
  549.             /// <summary>  
  550.             ///   
  551.             /// </summary>  
  552.             /// <returns></returns>  
  553.             public override int GetHashCode()  
  554.             {  
  555.                 return hashCode;  
  556.             }  
  557.             /// <summary>  
  558.             /// Compare 2 Identity objects  
  559.             /// </summary>  
  560.             /// <param name="other"></param>  
  561.             /// <returns></returns>  
  562.             public bool Equals(Identity other)  
  563.             {  
  564.                 return  
  565.                     other != null &&  
  566.                     gridIndex == other.gridIndex &&  
  567.                     type == other.type &&  
  568.                     sql == other.sql &&  
  569.                     commandType == other.commandType &&  
  570.                     SqlMapper.connectionStringComparer.Equals(connectionString, other.connectionString) &&  
  571.                     parametersType == other.parametersType;  
  572.             }  
  573.         }  
  574.  
  575. #if CSHARP30  
  576.         /// <summary>  
  577.         /// Execute parameterized SQL    
  578.         /// </summary>  
  579.         /// <returns>Number of rows affected</returns>  
  580.         public static int Execute(this IDbConnection cnn, string sql, object param)  
  581.         {  
  582.             return Execute(cnn, sql, param, nullnullnull);  
  583.         }  
  584.   
  585.         /// <summary>  
  586.         /// Execute parameterized SQL  
  587.         /// </summary>  
  588.         /// <returns>Number of rows affected</returns>  
  589.         public static int Execute(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)  
  590.         {  
  591.             return Execute(cnn, sql, param, transaction, nullnull);  
  592.         }  
  593.   
  594.         /// <summary>  
  595.         /// Execute parameterized SQL  
  596.         /// </summary>  
  597.         /// <returns>Number of rows affected</returns>  
  598.         public static int Execute(this IDbConnection cnn, string sql, object param, CommandType commandType)  
  599.         {  
  600.             return Execute(cnn, sql, param, nullnull, commandType);  
  601.         }  
  602.   
  603.         /// <summary>  
  604.         /// Execute parameterized SQL  
  605.         /// </summary>  
  606.         /// <returns>Number of rows affected</returns>  
  607.         public static int Execute(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType commandType)  
  608.         {  
  609.             return Execute(cnn, sql, param, transaction, null, commandType);  
  610.         }  
  611.   
  612.         /// <summary>  
  613.         /// Executes a query, returning the data typed as per T  
  614.         /// </summary>  
  615.         /// <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  
  616.         /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
  617.         /// </returns>  
  618.         public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param)  
  619.         {  
  620.             return Query<T>(cnn, sql, param, nulltruenullnull);  
  621.         }  
  622.   
  623.         /// <summary>  
  624.         /// Executes a query, returning the data typed as per T  
  625.         /// </summary>  
  626.         /// <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  
  627.         /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
  628.         /// </returns>  
  629.         public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)  
  630.         {  
  631.             return Query<T>(cnn, sql, param, transaction, truenullnull);  
  632.         }  
  633.   
  634.         /// <summary>  
  635.         /// Executes a query, returning the data typed as per T  
  636.         /// </summary>  
  637.         /// <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  
  638.         /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
  639.         /// </returns>  
  640.         public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param, CommandType commandType)  
  641.         {  
  642.             return Query<T>(cnn, sql, param, nulltruenull, commandType);  
  643.         }  
  644.   
  645.         /// <summary>  
  646.         /// Executes a query, returning the data typed as per T  
  647.         /// </summary>  
  648.         /// <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  
  649.         /// created per row, and a direct column-name===member-name mapping is assumed (case insensitive).  
  650.         /// </returns>  
  651.         public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType commandType)  
  652.         {  
  653.             return Query<T>(cnn, sql, param, transaction, truenull, commandType);  
  654.         }  
  655.   
  656.         /// <summary>  
  657.         /// Execute a command that returns multiple result sets, and access each in turn  
  658.         /// </summary>  
  659.         public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)  
  660.         {  
  661.             return QueryMultiple(cnn, sql, param, transaction, nullnull);  
  662.         }  
  663.   
  664.         /// <summary>  
  665.         /// Execute a command that returns multiple result sets, and access each in turn  
  666.         /// </summary>  
  667.         public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, CommandType commandType)  
  668.         {  
  669.             return QueryMultiple(cnn, sql, param, nullnull, commandType);  
  670.         }  
  671.   
  672.         /// <summary>  
  673.         /// Execute a command that returns multiple result sets, and access each in turn  
  674.         /// </summary>  
  675.         public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType commandType)  
  676.         {  
  677.             return QueryMultiple(cnn, sql, param, transaction, null, commandType);  
  678.         }  
  679. #endif  
  680.   
  681.         private static int Execute(  
  682. #if CSHARP30  
  683. this IDbConnection cnn, string sql,Type type, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType  
  684. #else  
  685. this IDbConnection cnn, string sql, Type type, dynamic param = null, IDbTransaction transaction = nullint? commandTimeout = null, CommandType? commandType = null  
  686. #endif  
  687. )  
  688.         {  
  689.             IEnumerable multiExec = (object)param as IEnumerable;  
  690.             Identity identity;  
  691.             CacheInfo info = null;  
  692.             if (multiExec != null && !(multiExec is string))  
  693.             {  
  694.                 bool isFirst = true;  
  695.                 int total = 0;  
  696.                 using (var cmd = SetupCommand(cnn, transaction, sql, nullnull, commandTimeout, commandType))  
  697.                 {  
  698.   
  699.                     string masterSql = null;  
  700.                     foreach (var obj in multiExec)  
  701.                     {  
  702.                         if (isFirst)  
  703.                         {  
  704.                             masterSql = cmd.CommandText;  
  705.                             isFirst = false;  
  706.                             identity = new Identity(sql, cmd.CommandType, cnn, type, obj.GetType(), null);  
  707.                             info = GetCacheInfo(identity);  
  708.                         }  
  709.                         else  
  710.                         {  
  711.                             cmd.CommandText = masterSql; // because we do magic replaces on "in" etc  
  712.                             cmd.Parameters.Clear(); // current code is Add-tastic  
  713.                         }  
  714.                         info.ParamReader(cmd, obj);  
  715.                         total += cmd.ExecuteNonQuery();  
  716.                     }  
  717.                 }  
  718.                 return total;  
  719.             }  
  720.   
  721.             // nice and simple  
  722.             if ((object)param != null)  
  723.             {  
  724.                 identity = new Identity(sql, commandType, cnn, type, (object)param == null ? null : ((object)param).GetType(), null);  
  725.                 info = GetCacheInfo(identity);  
  726.             }  
  727.             return ExecuteCommand(cnn, transaction, sql, (object)param == null ? null : info.ParamReader, (object)param, commandTimeout, commandType);  
  728.         }  
  729.   
  730.         /// <summary>  
  731.         /// Execute parameterized SQL    
  732.         /// </summary>  
  733.         /// <returns>Number of rows affected</returns>  
  734.         public static int Execute<T>(  
  735. #if CSHARP30  
  736. this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType  
  737. #else  
  738. this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = nullint? commandTimeout = null, CommandType? commandType = null  
  739. #endif  
  740. )  
  741.             where T : class  
  742.         {  
  743.             return Execute(cnn, sql, typeof(T), param, transaction, commandTimeout, commandType);  
  744.         }  
  745.         /// <summary>  
  746.         /// Execute parameterized SQL    
  747.         /// </summary>  
  748.         /// <returns>Number of rows affected</returns>  
  749.         public static int Execute(  
  750. #if CSHARP30  
  751. this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType  
  752. #else  
  753. this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = nullint? commandTimeout = null, CommandType? commandType = null  
  754. #endif  
  755. )  
  756.         {  
  757.             return Execute(cnn, sql, null, param, transaction, commandTimeout, commandType);  
  758.         }  
  759.  
  760. #if !CSHARP30  
  761.         /// <summary>  
  762.         /// Return a list of dynamic objects, reader is closed after the call  
  763.         /// </summary>  
  764.         public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = nullbool buffered = trueint? commandTimeout = null, CommandType? commandType = null)  
  765.         {  
  766.             return Query<DapperRow>(cnn, sql, param as object, transaction, buffered, commandTimeout, commandType);  
  767.         }  
  768. #else  
  769.         /// <summary>  
  770.         /// Return a list of dynamic objects, reader is closed after the call  
  771.         /// </summary>  
  772.         public static IEnumerable<IDictionary<stringobject>> Query(this IDbConnection cnn, string sql, object param)  
  773.         {  
  774.             return Query(cnn, sql, param, nulltruenullnull);  
  775.         }  
  776.   
  777.         /// <summary>  
  778.         /// Return a list of dynamic objects, reader is closed after the call  

你可能感兴趣的:(APP)