在c#中调用带参数的存储过程

Posted

技术标签:

【中文标题】在c#中调用带参数的存储过程【英文标题】:Call a stored procedure with parameter in c# 【发布时间】:2011-11-24 10:40:45 【问题描述】:

我能够在我的程序中删除、插入和更新,我尝试通过从我的数据库中调用创建的存储过程来进行插入。

我制作的这个按钮插入效果很好。

private void btnAdd_Click(object sender, EventArgs e)

        SqlConnection con = new SqlConnection(dc.Con);
        SqlCommand cmd = new SqlCommand("Command String", con);
        
        da.InsertCommand = new SqlCommand("INSERT INTO tblContacts VALUES (@FirstName, @LastName)", con);
        da.InsertCommand.Parameters.Add("@FirstName", SqlDbType.VarChar).Value = txtFirstName.Text;
        da.InsertCommand.Parameters.Add("@LastName", SqlDbType.VarChar).Value = txtLastName.Text;

        con.Open();
        da.InsertCommand.ExecuteNonQuery();
        con.Close();

        dt.Clear();
        da.Fill(dt);
     

这是调用名为sp_Add_contact 的过程以添加联系人的按钮的开始。 sp_Add_contact(@FirstName,@LastName) 的两个参数。我在谷歌上搜索了一些很好的例子,但没有发现任何有趣的东西。

private void button1_Click(object sender, EventArgs e)

        SqlConnection con = new SqlConnection(dc.Con);
        SqlCommand cmd = new SqlCommand("Command String", con);
        cmd.CommandType = CommandType.StoredProcedure;

        ???
        
        con.Open();
        da. ???.ExecuteNonQuery();
        con.Close();

        dt.Clear();
        da.Fill(dt);
    

【问题讨论】:

只是一点额外的信息 - 您不应该使用 sp_ 前缀命名您的应用程序存储过程,就像上面的 sp_Add_contact 一样。 sp_ 前缀是系统存储过程命名约定,当 SQL 看到它时,将首先搜索所有系统存储过程,然后再搜索任何应用程序或用户空间存储过程。作为性能问题,如果您在应用程序中关心这一点,则 sp_ 前缀会降低您的响应时间。 【参考方案1】:

这与运行查询几乎相同。在您的原始代码中,您正在创建一个命令对象,将其放入 cmd 变量中,并且永远不要使用它。但是,在这里,您将使用它而不是 da.InsertCommand

另外,对所有一次性物品使用using,这样您就可以确保它们被正确处理:

private void button1_Click(object sender, EventArgs e) 
  using (SqlConnection con = new SqlConnection(dc.Con)) 
    using (SqlCommand cmd = new SqlCommand("sp_Add_contact", con)) 
      cmd.CommandType = CommandType.StoredProcedure;

      cmd.Parameters.Add("@FirstName", SqlDbType.VarChar).Value = txtFirstName.Text;
      cmd.Parameters.Add("@LastName", SqlDbType.VarChar).Value = txtLastName.Text;

      con.Open();
      cmd.ExecuteNonQuery();
    
  

【讨论】:

但是如果这个过程返回数据,我如何在 C# 中捕获它? @M009:那你就用ExecuteReader或者ExecuteScalar来调用吧。 @M009:是的,这是做同样事情的另一种方式。数据适配器使用ExecuteReader @DylanChen:这取决于数据库设置。默认设置是标识符不区分大小写。 @DylanChen:决定标识符是否区分大小写的是数据库的排序规则设置。【参考方案2】:

你必须添加参数,因为它是SP执行所需要的

using (SqlConnection con = new SqlConnection(dc.Con))

    using (SqlCommand cmd = new SqlCommand("SP_ADD", con))
    
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@FirstName", txtfirstname.Text);
        cmd.Parameters.AddWithValue("@LastName", txtlastname.Text);
        con.Open();
        cmd.ExecuteNonQuery();
                

【讨论】:

AddWithValue 是个坏主意; SQL Server 并不总是为 nvarchar 或 varchar 使用正确的长度,从而导致发生隐式转换。最好明确指定参数的长度,然后使用parameter.Value = txtfirstname单独添加值。【参考方案3】:

cmd.Parameters.Add(String parameterName, Object value) 现已弃用。而是使用cmd.Parameters.AddWithValue(String parameterName, Object value)

Add(String parameterName, Object value) has been deprecated. Use AddWithValue(String parameterName, Object value)

在功能方面没有区别。他们的原因 弃用 cmd.Parameters.Add(String parameterName, Object value) 支持 AddWithValue(String parameterName, Object value) 是为了提供更多 明晰。 Here is the MSDN reference for the same

private void button1_Click(object sender, EventArgs e) 
  using (SqlConnection con = new SqlConnection(dc.Con)) 
    using (SqlCommand cmd = new SqlCommand("sp_Add_contact", con)) 
      cmd.CommandType = CommandType.StoredProcedure;

      cmd.Parameters.AddWithValue("@FirstName", SqlDbType.VarChar).Value = txtFirstName.Text;
      cmd.Parameters.AddWithValue("@LastName", SqlDbType.VarChar).Value = txtLastName.Text;

      con.Open();
      cmd.ExecuteNonQuery();
    
  

【讨论】:

您是否有链接或来源表明 cmd.Parameters.Add 已被弃用? @TonyG:这不是真的,接受的答案使用Add 的首选重载,这也没有被弃用。 AddWithValue 也不是最好的方法,因为它从参数值推断参数的类型。这通常会导致错误的执行计划或不正确的转换。它也不会首先验证参数(例如,键入 if Datetime 但您传递了 String)。您可以看到 here 仅不推荐使用将 Object 作为第二个参数的 Add AddWithValueAddObject 具有相同的功能,但这不是首选方式。两者都需要推断类型。 你说得对,@TimSchmelter。我对文本的阅读是有缺陷的。感谢您的指正。我正在编写一些将使用 Add() 的新代码。我会把我对这个答案的赞成票改为反对票,因为拉胡尔·尼凯特和我一样错了。 @TimSchmelter 感谢您的建议。我已经编辑了我的答案。【参考方案4】:

作为替代方案,我有一个可以轻松使用 procs 的库:https://www.nuget.org/packages/SprocMapper/

SqlServerAccess sqlAccess = new SqlServerAccess("your connection string");
    sqlAccess.Procedure()
         .AddSqlParameter("@FirstName", SqlDbType.VarChar, txtFirstName.Text)
         .AddSqlParameter("@FirstName", SqlDbType.VarChar, txtLastName.Text)
         .ExecuteNonQuery("StoredProcedureName");

【讨论】:

【参考方案5】:
public void myfunction()
        try
        
            sqlcon.Open();
            SqlCommand cmd = new SqlCommand("sp_laba", sqlcon);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.ExecuteNonQuery();
        
        catch(Exception ex)
        
            MessageBox.Show(ex.Message);
        
        finally
        
            sqlcon.Close();
        

【讨论】:

缺少参数,但恕我直言最好的答案,如果您包括 command.parameters.AddSqlParameter("@FirstName", SqlDbType.VarChar).Value ="myText" if (connection.State != ConnectionState.Closed) connection.Close();【参考方案6】:

.NET 数据提供程序由许多用于连接数据源、执行命令和返回记录集的类组成。 ADO.NET 中的 Command Object 提供了许多 Execute 方法,可用于以各种方式执行 SQL 查询。

存储过程是包含一个或多个 SQL 语句的预编译可执行对象。在许多情况下,存储过程接受输入参数并返回多个值。如果编写存储过程来接受参数值,则可以提供参数值。下面给出了一个接受输入参数的示例存储过程:

  CREATE PROCEDURE SPCOUNTRY
  @COUNTRY VARCHAR(20)
  AS
  SELECT PUB_NAME FROM publishers WHERE COUNTRY = @COUNTRY
  GO

上述存储过程接受国家名称(@COUNTRY VARCHAR(20))作为参数,并返回输入国家的所有发布者。将 CommandType 设置为 StoredProcedure 后,您可以使用 Parameters 集合来定义参数。

  command.CommandType = CommandType.StoredProcedure;
  param = new SqlParameter("@COUNTRY", "Germany");
  param.Direction = ParameterDirection.Input;
  param.DbType = DbType.String;
  command.Parameters.Add(param);

上述代码将国家参数从 C# 应用程序传递给存储过程。

using System;
using System.Data;
using System.Windows.Forms;
using System.Data.SqlClient;

namespace WindowsFormsApplication1

    public partial class Form1 : Form
    
        public Form1()
        
            InitializeComponent();
        

        private void button1_Click(object sender, EventArgs e)
        
            string connetionString = null;
            SqlConnection connection ;
            SqlDataAdapter adapter ;
            SqlCommand command = new SqlCommand();
            SqlParameter param ;
            DataSet ds = new DataSet();

            int i = 0;

            connetionString = "Data Source=servername;Initial Catalog=PUBS;User ID=sa;Password=yourpassword";
            connection = new SqlConnection(connetionString);

            connection.Open();
            command.Connection = connection;
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = "SPCOUNTRY";

            param = new SqlParameter("@COUNTRY", "Germany");
            param.Direction = ParameterDirection.Input;
            param.DbType = DbType.String;
            command.Parameters.Add(param);

            adapter = new SqlDataAdapter(command);
            adapter.Fill(ds);

            for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
            
                MessageBox.Show (ds.Tables[0].Rows[i][0].ToString ());
            

            connection.Close();
        
    

【讨论】:

您的答案不使用using 块,这是最佳做法。此外,应该有一个 try catch 块来处理任何异常。【参考方案7】:

这是我想分享的技术。只要您的 clr 属性类型是 sql 等效类型,就可以很好地工作,例如。 bool -> bit, long -> bigint, string -> nchar/char/varchar/nvarchar, decimal -> 钱

public void SaveTransaction(Transaction transaction) 

    using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConString"].ConnectionString))
    
        using (var cmd = new SqlCommand("spAddTransaction", con))
        
            cmd.CommandType = CommandType.StoredProcedure;
            foreach (var prop in transaction.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
                cmd.Parameters.AddWithValue("@" + prop.Name, prop.GetValue(transaction, null));
            con.Open();
            cmd.ExecuteNonQuery();
        
    

【讨论】:

以上是关于在c#中调用带参数的存储过程的主要内容,如果未能解决你的问题,请参考以下文章

c#调用oracle存储过程,返回2个值

在 PetaPoco 中调用带参数的存储过程

sql数据库中怎样调用带参数的存储过程

怎样在Delphi中实现在运行中实现带参数的存储过程?

有无参数之存储过程

oracle 存储过程中调用存储过程