调用存储过程时最小化代码重复

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

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,字符串bool – 从不其他任何东西)我用 ?

我可以使用不同数量的参数(0-10)来实现几个不同的function,但我觉得有更好的方法可以做到这一点?

更新

我知道这是一个非常古老的问题(实际上,我只是偶然发现它在搜索另一个旧答案时我给了其他人关闭作为复制品),但我最近发布了一个git hub项目来满足这个需求。 通过封装Connection,Command,Parameters和DataAdapter,它可以最大限度地减少使用ADO.Net时的代码重复。
如果你想尝试一下,我会很高兴知道你对它的看法。

第一个版本

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

助手class:

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

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

 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作为参数的方法。 现在您可以根据命令文本和参数字典构建命令。 此外,您可以扩展此方法并将其用于选择,插入等查询。

例:

 private void ExecCommand(string commandText, Dictionary 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 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 parameters = new Dictionary(); 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("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 

您的存储过程必须选择Age,Id,Name,Weight列(通过属性名称实现映射)。 我真的不知道你是否可以更改这个comportment,因为如果你在使用存储过程的database / dto中有相同的列/属性,那么开发过程会更快。

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

这就是你需要做的。