Wywołaj procedurę składowaną z parametrem w języku C #

138

Mogę usunąć, wstawić i zaktualizować w moim programie i spróbować wstawić, wywołując utworzoną procedurę składowaną z mojej bazy danych.

Ta wkładka guzikowa, którą wykonuję, działa dobrze.

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

To jest początek przycisku wywołującego procedurę o nazwie w sp_Add_contactcelu dodania kontaktu. Dwa parametry dla sp_Add_contact(@FirstName,@LastName). Szukałem w Google dobrego przykładu, ale nie znalazłem nic interesującego.

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
źródło
8
Tylko dodatkowa informacja - nie powinieneś nazywać swoich procedur składowanych aplikacji prefiksem sp_, tak jak powyżej z sp_Add_contact. przedrostek sp_ jest konwencją nazewnictwa procesów przechowywanych w systemie, która po zobaczeniu go przez język SQL przeszuka wszystkie procedury składowane w systemie, a dopiero potem procedury zapisane w aplikacji lub przestrzeni użytkownika. Jeśli chodzi o wydajność, jeśli zależy Ci na tym w aplikacji, prefiks sp_ ​​obniży czas odpowiedzi.
Robert Achmann

Odpowiedzi:

265

To prawie to samo, co uruchomienie zapytania. W swoim oryginalnym kodzie tworzysz obiekt polecenia, umieszczasz go w cmdzmiennej i nigdy go nie używasz. Tutaj jednak użyjesz tego zamiast da.InsertCommand.

Użyj również usingdla wszystkich przedmiotów jednorazowego użytku, aby mieć pewność, że są one prawidłowo utylizowane:

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();
    }
  }
}
Guffa
źródło
7
ale jeśli ta procedura zwraca dane, jak mogę je złapać w C #?
MA9H
8
@ M009: W takim razie używasz ExecuteReaderlub, ExecuteScalaraby to nazwać.
Guffa,
2
@ M009: Tak, to inny sposób na zrobienie tego samego. Adapter danych używa ExecuteReader.
Guffa
1
@DylanChen: To zależy od ustawień bazy danych. Domyślnie identyfikatory nie rozróżniają wielkości liter.
Guffa
1
@DylanChen: To ustawienie sortowania w bazie danych określa, czy identyfikatory rozróżniają wielkość liter.
Guffa
36

Musisz dodać parametry, ponieważ jest to potrzebne do wykonania 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();
    }            
}
Ravi Gadag
źródło
7
AddWithValue to zły pomysł; SQL Server nie zawsze używa poprawnej długości dla nvarchar lub varchar, powodując niejawną konwersję. Lepiej jest jawnie określić długość parametru, a następnie osobno dodać wartość za pomocą parameter.Value = txtfirstname.
George Stocker
14

cmd.Parameters.Add(String parameterName, Object value)jest teraz przestarzała. Zamiast tego użyjcmd.Parameters.AddWithValue(String parameterName, Object value)

Funkcja Add (nazwa parametru ciągu, wartość obiektu) została wycofana. Użyj AddWithValue (nazwa parametru ciągu, wartość obiektu)

Nie ma różnicy pod względem funkcjonalności. Powodem, dla którego odrzucili na cmd.Parameters.Add(String parameterName, Object value)korzyść, AddWithValue(String parameterName, Object value)jest zapewnienie większej przejrzystości. Oto odniesienie MSDN dla tego samego

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();
    }
  }
}
Rahul Nikate
źródło
2
Czy masz link lub źródło do roszczenia, które cmd.Parameters.Addjest przestarzałe?
David
7
@TonyG: to nieprawda, zaakceptowana odpowiedź używa preferowanego przeciążenia, Addktóre również nie jest przestarzałe. AddWithValuerównież nie jest najlepszym sposobem, ponieważ określa typ parametru z wartości parametru. Często prowadzi to do złych planów wykonania lub nieprawidłowych konwersji. Nie sprawdza też w pierwszej kolejności parametru (np. Wpisz if, Datetimeale przekażesz a String). Widać tutaj, że tylko ten, Addktóry przyjmuje Objectjako drugi argument, jest przestarzały.
Tim Schmelter
2
AddWithValuema taką samą funkcjonalność jak Addz Object, ale nie jest to preferowany sposób. Obaj muszą wywnioskować typ.
Tim Schmelter
2
Masz całkowitą rację, @TimSchmelter. Moje odczytanie tekstu było błędne. Dziękuję za poprawienie mnie. Piszę nowy kod, w którym będę używać Add (). I zmienię mój głos „za” w tej odpowiedzi na „przeciw”, ponieważ Rahul Nikate był w błędzie tak samo jak ja.
TonyG
2
@TimSchmelter Dziękuję za radę. Zmieniłem odpowiedź.
Rahul Nikate
3

Jako alternatywę mam bibliotekę, która ułatwia pracę z 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");
Greg R. Taylor
źródło
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
źródło
0

Dostawcy danych .NET składają się z wielu klas używanych do łączenia się ze źródłem danych, wykonywania poleceń i zwracania zestawów rekordów. Obiekt polecenia w ADO.NET udostępnia szereg metod Execute, których można używać do wykonywania zapytań SQL na różne sposoby.

Procedura składowana to wstępnie skompilowany obiekt wykonywalny, który zawiera co najmniej jedną instrukcję SQL. W wielu przypadkach procedury składowane akceptują parametry wejściowe i zwracają wiele wartości. Wartości parametrów można podać, jeśli zapisano procedurę składowaną w celu ich akceptacji. Przykładowa procedura składowana z akceptacją parametru wejściowego jest podana poniżej:

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

Powyższa procedura składowana akceptuje nazwę kraju (@COUNTRY VARCHAR (20)) jako parametr i zwraca wszystkich wydawców z kraju wejściowego. Po ustawieniu CommandType na StoredProcedure można użyć kolekcji Parameters do zdefiniowania parametrów.

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

Powyższy kod przekazujący parametr kraju do procedury składowanej z aplikacji 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();
        }
    }
}
Sudhakar Rao
źródło
Twoja odpowiedź nie korzysta z wykorzystaniem bloków, które jest najlepszą praktyką. Powinien również istnieć blok try catch, aby poradzić sobie z wszelkimi wyjątkami.
Trisped