• Attribute学习:SqlCommandGenerator 荣


    using System;
    using System.Reflection;
    using System.Data;
    using System.Data.SqlClient;
    using Debug = System.Diagnostics.Debug;
    using StackTrace = System.Diagnostics.StackTrace;

    namespace WebApplication1
    {
     /// <summary>
     /// 本类主要用于根据属性生成带参数数组的Command对象。
     ///我存在一个问题就是利用属性,是否对程序的效率有很大的影响。
     /// 还有,我如何把属性应用到某个类的property或字段中,而且能很方便的读取这些变量?

     /// </summary>
     public sealed class SqlCommandGenerator
     {
      // 静态只读属性,定义用于返回值的参数名称
      public static string ReturnValueParameterName
      {
       get
       {
        return "RETURN_VALUE";
       }
      }

      // 静态只读属性,用于不带参数的存储过程
      public static object[] NoValues
      {
       get
       {
        return new object[] {};
       }
      }

      // 私有构造器,不允许使用无参数的构造器构造一个实例
      private SqlCommandGenerator()
      {
       throw new NotSupportedException();
      }

      /// <summary>
      /// 根据传入的参数,生成一个Command对象。
      /// </summary>
      /// <param name="connection">数据库联接组件</param>
      /// <param name="method"> 发现方法的特性并提供对方法元数据的访问</param>
      /// <param name="values">参数数组值集合</param>
      /// <returns>Command镀锡iang</returns>
      public static SqlCommand GenerateCommand(SqlConnection connection, MethodInfo method, object[] values)
      {
       //如果没有指定方法名称,从堆栈帧得到方法名称
       //  StackTrace:表示一个堆栈跟踪,它是一个或多个堆栈帧的有序集合。
       //  GetFrame: 获取指定的堆栈帧。
       //  GetMethod: 获取在其中执行帧的方法。
       //  这儿不懂,就囫囵吞枣的放在这儿。
       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.Commondtype == CommandType.StoredProcedure ||
        commandAttribute.Commondtype == CommandType.Text);

        // 创建一个SqlCommand对象,同时通过指定的attribute对它进行配置。
        SqlCommand command = new SqlCommand();
       command.Connection = connection;

       // command类型
       command.CommandType = commandAttribute.Commondtype;

       // 获取command的文本,如果没有指定,那么使用方法的名称作为存储过程名称
       if (commandAttribute.CommandText.Length == 0)
       {
        Debug.Assert(commandAttribute.Commondtype == CommandType.StoredProcedure);
        command.CommandText = method.Name;
       }
       else
       {
        command.CommandText = commandAttribute.CommandText;
       }

       // 调用GeneratorCommandParameters方法,生成command参数,同时添加一个返回值参数
       GenerateCommandParameters(command, method, values);

       // 给参数数组添加一个参数“RETURN_VALUE”
       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 paraAttribute = (SqlParameterAttribute)Attribute.GetCustomAttribute(paramInfo, typeof(SqlParameterAttribute));

        if (paraAttribute == null)
        {
         paraAttribute = new SqlParameterAttribute();
        }

        //使用attribute的设置来配置一个参数对象。使用那些已经定义的参数值。如果没有定义,那么就从方法
        // 的参数来推断它的参数值。
        SqlParameter sqlParameter = new SqlParameter();

        // 如果属性中名称有指定,用属性名称
        if (paraAttribute.IsNameDefined)
        {
         sqlParameter.ParameterName = paraAttribute.Name;
        }
         // 否则,用参数名称
        else
        {
         sqlParameter.ParameterName = paramInfo.Name;
        }

        // 参数名称是否以@开头,如果不是,自动添加@
        if (!(sqlParameter.ParameterName.StartsWith("@")))
        {
         sqlParameter.ParameterName = "@" + sqlParameter.ParameterName;
        }

        // 参数是否指定参数类型,如果指定,用属性中的类型
        if (paraAttribute.IsTypeDefined)
        {
         sqlParameter.SqlDbType = paraAttribute.ParamType;
        }

        // 属性中是否指定参数大小,如果指定,用参数中的大小
        if (paraAttribute.IsSizeDefined)
        {
         sqlParameter.Size = paraAttribute.Size;
        }

        // 属性中是否指定参数的范围,如果指定,用参数中的范围。
        if (paraAttribute.IsScaleDefined)
        {
         sqlParameter.Scale = paraAttribute.Scale;
        }

        // 属性中是否指定参数的精度,如果指定,用参数中的精度。
        if (paraAttribute.IsPrecisionDefined)
        {
         sqlParameter.Precision = paraAttribute.Precision;
        }

        // 属性中是否指定参数的方向,如果指定,用参数中定义的方向
        if (paraAttribute.IsDirectionDefined)
        {
         sqlParameter.Direction = paraAttribute.Direction;
        }
        else
        {
         // 参数是否是引用,如果是引用,则设置为Output,或InputOutput
         if (paramInfo.ParameterType.IsByRef)
         {
          sqlParameter.Direction = paramInfo.IsOut ? ParameterDirection.Output : ParameterDirection.InputOutput;
         }
          // 否则,设置为Input
         else
         {
          sqlParameter.Direction = ParameterDirection.Input;
         }
        }

        // 检测是否提供的足够的参数对象值
        Debug.Assert(paramIndex < values.Length);

        sqlParameter.Value = values[paramIndex];
        command.Parameters.Add(sqlParameter);

        paramIndex++;
       }

       // 检测是否有多余的参数对象值
       Debug.Assert(paramIndex == values.Length);
      }
     }
    }

  • 相关阅读:
    Redis简介(数据结构,哨兵、集群和SpringDataRedis)
    FastDFS + Nginx
    Dubbo
    Ubuntu下Zookeeper的安装和基本使用
    RMI简介
    RPC
    各大技术团队的博客
    天了噜,为什么外链css要放在头部,js要放在尾部?
    月经帖 | 2019.11
    前端面试知识点
  • 原文地址:https://www.cnblogs.com/admin11/p/200267.html
Copyright © 2020-2023  润新知