none
Validar datos ingresados a una Grilla ASP.NET C# RRS feed

  • Pregunta

  • Hola! Cómo podría validar que los datos que ingreso en una Grilla no se repitan, por medio de su ID. Mi código es el siguiente:

     protected void Button1_Click(object sender, EventArgs e)
        {
            int Slpcode = 0;
            if (!string.IsNullOrEmpty(TextBox4.Text))
            {
                if (!int.TryParse(TextBox4.Text, out Slpcode))
                {
                    lblMensaje.Text = ("El ID debe ser un valor numérico");
                    return;
                }
            }
                try
                {
                    cn = new OdbcConnection(Conexion);
                    using (cmd = new OdbcCommand(MyString, cn))
                        cn.Open();
                    using (cmd = new OdbcCommand("INSERT INTO Vendedores(SlpCode, SlpName, Memo) values ('" + TextBox4.Text + "', '" + TextBox1.Text + "', '" + List.SelectedItem.ToString() + "')" +
                        "INSERT INTO Usuarios(SlpCode, passw) values ('" + TextBox4.Text + "', '" + TextBox2.Text + "')", cn))
                    {
                        OdbcDataReader d = cmd.ExecuteReader();
                        if (d.Read())
                        {
                            lblMensaje.Text = ("Error al guardar datos.");
                            Limpiar();
                        }
                        else
                        {
    
                            lblMensaje.Text = ("Datos correctos.");
                            Limpiar();
                        }
                        Grilla.DataBind();
                    }
                }
                catch (Exception ex)
                {
                    Response.Write(ex.ToString());
                }
                finally
                {
                    cn.Close();
                }
            //}
        }

    miércoles, 30 de mayo de 2018 17:42

Respuestas

  • Como menciona WebJose no deberias concatenar SQL, eso te hace estar demasiado expuesta a SQL Injection!!!! en tu formulario.

    Por ponerte un ejemplo que pasaria si en el TextBox4 ponemos un valor como: ";DROP TABLE Usuarios; --"

    En tu lugar podrias utilizar un procedimiento almacenado con la sintaxis:

    MERGE [tu tabla]
       WHEN MATCHED THEN
                UPDATE SET
                       --SI EL ID YA EXISTE SOLO ACTUALIZAS LOS VALORES
            WHEN NOT MATCHED THEN
    --SI EL ID NO EXISTE ENTONCES INSERTAS LOS VALORES COMO UN NUEVO REGISTRO

    Como vez mediante un sp te quitarias el problema de validar la Grilla pues si el id ya existe lo que hara el merge es actualizar, y si no existe lo que hara es insertar el registro.

    No deberias hacer caso omiso de las buenas Practicas que los expertos del foro te recomiendan.

    Saludos



    Carlos Aldi


    • Editado Carlos Aldi jueves, 31 de mayo de 2018 17:06
    • Marcado como respuesta Elizabeth X viernes, 8 de junio de 2018 3:07
    jueves, 31 de mayo de 2018 16:59

Todas las respuestas

  • Algunas preguntas y anotaciones:

    1. ¿Es un botón por línea en la grilla, o es un único botón y punto?
    2. No concatene SQL.  Eso es una práctica terrible.  Aprenda a usar objetos de comando con parámetros (consultas parametrizadas).
    3. Dice no querer elementos repetidos, y según parece, la definición de "repetido" es que su ID sean iguales.  Para poder determinar si un elemento ya existe, hay que definir el "dónde".  En su caso puedo imaginar 2 lugares posibles:  Como es una grilla, tal vez no desea que la grilla contenga dos elementos con el mismo ID; o bien, la base de datos, que sería que la grilla provee nuevos elementos a una tabla y la tabla debe rechazar elementos duplicados basándose en el campo ID.  ¿Cuál es el correcto?
    4. Su consulta SQL consiste en 2 INSERT y 0 SELECT, sin embargo usted utiliza el método ExecuteReader() para ejecutar la consulta.  Esto es incorrecto pues no hay datos que leer (no hay SELECT alguno) y por lo tanto no es necesario obtener un objeto lector (OdbcDataReader).  Debe utlizar ExecuteNonQuery() en su lugar.

    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    miércoles, 30 de mayo de 2018 22:48
    Moderador
  • El botón es el que guarda los datos en sql y los muestra en la grilla. Y pues me resulta bastante bien la consulta al final, lo único que quiero saber es qué o cómo le hago para que el ID no se repita, no se guarde ni en la base de datos ni en la grilla y ejecuto ExecuteReader() para poder indicarle al usuario si esta correcto o no. No se si puedas ayudarme a explicarme con algún ejemplo o algo. Eh visto varios videos y cosillas en internet pero son muy viejos los ejemplos y usan demasiadas clases y métodos. Simplemente buscaba la manera más sencilla.

    Tengo una duda, al no utilizar consultas paramentadas y hacerlo de la forma en que lo hago consume más memoria o qué es lo que sucede al ocuparlo de esa manera?

    jueves, 31 de mayo de 2018 13:31
  • Como menciona WebJose no deberias concatenar SQL, eso te hace estar demasiado expuesta a SQL Injection!!!! en tu formulario.

    Por ponerte un ejemplo que pasaria si en el TextBox4 ponemos un valor como: ";DROP TABLE Usuarios; --"

    En tu lugar podrias utilizar un procedimiento almacenado con la sintaxis:

    MERGE [tu tabla]
       WHEN MATCHED THEN
                UPDATE SET
                       --SI EL ID YA EXISTE SOLO ACTUALIZAS LOS VALORES
            WHEN NOT MATCHED THEN
    --SI EL ID NO EXISTE ENTONCES INSERTAS LOS VALORES COMO UN NUEVO REGISTRO

    Como vez mediante un sp te quitarias el problema de validar la Grilla pues si el id ya existe lo que hara el merge es actualizar, y si no existe lo que hara es insertar el registro.

    No deberias hacer caso omiso de las buenas Practicas que los expertos del foro te recomiendan.

    Saludos



    Carlos Aldi


    • Editado Carlos Aldi jueves, 31 de mayo de 2018 17:06
    • Marcado como respuesta Elizabeth X viernes, 8 de junio de 2018 3:07
    jueves, 31 de mayo de 2018 16:59
  • Pero si se actualiza, automáticamente se actualizarán los datos? Es que realmente la página da de alta a nuevos usuarios, actualiza y elimina. Pero si utilizo algo así, como implemento en el código de la pagina? o simplemente se ejecuta al instante?

    jueves, 31 de mayo de 2018 17:08
  • Si haces un procedimiento almacenado con el Merge y este detecta que le mandas campos llaves, que ya existen automáticamente actualizara el registro mediante un Update, si los campos llave que mandas no existen en la tabla entonces ejecuta un Insert Into.



    Carlos Aldi

    jueves, 31 de mayo de 2018 17:17
  • Desafortunadamente no obtuve respuestas claras a mis preguntas.  En este punto asumiré que es un único botón, y no un botón por fila de la grilla.

    Tampoco me dijo dónde no puede repetirse el ID.  Como expliqué antes, hay dos posibilidades:  Que el usuario haya digitado 2 ID's idénticos en la grilla, o que hayan ID's en base de datos que son idénticos a los que el usuario ha digitado en la grilla.  Asumiré entonces que es la opción #2.

    Como asumí que es un único botón, y que no veo FindControl() por ninguna parte, imagino que en realidad lo que tiene es un formulario que inserta/actualiza registros uno a uno, y luego la grilla es de sólo lectura y simplemente muestra el estado actual de la tabla correspondiente en el servidor de base de datos.

    Integrando la segunda suposición, sí, Carlos Aldi le da una opción viable:  Tratar un duplicado como una actualización.  Si no desea hacer eso, y la tabla en base de datos tiene un índice único sobre el campo de ID que no debe repetirse, pues un INSERT fallará y ocurrirá una excepción, que puede ser detectada y usarse para informarle al usuario que el ID que ha digitado ya existe.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    jueves, 31 de mayo de 2018 18:09
    Moderador
  • Hola de nuevo! 

    Jeje, disculpen que otra vez moleste pero soy nueva con ésto de las páginas y bases de datos. 

    Ya cree un procedimiento almacenado de ésta manera:

    Aquí tengo Nombres de vendedores, tipo de usuario y el ID

    USE [Ventas_catavina]
    GO
    /****** Object:  StoredProcedure [dbo].[InsertaUsuario]    Script Date: 06/06/2018 10:27:20 a.m. ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[InsertaUsuario](
    @id int = 0,
    @nombre nvarchar(155),
    @memo nvarchar (50)
    )
    AS
    BEGIN
    	Set NOCOUNT ON
    
    	MERGE [Vendedores] as TARGET
    	USING (SELECT @id, @nombre, @memo) AS SOURCE(SlpCode, SlpName, Memo)
    	ON (@id = SOURCE.SlpCode)
    	WHEN MATCHED THEN
    		UPDATE SET @nombre = SOURCE.SlpName,
    				   @memo = SOURCE.Memo
    	WHEN NOT MATCHED THEN
    		INSERT (SlpCode, SlpName, Memo) values (@id, @nombre, @memo);
    END

    Y este es para Usuarios(donde solo tengo contraseña y ID)

    USE [Ventas_catavina]
    GO
    /****** Object:  StoredProcedure [dbo].[Usuario]    Script Date: 06/06/2018 10:28:50 a.m. ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[Usuario](
    @id2 int = 0,
    @pass nvarchar (50)
    )
    AS
    BEGIN
    	Set NOCOUNT ON
    
    	MERGE [Usuarios] as TARGET
    	USING (SELECT @id2, @pass) AS SOURCE(SlpCode, passw)
    	ON (@id2 = SOURCE.SlpCode)
    	WHEN MATCHED THEN
    		UPDATE SET  @pass = SOURCE.passw
    	WHEN NOT MATCHED THEN
    		INSERT (SlpCode, passw) values (@id2, @pass);
    END

    Y en el método tengo ésto:

    protected void Button3_Click(object sender, EventArgs e)
        {
            int Slpcode = 0;
            if (!string.IsNullOrEmpty(TxtID.Text))
            {
                if (!int.TryParse(TxtID.Text, out Slpcode))
                {
                    lblMensaje.Text = ("El ID debe ser un valor numérico");
                    return;
                }
                using (cn)
                {
                    cn.Open();
                    OdbcCommand cmd = new OdbcCommand("InsertaUsuario" + "Usuario", cn);
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("id", TxtID.Text);
                    cmd.Parameters.AddWithValue("nombre", TxtNombre.Text);
                    cmd.Parameters.AddWithValue("memo", List.SelectedItem.ToString());
                    cmd.Parameters.AddWithValue("id2", TxtID.Text);
                    cmd.Parameters.AddWithValue("pass", TxtContra);
                    OdbcDataReader da = cmd.ExecuteReader();
                    if (da.Read())
                    {
                        lblMensaje.Text = ("Error al guardar datos.");
                        Limpiar();
                    }
                    else
                    {
                        lblMensaje.Text = ("Datos correctos.");
                        Limpiar();
                    }
                    Grilla.DataBind();
    
                }
            }
            
        }

    Es un único botón para insertar los datos y la grilla si es de solo lectura. Pero al momento de ejecutar me marca error en "OdbcDataReader da = cmd.ExecuteReader();"

    No se si puedan ayudarme! O decirme que errores tengo

    miércoles, 6 de junio de 2018 15:31
  • Nuevamente como te respondian en días anteriores es incorrecto que uses ExecuteReader() pues no hay datos que leer, pues tu procedimiento ES DE INSERCIÓN!!!! y no de Select por lo que deberias usar ExecuteNonQuery().

    Y por Favor he visto que te han apoyado en varios Hilos del foro pero no te tomas la molestia de calificar las respuestas.

    Saludos


    Carlos Aldi

    miércoles, 6 de junio de 2018 15:37
  • Pero si uso ExecuteNonQuery me sigue sin validar ni insertar nada. Por eso preguntaba si mis procedimientos en sql estaban correctos.

    Y si aveces no marco es porque ninguno me dio respuesta que ayudara, en otros porque no me permite insertar imágenes y lo deje así, pero las elimino entonces. De verdad no pensé que "calificar" era más importante que dar respuestas que se necesitan realmente. Cuando me han dado respuesta lo hago.

    miércoles, 6 de junio de 2018 15:46
  • Veo inmediatamente que la cláusula ON del MERGE es incorrecta.  La idea del ON es relacionar la tabla fuente (SOURCE) con la tabla destino (TARGET).  Su ON solamente menciona SOURCE, pero no menciona TARGET.  Mi suposición sería que debe ser ON TARGET.SlpCode = SOURCE.SlpCode.

    Nuevamente, debe utilizar ExecuteNonQuery() y no ExecuteReader().

    Veo que ya ha pasado a parámetros, que es bueno.  Encontrará innumerables ejemplos de esto usando AddWithValue(), que es lo que usted también ha usado.  Le adelanto que no es la mejor opción.  La mejor opción es Parameters.Add("nombreDeParametro", <tipo de dato>).Value = <valor>.  Hay razones para ello que no vienen hoy al caso.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    miércoles, 6 de junio de 2018 23:21
    Moderador
  • Ah y veo que el nombre del procedimiento almacenado dice "InsertarUsuario" + "Usuario", que dará como resultado "InsertarUsuarioUsuario", que NO es el nombre de su procedimiento almacenado.  No sé por qué tiene usted esa concatenación, pero debe eliminarla para obtener el nombre correcto del procedimiento almacenado.

    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    miércoles, 6 de junio de 2018 23:23
    Moderador
  • El problema es que tengo dos tablas, una para contraseñas y su ID, y otra para nombre de usuario, tipo de usuario, y su ID también. Y en la pagina que estoy haciendo, al guardar un nuevo usuario, borrarlo o actualizar sus datos pues se ocupan las dos tablas.

    Entonces ¿Existe alguna forma de llamar las dos tablas en un solo procedimiento? y si no es así, entonces ¿cómo mando a llamar los dos procedimientos en un solo botón pero que inserten al mismo tiempo?

    jueves, 7 de junio de 2018 13:14
  • Necesita un comando por cada procedimiento almacenado, o bien escribir un único procedimiento almacenado que haga ambas cosas.  Si opta por la segunda opción, deberá incrementar la cantidad de parámetros para aceptar los datos necesarios para ambas tablas.

    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    jueves, 7 de junio de 2018 17:50
    Moderador