Llamar a un procedimiento almacenado con parámetro en c #

138

Puedo eliminar, insertar y actualizar mi programa e intento hacer una inserción llamando a un procedimiento almacenado creado desde mi base de datos.

Este es un inserto de botón que hago que funcione bien.

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

Este es el inicio del botón para llamar al procedimiento nombrado sp_Add_contactpara agregar un contacto. Los dos parámetros para sp_Add_contact(@FirstName,@LastName). Busqué en Google algún buen ejemplo, pero no encontré nada interesante.

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
fuente
8
Solo un poco más de información: no debe nombrar los procedimientos almacenados de su aplicación con un prefijo sp_, como el anterior con sp_Add_contact. el prefijo sp_ es una convención de nomenclatura de procesos almacenados del sistema que, cuando SQL lo vea, buscará primero en todos los procedimientos almacenados del sistema antes de cualquier aplicación o espacio de usuario almacenado. Como cuestión de rendimiento, si le importa eso en su aplicación, el prefijo sp_ degradará sus tiempos de respuesta.
Robert Achmann

Respuestas:

265

Es casi lo mismo que ejecutar una consulta. En su código original, está creando un objeto de comando, colocándolo en la cmdvariable y nunca lo usa. Aquí, sin embargo, lo usará en lugar de da.InsertCommand.

Además, utilice a usingpara todos los objetos desechables, de modo que esté seguro de que están dispuestos correctamente:

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
fuente
77
pero si este procedimiento devuelve datos, ¿cómo puedo capturarlos en C #?
MA9H
8
@ M009: Luego lo usa ExecuteReadero ExecuteScalarpara llamarlo.
Guffa
2
@ M009: Sí, esa es otra forma de hacer lo mismo. El adaptador de datos utiliza ExecuteReader.
Guffa
1
@DylanChen: Eso depende de la configuración de la base de datos. La configuración predeterminada es que los identificadores no distinguen entre mayúsculas y minúsculas.
Guffa
1
@DylanChen: es la configuración de clasificación de la base de datos que determina si los identificadores distinguen entre mayúsculas y minúsculas.
Guffa
36

Debe agregar parámetros, ya que es necesario para que el SP se ejecute

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
fuente
77
AddWithValue es una mala idea; SQL Server no siempre usa la longitud correcta para nvarchar o varchar, lo que provoca una conversión implícita. Es mejor especificar la longitud del parámetro explícitamente y luego agregar el valor por separado usando parameter.Value = txtfirstname.
George Stocker
14

cmd.Parameters.Add(String parameterName, Object value)está en desuso ahora. En lugar de usarcmd.Parameters.AddWithValue(String parameterName, Object value)

Agregar (String parameterName, Object value) ha quedado en desuso. Use AddWithValue (String parameterName, Object value)

No hay diferencia en términos de funcionalidad. La razón por la que desaprobaron el cmd.Parameters.Add(String parameterName, Object value)favor AddWithValue(String parameterName, Object value)es para dar más claridad. Aquí está la referencia de MSDN para el mismo

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
fuente
2
¿Tiene un enlace o fuente para el reclamo que cmd.Parameters.Addestá en desuso?
David
77
@TonyG: eso no es cierto, la respuesta aceptada utiliza la sobrecarga preferida de la Addcual tampoco está en desuso. AddWithValueTampoco es la mejor manera, ya que infiere el tipo de parámetro del valor del parámetro. Esto a menudo conduce a malos planes de ejecución o conversiones incorrectas. Tampoco valida el parámetro en primer lugar (escriba fe si Datetimepero pasa a String). Puede ver aquí que solo lo Addque toma un Objectsegundo argumento está en desuso.
Tim Schmelter
2
AddWithValuetiene la misma funcionalidad que Addcon Object, pero no es la forma preferida. Ambos necesitan inferir el tipo.
Tim Schmelter
2
Tienes toda la razón, @TimSchmelter. Mi lectura del texto fue errónea. Gracias por la corrección. Estoy escribiendo un nuevo código donde usaré Add (). Y cambiaré mi voto positivo en esta Respuesta a un voto negativo, ya que Rahul Nikate estaba tan equivocado como yo.
TonyG
2
@TimSchmelter Gracias por tu consejo. He editado mi respuesta.
Rahul Nikate
3

Como alternativa, tengo una biblioteca que facilita el trabajo con 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
fuente
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();
        }
}
usuario6916720
fuente
0

Los proveedores de datos .NET consisten en una serie de clases utilizadas para conectarse a una fuente de datos, ejecutar comandos y devolver conjuntos de registros. El objeto de comando en ADO.NET proporciona una serie de métodos de ejecución que se pueden utilizar para realizar las consultas SQL en una variedad de modas.

Un procedimiento almacenado es un objeto ejecutable precompilado que contiene una o más instrucciones SQL. En muchos casos, los procedimientos almacenados aceptan parámetros de entrada y devuelven múltiples valores. Los valores de los parámetros se pueden proporcionar si se escribe un procedimiento almacenado para aceptarlos. A continuación se muestra un procedimiento almacenado de muestra con el parámetro de entrada de aceptación:

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

El procedimiento almacenado anterior acepta un nombre de país (@COUNTRY VARCHAR (20)) como parámetro y devuelve todos los publicadores del país de entrada. Una vez que CommandType se establece en StoredProcedure, puede usar la colección Parameters para definir parámetros.

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

El código anterior que pasa el parámetro de país al procedimiento almacenado desde la aplicación 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
fuente
Su respuesta no utiliza el uso de bloques, que es una mejor práctica. Además, debe haber un bloque try catch para tratar cualquier excepción.
Trisped