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);
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .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语句:使用策略模式优化代码结构