Attribute在.net編程中的應用(四)

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);
      }
   }
}
必要的工作終於完成了。SqlCommandGenerator中的代碼都加上了註釋,所以並不難讀懂。下面我們進入最後的一步,那就是使用新的方法來實現上一節我們一開始顯示個那個AddCustomer的方法。

重構新的AddCustomer代碼:

[ SqlCommandMethod(CommandType.StoredProcedure) ]
public void AddCustomer( [NonCommandParameter] SqlConnection connection,
                   [SqlParameter(50)] string customerName,
                   [SqlParameter(20)] string country,
                   [SqlParameter(20)] string province,
                   [SqlParameter(20)] string city,
                   [SqlParameter(60)] string address,
                   [SqlParameter(16)] string telephone,
                   out int customerId )
{
   customerId=0; //需要初始化輸出參數
  //調用Command生成器生成SqlCommand實例
   SqlCommand command = SqlCommandGenerator.GenerateCommand( connection, null, new object[]
{customerName,country,province,city,address,telephone,customerId } );
                        
   connection.Open();
   command.ExecuteNonQuery();
   connection.Close();

   //必須明確返回輸出參數的值
   customerId=(int)command.Parameters["@CustomerId"].Value;
}
代碼中必須注意的就是out參數,需要事先進行初始化,並在Command執行操作以後,把參數值傳回給它。受益於Attribute,使我們擺脫了那種編寫大量枯燥代碼編程生涯。 我們甚至還可以使用Sql存儲過程來編寫生成整個方法的代碼,如果那樣做的話,可就大大節省了你的時間了,上一節和這一節中所示的代碼,你可以把它們單獨編譯成一個組件,這樣就可以在你的項目中不斷的重用它們了。從下一節開始,我們將更深層次的介紹Attribute的應用,請繼續關注。(待續)


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/okvee/archive/2008/07/04/2610373.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章