SqlCommandGenerator類的設計
SqlCommandGEnerator類的設計思路就是通過反射得到方法的參數,使用被SqlCommandParameterAttribute標記的參數來裝配一個Command實例。
引用的命名空間:
//SqlCommandGenerator.cs
using System;
using System.Reflection;
using System.Data;
using System.Data.SqlClient;
using Debug = System.Diagnostics.Debug;
using StackTrace = System.Diagnostics.StackTrace;
類代碼:
namespace DataAccess
{
public sealed class SqlCommandGenerator
{
//私有構造器,不允許使用無參數的構造器構造一個實例
private SqlCommandGenerator()
{
throw new NotSupportedException();
}
//靜態只讀字段,定義用於返回值的參數名稱
public static readonly string ReturnValueParameterName = "RETURN_VALUE";
//靜態只讀字段,用於不帶參數的存儲過程
public static readonly object[] NoValues = new object[] {};
public static SqlCommand GenerateCommand(SqlConnection connection,
MethodInfo method, object[] values)
{
//如果沒有指定方法名稱,從堆棧幀得到方法名稱
if (method == null)
method = (MethodInfo) (new StackTrace().GetFrame(1).GetMethod());
// 獲取方法傳進來的SqlCommandMethodAttribute
// 為了使用該方法來生成一個Command對象,要求有這個Attribute。
SqlCommandMethodAttribute commandAttribute =
(SqlCommandMethodAttribute) Attribute.GetCustomAttribute(method, typeof(SqlCommandMethodAttribute));
Debug.Assert(commandAttribute != null);
Debug.Assert(commandAttribute.CommandType == CommandType.StoredProcedure ||
commandAttribute.CommandType == CommandType.Text);
// 創建一個SqlCommand對象,同時通過指定的attribute對它進行配置。
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandType = commandAttribute.CommandType;
// 獲取command的文本,如果沒有指定,那麼使用方法的名稱作為存儲過程名稱
if (commandAttribute.CommandText.Length == 0)
{
Debug.Assert(commandAttribute.CommandType == CommandType.StoredProcedure);
command.CommandText = method.Name;
}
else
{
command.CommandText = commandAttribute.CommandText;
}
// 調用GeneratorCommandParameters方法,生成command參數,同時添加一個返回值參數
GenerateCommandParameters(command, method, values);
command.Parameters.Add(ReturnValueParameterName, SqlDbType.Int).Direction
=ParameterDirection.ReturnValue;
return command;
}
private static void GenerateCommandParameters(
SqlCommand command, MethodInfo method, object[] values)
{
// 得到所有的參數,通過循環一一進行處理。
ParameterInfo[] methodParameters = method.GetParameters();
int paramIndex = 0;
foreach (ParameterInfo paramInfo in methodParameters)
{
// 忽略掉參數被標記為[NonCommandParameter ]的參數
if (Attribute.IsDefined(paramInfo, typeof(NonCommandParameterAttribute)))
continue;
// 獲取參數的SqlParameter attribute,如果沒有指定,那麼就創建一個並使用它的缺省設置。
SqlParameterAttribute paramAttribute = (SqlParameterAttribute) Attribute.GetCustomAttribute(
paramInfo, typeof(SqlParameterAttribute));
if (paramAttribute == null)
paramAttribute = new SqlParameterAttribute();
//使用attribute的設置來配置一個參數對象。使用那些已經定義的參數值。如果沒有定義,那麼就從方法
// 的參數來推斷它的參數值。
SqlParameter sqlParameter = new SqlParameter();
if (paramAttribute.IsNameDefined)
sqlParameter.ParameterName = paramAttribute.Name;
else
sqlParameter.ParameterName = paramInfo.Name;
if (!sqlParameter.ParameterName.StartsWith("@"))
sqlParameter.ParameterName = "@" + sqlParameter.ParameterName;
if (paramAttribute.IsTypeDefined)
sqlParameter.SqlDbType = paramAttribute.SqlDbType;
if (paramAttribute.IsSizeDefined)
sqlParameter.Size = paramAttribute.Size;
if (paramAttribute.IsScaleDefined)
sqlParameter.Scale = paramAttribute.Scale;
if (paramAttribute.IsPrecisionDefined)
sqlParameter.Precision = paramAttribute.Precision;
if (paramAttribute.IsDirectionDefined)
{
sqlParameter.Direction = paramAttribute.Direction;
}
else
{
if (paramInfo.ParameterType.IsByRef)
{
sqlParameter.Direction = paramInfo.IsOut ?
ParameterDirection.Output :
ParameterDirection.InputOutput;
}
else
{
sqlParameter.Direction = ParameterDirection.Input;
}
}
// 檢測是否提供的足夠的參數對象值
Debug.Assert(paramIndex < values.Length);
//把相應的對象值賦於參數。
sqlParameter.Value = values[paramIndex];
command.Parameters.Add(sqlParameter);
paramIndex++;
}
//檢測是否有多余的參數對象值
Debug.Assert(paramIndex == values.Length);
}