none
Maestro detalle RRS feed

  • Pregunta

  • A que se debe este error

    public static DataSet PedidoDetalle(string idCia, DateTime fecha)
            {
                using (SqlConnection cn = Conexion.Conectar("default"))
                {
                    using (SqlCommand cmd = cn.CreateCommand())
                    {
                        cmd.CommandText =
                            //"SELECT p.Venta_Id AS Id, p.Nro_Doc, CONVERT(varchar(15), CAST(p.Fecha_Doc as time), 100) AS Hora, c.Nombre As Cliente, pe.Nombre AS Moso, p.Lug_Ent_Id AS Mesa," +
                            //" p.Estado_Id AS Estado FROM Pedidos p INNER JOIN Clientes c ON p.Cliente_Id = c.Cliente_Id CROSS JOIN Personal pe" +
                            //" WHERE p.Cia_Id=@Cia_Id AND p.Fecha_Doc=@Fecha"; 
                            "SELECT p.Venta_Id, p.Nro_Doc, CONVERT(varchar(15), CAST(p.Fecha_Doc AS time), 100) AS Hora, c.Nombre AS Cliente, c.Nombre AS Moso, p.Lug_Ent_Id AS Mesa," + 
                            " es.Descripcion AS Estado" +
                            " FROM Pedidos AS p" + 
                            " INNER JOIN Clientes AS c ON p.Cliente_Id = c.Cliente_Id" +
                            " INNER JOIN EstadoServ ES ON p.Estado_Id = es.Estado_Id" +
                            " WHERE p.Cia_Id=@Cia_Id AND p.Fecha_Doc=@Fecha";
                        cmd.Parameters.AddWithValue("@Cia_Id", idCia);
                        cmd.Parameters.AddWithValue("@Fecha", fecha);
                        using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                        {
                            DataSet ds = new DataSet();
                            // Llenar DataTables en el DataSet
                            da.Fill(ds, "Pedidos");
                            cmd.CommandText =
                                "SELECT pd.Venta_Id, pd.Producto_Id AS Codigo, p.Nombre AS Descripción, pd.Cantidad AS Cantidad, pd.Imp_Uni AS Precio, pd.Imp_Tot AS Importe" +
                                " FROM Pedidos_Detalle pd INNER JOIN" +
                                " Productos p ON pd.Producto_Id = p.Producto_Id";
                               
                            da.Fill(ds, "Pedidos_Detalle");
    
                            // Establecer relaciones
                            DataColumn colPadre = ds.Tables["Pedidos"].Columns["Venta_Id"];
                            DataColumn colHijo = ds.Tables["Pedidos_Detalle"].Columns["Venta_Id"];
                            DataRelation Relacion = new DataRelation("DetallePedidos", colPadre, colHijo);
                            ds.Relations.Add(Relacion); ==> Error
    
                            //DataTable dt = new DataTable();
                            //da.Fill(dt);
                            return ds;
                        }
                    }
                }
            }

    Error : No se puede habilitar esta restricción ya que todos los valores no tienen los valores primarios correspondientes.


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    miércoles, 9 de abril de 2014 14:06

Respuestas

  • Lo de los métodos da igual. Esencialmente, tienes que hacer 3 cosas con un DataSet:

    - Cargar la tabla de cabeceras

    - Cargar la tabla de detalle

    - Añadir una relación entre las dos tablas

    Con tal de que las tres cosas las hagas sobre el mismo DataSet, da igual si el código que las hace está todo escrito en un mismo procedimiento o está separado en tres. Evidentemente, si el código lo troceas en tres procedimientos, tendrás que pasarles como argumento el DataSet, o declararlo en una variable gobal, de forma que los tres procedimientos operen sobre el mismo objeto.

    Si planeas refrescar la cabecera periódicamente, ten presente que si durante el proceso de refresco ocurre en algún momento que borras una línea de cabecera de la cual colgaban líneas de detalle, se producirá un error (si has creado la relación entre tablas), porque en ese momento esas líneas de detalle no tendrían ninguna cabecera. Opcionalmente, al crear la relación puedes configurarla con borrados en cascada, es decir, que si se borra una cabecera se borren automáticamente sus detalles. En ese caso, no se produciría ningún error.

    • Marcado como respuesta Pedro Ávila jueves, 10 de abril de 2014 2:25
    jueves, 10 de abril de 2014 2:20
    Moderador
  • Termine haciendolo así y quedo bien.

    Vale, pero fíjate que con este último código que has escrito ya no estás creando la relación entre tablas. Era precisamente esa relación la que te estaba detectando los errores de incoherencia entre las dos tablas (es decir, en el maestro/detalle tenías registros de detalle que no colgaban de ningún maestro). Como ahora ya no tienes la relación, si se produce la inconsistencia entre los datos, el programa la dejará pasar sin darte ningún error. Es decir, si cargas datos en la tabla de detalle que no se corresponden con un maestro, ahora te los carga sin dar un error. Pero claro, luego cuando te pongas a trabajar con esos datos inconsistentes, los resultados previsiblemente no serán los deseados. No es razonable arreglar los errores por el expeditivo método de suprimir la parte del código que sirve para detectar la existencia de esos errores.

    • Marcado como respuesta Pedro Ávila jueves, 10 de abril de 2014 2:25
    jueves, 10 de abril de 2014 1:23
    Moderador

Todas las respuestas

  • El error significa que los datos que tienes cargados hasta el momento NO CUMPLEN la restricción que quieres establecer entre las tablas. Es decir, que en la tabla hija existe al menos un registro que no tiene correspondencia en la tabla madre.

    Una posible razón para que eso ocurra es que al cargar la tabla de pedidos estás haciendo un inner join entre varias tablas. Alguno de esos joins podría no encontrar correspondencia en la correspondiente tabla hija, y entonces el registro de pedidos no se devolvería, con lo que no se cargaría ese Venta_Id en la tabla madre del dataset. Si luego recoges detalles de ese pedido para la tabla de detalles, pues te encontrarías que la tabla de detalles en el dataset no tiene correspondencia para ese registro en la tabla madre.

    Eso es solo un ejemplo de lo que puede pasar. No se puede determinar cuáles son los registros que faltan solo con examinar el código fuente. Tendrás que examinar los datos con el debugger (o enviando las SELECT directamente al servidor desde SSMS), ver qué registros se han cargado en cada tabla, y de ahí deducir cuáles faltan y por qué faltan.

    miércoles, 9 de abril de 2014 14:15
    Moderador
  • Hola Alberto no he podido dar con la solución todo el dia en este rollo. lo que hice fue organizar bien las consultas, los tablas tienen datos pero no se como solucionarlo


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    miércoles, 9 de abril de 2014 17:22
  • Sí, claro que las tablas tienen datos. Si estuvieran vacías te dejaría establecer la relación sin ningún problema y no daría error. El problema es que has traído datos a la tabla de detalle del dataset, y alguno de esos datos no tiene correspondencia con ninguno de los datos que has traído a la tabla maestra dataset.

    No tiene remedio sencillo, más que revisar cuidadosamente los registros que has traído a la tabla de detalle, examinar cuáles son los valores de sus Venta_Id, y luego buscar esos Venta_Id en la tabla madre. Seguro que alguno de ellos falta. Y a continuación examinar las consultas que supuestamente deberían haber traído desde el servidor de base de datos esos registros faltantes, a ver por qué no se están cumpliendo las condiciones y no se han recibido esos valores.

    miércoles, 9 de abril de 2014 20:31
    Moderador
  • Alberto

    Termine haciendolo así y quedo bien.

    public static DataTable tPedido(string idCia, DateTime fecha)
            {
                using (SqlConnection cn = Conexion.Conectar("default"))
                {
                    cn.Open();
                    using(SqlCommand cmd = cn.CreateCommand())
                    {
                        // " DATEDIFF(mi, v.Fecha_Doc, GETDATE()) AS [T Atención], v.Fecha_Doc AS Fecha, c.Nombre AS Cliente, v.Lug_Ent_Id,e.Descripcion" +
                        cmd.CommandText =
                        "SELECT DISTINCT v.Venta_Id AS Id, v.Nro_Doc AS Pedido, CONVERT(varchar(10), CAST(v.Fecha_Doc as time), 100) AS [H Ingreso]," +
                            " DATEDIFF(mi, v.Fecha_Doc, GETDATE()) AS [T Atención], c.Nombre AS Cliente, ps.Nombre AS Moso, v.Lug_Ent_Id AS Mesa, e.Descripcion AS Estado" +
                            " FROM Pedidos v" +
                            " INNER JOIN Clientes c ON v.Cliente_Id = c.Cliente_Id" +
                            " INNER JOIN Personal ps ON v.Vendedor_Id = ps.Personal_Id" +
                            " INNER JOIN EstadoServ e ON v.Estado_Id = e.Estado_Id" +
                            " WHERE v.Cia_Id=@Cia_Id AND v.Fecha_Doc=@Fecha_Doc";
    
                        cmd.Parameters.AddWithValue("@Cia_Id", idCia);
                        cmd.Parameters.AddWithValue("@Fecha_Doc", fecha);
                        using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                        {
                            DataTable t = new DataTable();
                            da.Fill(t);
                            return t;
                        }
                    }
                }
            }
    
    
            public static DataTable tPedidoDetalle(string idVenta)
            {
                using (SqlConnection cn = Conexion.Conectar("default"))
                {
                    cn.Open();
                    using (SqlCommand cmd = cn.CreateCommand())
                    {
                        cmd.CommandText =
                            "SELECT vd.Venta_Id AS Id, p.Producto_Id AS Codigo, p.Nombre AS Descripción, vd.Cantidad, vd.Imp_Uni AS Precio, vd.Imp_Tot AS Importe" +
                                " FROM Pedidos_Detalle vd" +
                                " INNER JOIN Productos p ON vd.Producto_Id = p.Producto_Id";
                        
                        using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                        {
                            DataTable t = new DataTable();
                            da.Fill(t);
                            return t;
                        }
                    }
                }
            }

    Un método para cabecera y otro para detalle.


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    miércoles, 9 de abril de 2014 23:44
  • Termine haciendolo así y quedo bien.

    Vale, pero fíjate que con este último código que has escrito ya no estás creando la relación entre tablas. Era precisamente esa relación la que te estaba detectando los errores de incoherencia entre las dos tablas (es decir, en el maestro/detalle tenías registros de detalle que no colgaban de ningún maestro). Como ahora ya no tienes la relación, si se produce la inconsistencia entre los datos, el programa la dejará pasar sin darte ningún error. Es decir, si cargas datos en la tabla de detalle que no se corresponden con un maestro, ahora te los carga sin dar un error. Pero claro, luego cuando te pongas a trabajar con esos datos inconsistentes, los resultados previsiblemente no serán los deseados. No es razonable arreglar los errores por el expeditivo método de suprimir la parte del código que sirve para detectar la existencia de esos errores.

    • Marcado como respuesta Pedro Ávila jueves, 10 de abril de 2014 2:25
    jueves, 10 de abril de 2014 1:23
    Moderador
  • Es que trate de salir del paso pero viendolo como me explicas tienes toda la razón, este problema me demostro que me falta en sql y eso que al parecer es algo sencillo.

    Entonces se debe hacer con una relación, para que los datos sean consistentes, pero es necesario tener los dos metodos en uno solo como lo estaba haciendo al principio.

    Como crearías el método que yo estaba haciendo, me puedes mostrar un ejemplo, la cabecera lo voy a refrescar cada 8 segundos en cambio el detalle no.

    Alguna idea.


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    jueves, 10 de abril de 2014 1:30
  • Lo de los métodos da igual. Esencialmente, tienes que hacer 3 cosas con un DataSet:

    - Cargar la tabla de cabeceras

    - Cargar la tabla de detalle

    - Añadir una relación entre las dos tablas

    Con tal de que las tres cosas las hagas sobre el mismo DataSet, da igual si el código que las hace está todo escrito en un mismo procedimiento o está separado en tres. Evidentemente, si el código lo troceas en tres procedimientos, tendrás que pasarles como argumento el DataSet, o declararlo en una variable gobal, de forma que los tres procedimientos operen sobre el mismo objeto.

    Si planeas refrescar la cabecera periódicamente, ten presente que si durante el proceso de refresco ocurre en algún momento que borras una línea de cabecera de la cual colgaban líneas de detalle, se producirá un error (si has creado la relación entre tablas), porque en ese momento esas líneas de detalle no tendrían ninguna cabecera. Opcionalmente, al crear la relación puedes configurarla con borrados en cascada, es decir, que si se borra una cabecera se borren automáticamente sus detalles. En ese caso, no se produciría ningún error.

    • Marcado como respuesta Pedro Ávila jueves, 10 de abril de 2014 2:25
    jueves, 10 de abril de 2014 2:20
    Moderador