传递多个SqlParameter到方法中

3
在我的主窗体中,我已经实现了以下代码...
void SampleMethod(string name, string lastName, string database)
{
        SqlParameter sqlParam = new SqlParameter();
        sqlParam.ParameterName = "@name";
        sqlParam.Value = name;
        sqlParam.SqlDbType = SqlDbType.NVarChar;

        SqlParameter sqlParam1 = new SqlParameter();
        sqlParam1.ParameterName = "@lastName";
        sqlParam1.Value = lastName;
        sqlParam1.SqlDbType = SqlDbType.NVarChar;

        SqlParameter sqlParam2 = new SqlParameter();
        sqlParam2.ParameterName = "@database";
        sqlParam2.Value = database;
        sqlParam2.SqlDbType = SqlDbType.NVarChar;

        SampleClass sampleClass = new SampleClass(new DBConn(@serverName, tableName, userName, password));
        sampleClass.executeStoredProc(dataGridView1, "sp_sampleStoredProc", sqlParam, sqlParam1, sqlParam2);
}

在我的SampleClass中,我有这样一种方法。

public DataGridView executeStoredProc(DataGridView dtgrdView, string storedProcName, params SqlParameter[] parameters)
{
        try
        {
            DataTable dt = new DataTable();
            sqlDA = new SqlDataAdapter(storedProcName, sqlconn);
            sqlDA.SelectCommand.CommandType = CommandType.StoredProcedure;
            sqlDA.SelectCommand.CommandTimeout = 60;

            // Loop through passed parameters
            if (parameters != null && parameters.Length > 0)
            {
                foreach (var p in parameters)
                    sqlDA.SelectCommand.Parameters.Add(p);
            }

            sqlDA.Fill(dt);
            dtgrdView.DataSource = dt;
            sqlconn.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
            sqlconn.Close();
        }

        return dtgrdView;
}

我尝试做的是避免多次重复。
SqlParameter sqlParam = new SqlParameter() 

在我的代码中,我尝试了很多解决方案,但没有得到正确的答案。我也尝试过研究这个问题,但仍然无法得到正确的答案。

请不要介意我的命名约定和其他代码,因为我有意改变了其中许多内容 :) 谢谢。


你可以使用 Parameters.Add 创建参数,但是你的代码明确地编写为将单个参数传递给 executeStoredProc。这有点自相矛盾。你为什么要完全避免多个参数呢? - Panagiotis Kanavos
1
或者你可以使用类似Dapper(https://github.com/StackExchange/dapper-dot-net)的东西。如果你的存储过程或查询需要多个参数,你仍然需要使用多个参数,但这已经为你很好地抽象出来了... - vidriduch
@SyntaxError,你必须指定字符串参数的长度,否则会发送'nvarchar(1)'的值。 - Panagiotis Kanavos
1
您可以使用对象集合初始化程序语法来缩短代码,但您无法真正避免创建调用所需的所有参数。请参见此处https://dev59.com/EWAg5IYBdhLWcg3wrMh4#23320836 - Steve
1
@mybirthname,你好像没有意识到你的代码允许转义异常。使用using而不是try/finally是有原因的。但由于你引入了GetSqlConnection方法,它实际上创建了一个连接并将其分配给一个命令(两个独立的任务),所以你不能使用它。你似乎也没有意识到AddWithValue不安全的——它很容易推断出错误的类型或大小。 - Panagiotis Kanavos
显示剩余5条评论
4个回答

2
作为您方案的替代选择,建议尝试使用已经存在的解决方案,即使用Dapper(https://github.com/StackExchange/dapper-dot-net)。
如果您的存储过程或查询需要多个参数,则仍然需要使用多个参数,但这已经为您很好地抽象出来了,这肯定可以减少代码量。
void SampleMethod(string name, string lastName, string database)
{
    using(var connection = new SqlConnection(MY_CONNECTION_STRING))
    {
        var resultListOfRows = connection.Query<ReturnObject>(MY_STORED_PROCEDURE, new { 
            name = name,
            lastName = lastName,
            database = database}, commandType: System.Data.CommandType.StoredProcedure);
    }
}

1
应该使用“查询(Query)”而不是“执行(Execute)”。 - Panagiotis Kanavos

1
将数据库逻辑单独放在一个地方(将sqladapter、sqlcommand等放在一个地方),然后像下面提到的那样封装命令中的参数,您就不需要单独声明sqlparameter,将其添加到参数列表中即可。
 cmdToExecute.Parameters.Add(new SqlParameter("@parameter", value));

请看下面的完整示例。
    public DataTable ProdTypeSelectAll(string cultureCode)
    {
        SqlCommand cmdToExecute = new SqlCommand();
        cmdToExecute.CommandText = "dbo.[pk_ProdType_SelectAll]";
        cmdToExecute.CommandType = CommandType.StoredProcedure;
        DataTable toReturn = new DataTable("ProdType");
        SqlDataAdapter adapter = new SqlDataAdapter(cmdToExecute);
        cmdToExecute.Connection = _mainConnection;
        cmdToExecute.Parameters.Add(new SqlParameter("@CultureName", cultureCode));
        _mainConnection.Open();
        adapter.Fill(toReturn);
        return toReturn;
}

是的,它确实可以,但方式不同。 - M. Adeel Khalid

1
你可以使用SqlParameter Constructor (String, Object)。替换为:
sampleClass.executeStoredProc(dataGridView1,
        "sp_sampleStoredProc",
        sqlParam,
        sqlParam1,
        sqlParam2);

With:

sampleClass.executeStoredProc(dataGridView1,
        "sp_sampleStoredProc",
        new SqlParameter("@name", (object)name),
        new SqlParameter("@lastName", (object)lastName),
        new SqlParameter("@database", (object)database));

1
首先,最简单的选项是使用像 Dapper 这样的微型ORM,并检索强类型集合。GridView可以绑定到任何东西,包括强类型集合。所有这些代码都可以变成:
using(var con=new SqlConnection(myConnectionString))
{
    con.Open();
    var result= connection.Query<ResultClass>("sp_MySproc", 
                         new { Name= name, LastName= lastName,Database=database},
                         commandType: CommandType.StoredProcedure);
    return result;
}

即使使用原始的 ADO.NET,您也可以通过使用 适当的构造函数 一行代码创建一个 SqlParameter。例如,您可以使用以下代码创建一个新的 nvarchar(n) 参数:
var myParam=new SqlParameter("@name",SqlDbType.NVarchar,20);

or

var myParam=new SqlParameter("@name",SqlDbType.NVarchar,20){Value = name};

更好的做法是只创建一次SqlCommand对象并重复使用。一旦你有了一个初始化的SqlCommand对象,你可以简单地为它设置一个新的连接并更改参数值,例如:
public void Init()
{
    _loadCustomers = new SqlCommand(...);
    _loadCustomers.Parameters.Add("@name",SqlDbType.NVarChar,20);
    ...
}

//In another method :
using(var con=new SqlConnection(myConnectionString)
{       
    _loadCustomers.Connection=con;
    _loadCustomers.Parameters["@name"].Value = myNameParam;
    con.Open();
    using(var reader=_load.ExecuteReader())
    {
    //...
    }
}

实际上,您可以使用SqlDataAdapter来做同样的事情,事实上,自.NET 1.0以来,Windows Forms和Data Adapters就是这样使用的。

不要每次想要填充网格时都创建一个新的SqlDataAdapter,而是创建一个单独的并在执行之前通过设置连接和参数进行重用。 您可以使用SqlDataAdapter(SqlCommand)构造函数使代码更加简洁:

public void Init()
{
    _loadCustomers = new SqlCommand(...);
    _loadCustomers.Parameters.Add("@name",SqlDbType.NVarChar,20);
    ....
    _myGridAdapter = new SqlDataAdapter(_loadCustomers);
    ...
}

并像这样调用它:

using(var con=new SqlConnection(myConnectionString))
{
    _myGridAdapter.SelectCommand.Connection=con;
    _myGridAdapter.SelectCommand.Parameters["@name"].Value =....;
    con.Open();

    var dt = new DataTable();
    _myGridAdapter.Fill(dt);
    dtgrdView.DataSource = dt;
    return dtgrdView;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接