在调用存储过程时最大程度地减少代码重复性



我正在使用某个方法主体来调用存储过程,示例代码如下:

     public void StoredProcedureThatIsBeingcalled(int variable_1, int variable_2, out DataSet ds)
 {
     using (SqlConnection con = new SqlConnection(DatabaseConnectionString))
     {
         ds = new DataSet("DsToGoOut");
         using (SqlCommand cmd = new SqlCommand("StoredProcedureThatIsBeingcalled", DbConn.objConn))
         {
             cmd.CommandType = CommandType.StoredProcedure;

             cmd.Parameters.Add(new SqlParameter("@variable_1", variable_1));
             cmd.Parameters.Add(new SqlParameter("@variable_2", variable_2));
             try
             {
                 con.Open();
                 SqlDataAdapter objDataAdapter = new SqlDataAdapter();
                 objDataAdapter.SelectCommand = cmd;
                 objDataAdapter.Fill(ds);
                 con.Close();
             }
             catch (Exception ex)
             {
                 //sql_log_err
             }
         }
     }
 }

有什么让我烦恼的是,对于我调用的每个不同过程,我在我的 cs 文件中一次又一次地重复上述大部分代码。

显然,我可以清除它并使用过程名称作为变量调用一个函数,但是我如何为我使用的不同过程提供不同数量的参数(具有不同的数据类型 - int,字符串布尔值 - 而不是其他任何东西)?

我可以有几个不同的函数和不同数量的参数(0-10),但我觉得有更好的方法可以做到这一点?

更新

我知道这是一个非常古老的问题(事实上,我只是在搜索我给别人的另一个旧答案以重复关闭时偶然发现了它),但我最近发布了一个 git hub 项目来满足这个非常需要。它通过封装连接、命令、参数和数据适配器来最大程度地减少使用 ADO.Net 时的代码重复。
如果你想试一试,我很高兴知道你的想法。

第一个版本

可以使用帮助程序类来封装 sql 参数,并创建单个方法来处理所有数据集填充,如下所示:

帮助程序类:

private class SqlParamDefinition
{
    public SqlParamDefinition(string name, SqlDbType dbType, object value)
    {
        this.Name = name;
        this.DbType = dbType;
        this.Value = value;
    }
    public string Name { get; }
    public SqlDbType DbType { get; }
    public object Value { get; }

}

执行方法(基于您发布的方法):

public DataSet ExecuteSelectProcedure(string procedeureName, params SqlParamDefinition[] parameters)
{
    var ds = new DataSet();
    using (var con = new SqlConnection(DatabaseConnectionString))
    {
        using (var cmd = new SqlCommand(procedeureName, DbConn.objConn))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            for(int i = 0; i < parameters.Length; i++)
            {
                var param = parameters[i];
                cmd.Parameters.Add(new SqlParameter(param.Name, param.DbType).Value = param.Value);
            }
            try
            {
                con.Open();
                var objDataAdapter = new SqlDataAdapter();
                objDataAdapter.SelectCommand = cmd;
                objDataAdapter.Fill(ds);
                con.Close();
            }
            catch (Exception ex)
            {
                //sql_log_err
            }
        }
    }
    return ds;
}

调用示例:

var parameters = new SqlParamDefinition[]
{
    new SqlParamDefinition("@Param1", SqlDbType.VarChar, "value1"),
    new SqlParamDefinition("@Param2", SqlDbType.VarChar, "value2"),
    new SqlParamDefinition("@Param3", SqlDbType.Int, 123),
};
var ds = ExecuteSelectProcedure("Strong procedure name", parameters);

我遇到了这个问题;我在多个数据库上调用存储过程。 您可以将存储过程详细信息(例如名称,输入参数,输出参数等)存储在数据库表中,然后使用工厂方法来填充对象(以下示例中的clsStorageProcedure)。 代码看起来像这样(我还没有测试过代码):

public void StoredProcedureThatIsBeingcalled(clsStoredProcedure objStoredProcedure)
 {
     using (SqlConnection con = new SqlConnection(objStoredProcedure.ConnectionString))
     {
         ds = new DataSet("DsToGoOut");
         using (SqlCommand cmd = new SqlCommand(objStoredProcedure.Name, DbConn.objConn))
         {
             cmd.CommandType = CommandType.StoredProcedure;
foreach (Parameter p in clsStoredProcedure.Parameters)
{
       cmd.Parameters.Add(new SqlParameter(p.name, p.value));
}
             try
             {
                 con.Open();
                 SqlDataAdapter objDataAdapter = new SqlDataAdapter();
                 objDataAdapter.SelectCommand = cmd;
                 objDataAdapter.Fill(ds);
                 con.Close();
             }
             catch (Exception ex)
             {
                 //sql_log_err
             }
         }
     }
 }

如果要连接到Oracle数据库和SQL数据库,则可以使用dbConnection,dbCommand等连接到数据库。

您可以创建接受stringDictionary<string,object>作为参数的方法。现在,您可以根据命令文本和参数字典构造命令。此外,您可以扩展此方法并将其用于选择、插入等查询。

例:

private void ExecCommand(string commandText, Dictionary<string, object> param)
{
 using (SqlConnection con = new SqlConnection(DatabaseConnectionString))
 {
     ds = new DataSet("DsToGoOut");
     using (SqlCommand cmd = new SqlCommand(commandText, DbConn.objConn))
     {
         cmd.CommandType = CommandType.StoredProcedure;
         //***************************************
         // New method
         cmd = AddParametersToCommand(cmd, param);
         //***************************************
         try
         {
             con.Open();
             SqlDataAdapter objDataAdapter = new SqlDataAdapter();
             objDataAdapter.SelectCommand = cmd;
             objDataAdapter.Fill(ds);
             con.Close();
         }
         catch (Exception ex)
         {
             //sql_log_err
         }
     }
 }
}

AddParametersToCommand

private SQLCommand AddParametersToCommand(SqlCommand command, Dictionary<string, object> parameters)
{
    if (parameters == null || command == null)
    {
        return;
    }

    SQLCommand tempCommand = command;
    foreach (var param in parameters)
    {
        var parameter = tempCommand.CreateParameter();
        parameter.ParameterName = param.Key;
        parameter.Value = param.Value ?? DBNull.Value;
        tempCommand.Parameters.Add(parameter);
    }
    return tempCommand;
}

并像这样使用它:

Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@variable_1", variable_1);
parameters.Add("@variable_2", variable_2);
ExecCommand("StoredProcedureThatIsBeingcalled", parameters);

所以,

可以使用 dapper 来执行存储过程。 https://github.com/StackExchange/dapper-dot-net

可以声明将使用在存储过程中选择的内容映射的 DTO 模型。

public class DogDto
{
    public int? Age { get; set; }
    public int Id { get; set; }
    public string Name { get; set; }
    public float? Weight { get; set; }
    public int IgnoredProperty { get { return 1; } }
}   
// _databaseConnectionString is your database connection string
using (var conn = new SqlConnection(_databaseConnectionString)){
var dog = cnn.Query<DogDto>("schema.spGetDog", new {Id = 120}, 
        commandType: CommandType.StoredProcedure).SingleOrDefault();
 }
// and let's assume we have schema.spGetDog stored procedure already declared in our database 
// and be aware that the 2nd parameter after the stored procedure name are the stored procedure parameters

存储过程必须选择列"期限"、"ID"、"名称"、"权重(映射由属性名称实现)。我真的不知道你是否可以改变这个行为,因为如果你在数据库/dto中具有使用存储过程的相同列/属性,开发过程会更快。

仅供记录,根据文档:"Dapper 没有特定于数据库的实现细节,它适用于所有 .NET ADO 提供程序,包括 SQLite、SQL CE、Firebird、Oracle、MySQL、PostgreSQL 和 SQL Server。

这就是你需要做的。

最新更新