在通过ADO.NET与SQL进行数据交互时,为了防止SQL注入,一般采用参数化的方式,而SqlParameter对应的构造函数如下
// 摘要:
// 初始化 System.Data.SqlClient.SqlParameter 类的新实例。
public SqlParameter();
//
// 摘要:
// 用参数名称和新 System.Data.SqlClient.SqlParameter 的一个值初始化 System.Data.SqlClient.SqlParameter
// 类的新实例。
//
// 参数:
// parameterName:
// 要映射的参数的名称。
//
// value:
// 一个 System.Object,它是 System.Data.SqlClient.SqlParameter 的值。
public SqlParameter(string parameterName, object value);
//
// 摘要:
// 用参数名称和数据类型初始化 System.Data.SqlClient.SqlParameter 类的新实例。
//
// 参数:
// parameterName:
// 要映射的参数的名称。
//
// dbType:
// System.Data.SqlDbType 值之一。
//
// 异常:
// System.ArgumentException:
// dbType 参数中提供的值为无效的后端数据类型。
public SqlParameter(string parameterName, SqlDbType dbType);
//
// 摘要:
// 用参数名称、System.Data.SqlDbType 和大小初始化 System.Data.SqlClient.SqlParameter 类的新实例。
//
// 参数:
// parameterName:
// 要映射的参数的名称。
//
// dbType:
// System.Data.SqlDbType 值之一。
//
// size:
// 参数的长度。
//
// 异常:
// System.ArgumentException:
// dbType 参数中提供的值为无效的后端数据类型。
public SqlParameter(string parameterName, SqlDbType dbType, int size);
//
// 摘要:
// 用参数名称、System.Data.SqlDbType、大小和源列名称初始化 System.Data.SqlClient.SqlParameter
// 类的新实例。
//
// 参数:
// parameterName:
// 要映射的参数的名称。
//
// dbType:
// System.Data.SqlDbType 值之一。
//
// size:
// 参数的长度。
//
// sourceColumn:
// 源列的名称。
//
// 异常:
// System.ArgumentException:
// dbType 参数中提供的值为无效的后端数据类型。
public SqlParameter(string parameterName, SqlDbType dbType, int size, string sourceColumn);
//
// 摘要:
// 用参数名称、参数的类型、参数的大小、System.Data.ParameterDirection、参数的精度、参数的小数位数、源列、要使用的 System.Data.DataRowVersion
// 和参数的值初始化 System.Data.SqlClient.SqlParameter 类的新实例。
//
// 参数:
// parameterName:
// 要映射的参数的名称。
//
// dbType:
// System.Data.SqlDbType 值之一。
//
// size:
// 参数的长度。
//
// direction:
// System.Data.ParameterDirection 值之一。
//
// isNullable:
// 如果字段的值可为 null,则为 true;否则为 false。
//
// precision:
// 要将 System.Data.SqlClient.SqlParameter.Value 解析为的小数点左右两侧的总位数。
//
// scale:
// 要将 System.Data.SqlClient.SqlParameter.Value 解析为的总小数位数。
//
// sourceColumn:
// 源列的名称。
//
// sourceVersion:
// System.Data.DataRowVersion 值之一。
//
// value:
// 一个 System.Object,它是 System.Data.SqlClient.SqlParameter 的值。
//
// 异常:
// System.ArgumentException:
// dbType 参数中提供的值为无效的后端数据类型。
[EditorBrowsable(EditorBrowsableState.Advanced)]
public SqlParameter(string parameterName, SqlDbType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value);
//
// 摘要:
// 初始化 System.Data.SqlClient.SqlParameter 类的一个新实例,该类使用参数名、参数的类型、参数的长度、方向、精度、小数位数、源列名称、System.Data.DataRowVersion
// 值之一、用于源列映射的布尔值、SqlParameter 的值、此 XML 实例的架构集合所在的数据库的名称、此 XML 实例的架构集合所在的关系架构以及此参数的架构集合的名称。
//
// 参数:
// parameterName:
// 要映射的参数的名称。
//
// dbType:
// System.Data.SqlDbType 值之一。
//
// size:
// 参数的长度。
//
// direction:
// System.Data.ParameterDirection 值之一。
//
// precision:
// 要将 System.Data.SqlClient.SqlParameter.Value 解析为的小数点左右两侧的总位数。
//
// scale:
// 要将 System.Data.SqlClient.SqlParameter.Value 解析为的总小数位数。
//
// sourceColumn:
// 源列的名称。
//
// sourceVersion:
// System.Data.DataRowVersion 值之一。
//
// sourceColumnNullMapping:
// 如果源列可以为 null,则为 true;如果不可以为 null,则为 false。
//
// value:
// 一个 System.Object,它是 System.Data.SqlClient.SqlParameter 的值。
//
// xmlSchemaCollectionDatabase:
// 此 XML 实例的架构集合所在的数据库的名称。
//
// xmlSchemaCollectionOwningSchema:
// 包含此 XML 实例的架构集合的关系架构。
//
// xmlSchemaCollectionName:
// 此参数的架构集合的名称。
public SqlParameter(string parameterName, SqlDbType dbType, int size, ParameterDirection direction, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping, object value, string xmlSchemaCollectionDatabase, string xmlSchemaCollectionOwningSchema, string xmlSchemaCollectionName);
对于这又臭又长的构造函数,一般情况下,我们都会采用第二个构造函数(如果你们不是,好吧,那是我懒),因为它只要两个参数,然后SqlParameter内部会根据value的类型自动推断其它的参数,比如SqlDbType,一切都是那么的美好,But,the question is coming!
1、绝对不要直接用 new SqlParameter(“@Test”,0),具体原因在msdn上有
2、查询时,对于字符串,会出现一些你意想不到的事情,以下是真实案例,亲身经历(注:数据库字段均为varchar,两个参数的构造函数默认会设置SqlDbType为nvarchar)
a) 根据用户名查询相关信息,简单的一个where userName=@UserName,数据量不大,查询时间需要几秒,直接在SQL查询分析器里面毫秒,具体原因可以见这里
b) Like查询,假定要查询%L%,有些包含L的能被查询出来,有些却查不出来,Why?好吧,暂时我还没找到相关的书面解释,但猜测还是跟a同样的原因,而对于此问题的推断依据是:能查询出来的字符串长度都是在几百以内,而查不出来的字符串都是非常长的字符串,虽然没具体统计过,但长度至少在4000以上(nvarchar后面为具体数字时最大只能4000)
PS:MSSQL的隐式转换遵循向上转换原则,类似C#,即(long)50与(int)50进行比较时,(int)50会被隐式转化成(long)50
注:虽然此处是以MSSQL作为例子,但相信同样的问题在其它关系型数据库中也会存在,所以最好还是不要偷懒,毕竟
new SqlParameter("@Test",0)
与
var param = new SqlParameter("@Test", SqlDbType.Int);
param.Value = 0;
相比,其实也没少多少代码是不是
其实没搞懂为啥微软没提供个如下的构造函数呢
public SqlParameter(string parameterName,SqlDbType dbType,object value);