muSQLe - SQL Server查询调用框架
一种简单且强类型的从代码调用查询和存储过程的方法

引言
随着 ADO.NET 的到来,我们有了与 Microsoft SQL Server 通信的极其强大的方式。但是,调用 SQL 存储过程、函数甚至简单的查询会让你每次需要时都写出类似...的语句。
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "MyProcName";
cmd.Parameters.Add ( ... );
....
cmd.Parameters.Add ( ... );
cmd.ExecuteNonQuery(); // or cmd.ExecuteReader() and more lines of code
// to read results
// and even more lines if Output parameters are present.
}
... 每次需要时。此外,您必须使用 DBNull.Value
而不是 C# 中的 null
或 VB 中的 Nothing
(这需要额外的检查和转换)。当然,您可以为每个查询编写大量包装器并将它们用作内置函数,但我认为这不是很方便。
背景
此项目的核心部分是 SqlQuery
类。它继承自 RealProxy
,用于包装声明了 SQL 函数的接口。SqlImportAttribute
属性用于将方法标记为 SQL 方法。它还可以指定函数名称或查询类型和文本。
当方法被调用时,代理会在由内部 static SqlParameterCache
类表示的缓存中查找它。当找到缓存条目(即此方法已被解析)时,它会返回给代理。否则,它将使用反射从 MethodInfo
定义中解析。同时还会执行一些基本检查。
SqlReturnAttribute
属性每个方法定义只能使用一次。- 标记了
SqlReturnAttribute
的参数必须是out
参数,并且类型为class
或Nullable<>
。 - 如果方法的返回类型被标记为
SqlReturnAttribute
,则它必须是class
或Nullable<>
类型。 ref
参数被解释为InputOutput
SQL 参数,out
参数被解释为Output
。两者都必须是class
或Nullable<>
类型。Output
参数必须指定SqlTypeAttribute
。
当所有这些检查通过后,SqlParameterCacheEntry
实例将被存储在缓存中并传回给代理。如果任何检查失败,则会抛出 ArgumentException
。
然后代理创建并初始化 SqlCommand
类的一个实例,用传入的参数填充所有需要的参数,并执行命令。执行的类型由方法定义确定。
- 如果方法返回类型为
void
、int
或标记了SqlReturnAttribute
,则使用ExecuteNonQuery()
。 - 如果方法的返回类型为
DataSet
,则使用ExecuteReader()
。 - 如果方法的返回类型为
DataTable
,则使用ExecuteReader(CommandBehavior.SingleResult)
。 - 如果方法的返回类型为
SingleRowDataTable
,则使用ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.SingleRow)
。
SingleRowDataTable
类继承自 DataTable
,主要用于类型区分。它还提供了一个 Row
属性来访问第一行(如果不存在,则返回 null
)。
用法
首先,您需要声明一个包含方法定义的 Interface
。通用方法描述。
- 每个方法定义都以
[SqlImport]
开始。它可以不带参数。- 如果方法名称与存储过程/函数名称不同,则必须在参数中指定真实名称:
[SqlImport("realname")]
。 - 如果方法用于包装另一种类型的查询(表直接查询、SQL 查询),则还必须指定查询类型:
[SqlImport(CommandType.TableDirect, "tableName")]
。
- 如果方法名称与存储过程/函数名称不同,则必须在参数中指定真实名称:
- 然后是返回类型定义。
- 对于不返回任何表数据(或我们不关心)的存储过程,我们应该使用以下类型之一:
void
int
(返回调用受影响的行数)- 标记了
[return: SqlReturn]
的可空类型 - 存储过程或函数的返回值。例如:[return: SqlReturn] int?
- 标记了
[return: SqlReturn("ParamName")]
的可空类型 - 存储过程的输出参数。例如:[return: SqlReturn("ParamName"), SqlType(SqlDbType.Int)] int?
- 当存储过程返回表数据时,应使用
DataSet
、DataTable
或SingleRowDataTable
类型。
- 对于不返回任何表数据(或我们不关心)的存储过程,我们应该使用以下类型之一:
- 从您的代码中调用的方法名称。
- 参数。
[SqlReturn]
属性也可以应用于out
参数。[SqlType]
属性必须应用于每个out
参数。
可以通过 XML 注释(如图所示)将帮助文本和描述应用于方法。
示例
// Interface definition:
interface IQuerySample
{
/// <summary>
/// Returns a list of active sessions on server
/// </summary>
/// <param name="LogiName">Show sessions only for this user,
/// null - for all users</param>
/// <returns>DataTable with session info</returns>
[SqlImport("sp_who")]
DataTable ShowSessions(string LogiName);
}
// Usage:
// Let's fill DataGridView named 'grid' with session information.
// Don't forget to turn on AutoGenerateColumns property.
// ...
IQuerySample q = SqlQuery<IQuerySample>.Create(connection);
grid.DataSource = q.ShowSessions(null);
// ... Here we could use 'q' more and more times ...
很简单,不是吗?
版本历史
- 9.09.06.
- 为
Create
方法添加了新的重载,允许从连接字符串创建查询。使用此重载时,连接将在执行查询之前打开,并在之后关闭。还添加了NullableEnum<T> static
类,以帮助将可空的数字查询结果与enum
值进行转换。 - 7.09.06.
- 修复了输出参数中
NULL
值作为方法结果返回的错误。添加了更详细的异常描述。 - 6.09.06.
- 修复了
out
参数的错误。添加了SqlTypeAttribute
属性用于显式类型指定。向SqlReturnAttribute
添加了可选参数,允许方法不仅返回返回值,还可以返回out
参数。因此,您可以编写[return: SqlReturn("ParamName")]
来返回输出参数ParamName
的值,这对于返回例如新创建记录 ID 的存储过程非常有用。 - 1.09.06.
- 首次发布