Вызов хранимой процедуры с параметром в c #

139

Я могу выполнять удаление, вставку и обновление в своей программе, и я пытаюсь выполнить вставку путем вызова созданной хранимой процедуры из моей базы данных.

Эту вставку для пуговицы я заставляю работать хорошо.

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). Я поискал в Google хороший пример, но ничего интересного не нашел.

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);
    }
FrankSharp
источник
10
Просто дополнительная информация - вы не должны называть хранимые процедуры приложения префиксом sp_, как указано выше, с помощью sp_Add_contact. префикс sp_ - это системное соглашение об именах хранимых процедур, которое, когда SQL видит его, сначала выполняет поиск по всем системным хранимым процедурам, прежде чем какие-либо хранимые процессы приложения или пользовательского пространства. Что касается производительности, если вы позаботитесь об этом в своем приложении, префикс sp_ снизит время отклика.
Роберт Ахманн

Ответы:

268

Это почти то же самое, что выполнение запроса. В исходном коде вы создаете командный объект, помещаете его в cmdпеременную и никогда не используете. Однако здесь вы будете использовать это вместо da.InsertCommand.

Кроме того, используйте a 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();
    }
  }
}
Гуффа
источник
7
но если эта процедура возвращает данные, как я могу их поймать на C #?
MA9H
8
@ M009: Тогда используйте ExecuteReaderили ExecuteScalarназовите это.
Guffa
2
@ M009: Да, это еще один способ сделать то же самое. Адаптер данных использует файлы ExecuteReader.
Guffa
1
@DylanChen: Это зависит от настроек базы данных. По умолчанию в идентификаторах регистр не учитывается.
Guffa
1
@DylanChen: это параметр сортировки базы данных, который определяет, учитывают ли идентификаторы регистр.
Guffa
38

Вы должны добавить параметры, так как это необходимо для выполнения 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();
    }            
}
Рави Гадаг
источник
7
AddWithValue - плохая идея; SQL Server не всегда использует правильную длину для nvarchar или varchar, что вызывает неявное преобразование. Лучше явно указать длину параметра, а затем добавить значение отдельно с помощью parameter.Value = txtfirstname.
Джордж Стокер
14

cmd.Parameters.Add(String parameterName, Object value)устарел. Вместо этого используйтеcmd.Parameters.AddWithValue(String parameterName, Object value)

Добавление (String parameterName, Object value) устарело. Используйте AddWithValue (String parameterName, Object value)

По функционалу разницы нет. Причина, по которой они отказались от cmd.Parameters.Add(String parameterName, Object value)использования, AddWithValue(String parameterName, Object value)состоит в том, чтобы дать больше ясности. Вот ссылка MSDN для того же

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();
    }
  }
}
Рахул Никате
источник
2
У вас есть ссылка или источник заявления, которое cmd.Parameters.Addне рекомендуется?
Дэвид
7
@TonyG: это неправда, в принятом ответе используется предпочтительная перегрузка, Addкоторая также не является устаревшей. AddWithValueтакже не лучший способ, поскольку он определяет тип параметра из значения параметра. Это часто приводит к плохим планам выполнения или неправильным преобразованиям. Он также не проверяет параметр в первую очередь (например, введите, Datetimeно вы передадите a String). Вы можете видеть здесь, что только тот, Addкоторый принимает Objectвторой аргумент, устарел.
Тим Шмелтер
2
AddWithValueимеет те же функции, что и Addwith Object, но это не лучший способ. Оба должны сделать вывод о типе.
Тим Шмелтер
2
Вы абсолютно правы, @TimSchmelter. Мое прочтение текста было ошибочным. Спасибо за исправление. Я пишу новый код, в котором буду использовать Add (). И я изменю свой голос за этот ответ на голос против, поскольку Рахул Никате ошибался так же, как и я.
TonyG
2
@TimSchmelter Спасибо за совет. Я отредактировал свой ответ.
Рахул Никате
3

В качестве альтернативы у меня есть библиотека, которая упрощает работу с процессами: 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");
Грег Р. Тейлор
источник
1

Поставщики данных .NET состоят из ряда классов, используемых для подключения к источнику данных, выполнения команд и возврата наборов записей. Командный объект в ADO.NET предоставляет ряд методов 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();
        }
    }
}
Судхакар Рао
источник
В вашем ответе не используются блоки, что является наилучшей практикой. Также должен быть блок try catch для обработки любых исключений.
Trisped
0
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();
        }
}
user6916720
источник
0

Вот моя техника, которой я хотел бы поделиться. Работает хорошо, если ваши типы свойств 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();
        }
    }
}
Матстар
источник