逆水行船

别人的天堂,是我的异乡;无端的繁华,倍添我的惆怅

 

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);
  }
 }
}

posted on   荣-  阅读(338)  评论(0编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构

导航

统计

点击右上角即可分享
微信分享提示