7

Soy muy nueva usando LINQ y he hecho pocas cosas, ahorita tengo una consulta SQL que debo implementar en LINQ y no tengo ni idea de cómo se hace.

SELECT Boletas.Boleta, DATEPART(DW, CAST(Boletas.Fecha AS datetime)) AS DiaDeLaSemana, 
       Materiales.Descripcion, Clientes.Nombre, 
       induscomer.NoCliente AS induscomerNoCliente
FROM   Boletas 
       INNER JOIN Materiales 
       ON Boletas.Material = Materiales.Material AND Boletas.Familia = Materiales.Familia 
       INNER JOIN Clientes 
       ON Boletas.NoCliente = Clientes.NoCliente 
       LEFT OUTER JOIN induscomer 
       ON Clientes.NoCliente = induscomer.NoCliente
WHERE  (Boletas.Fecha >= '20170101') AND (Boletas.Fecha <= '20170107') 
       AND (Boletas.Status = 'A')
ORDER BY Boletas.Material

De tal forma que si no existe el correspondiente cliente en la tabla induscomer, entonces induscomerNoCliente sería nulo.

Intenté siguiendo algunas ayudas que encontré hacerlo así:

var boletaQuery = (
    from b in _context.Boletas
    join m in _context.Materiales on b.Material equals m.Material
    join c in _context.Clientes on b.NoCliente equals c.NoCliente
    join i in _context.induscomer on c.NoCliente equals i.NoCliente into indus
    from ind in indus.DefaultIfEmpty()
    where b.Fecha.CompareTo(FechaIni) >= 0
        && b.Fecha.CompareTo(FechaFin) <= 0
        && b.Status.Equals('A')
    select new { 
        b, 
        induscomerNoCliente = ind.NoCliente, 
        NombreCliente = c.Nombre, 
        DescripcionMaterial = m.Descripcion 
    }
);

Pero al hacer boletaQuery.ToList(); me marca el siguiente error:

Excepción no controlada del tipo 'System.NotSupportedException' en System.Data.Entity.dll Información adicional: No se pudo crear un valor de constante de tipo 'System.Object'. Solo se admiten tipos primitivos o tipos de enumeración en este contexto.

Davlio
  • 2,900
  • 1
  • 13
  • 22
Cyndy
  • 147
  • 10
  • A simple vista tu consulta en `LINQ` esta bien estructurada, pero de pronto si tienes problemas con el `where`. No utilices `CompareTo` o `Equals` te recomiendo que utilices `b.Fecha >= fecha && b.Fecha <= fecha && b.Status == 'A'` – Weimar Yamit Moreno Perez Mar 28 '17 at 20:36
  • muchas gracias Weimar Yamit, voy a revisarlo – Cyndy Mar 28 '17 at 22:24
  • @WeimarYamitMorenoPerez hice un abreviado para probar, y pues el problema es en left join, pues me marca el mismo error dejando solamente en el query: var boletaQuery = (from b in _context.Boletas join i in _context.induscomer on b.NoCliente equals i.NoCliente into indus from ind in indus.DefaultIfEmpty() select new { b, induscomerNoCliente = ind.NoCliente} ); – Cyndy Mar 29 '17 at 17:25
  • Cyndy, Intenta por favor lo siguiente: `var boletaQuery = (from b in _context.Boletas join i in _context.induscomer on b.NoCliente equals i.NoCliente into indus from ind in indus.DefaultIfEmpty() select new { b, induscomerNoCliente = (ind == null ? String.Empty : ind.NoCliente)} );` y me cuentas si te sigue mostrando el error. – Weimar Yamit Moreno Perez Mar 29 '17 at 18:45
  • ok, lo checo @WeimarYamitMorenoPerez, gracias – Cyndy Mar 30 '17 at 19:58
  • @WeimarYamitMorenoPerez, ya lo chequé y me marcaba que no hay una conversion implicita de string a int, traté de ponerle Convert.ToInt32(String.Empty), pero al ejecutar el linq marca que "LINQ to Entities no reconoce el método 'Int32 ToInt32(System.String)' del método, y este método no se puede traducir en una expresión de almacén." – Cyndy Mar 30 '17 at 21:41

4 Answers4

4

Existe una herramienta que te puede ayudar, se llama Linqer. Esta herramienta te puede ayudar a convertir un query de SQL a Linq y viceversa.

Te recomiendo que lo utilices, veas el comportamiento que tiene al realizar las conversiones y sobre todo asimiles que es bastante parecido, aunque de primera instancia pareciera que SQL y Linq son totalmente diferentes, no lo veas por ese lado.

De igual forma te recomiendo que revises la documentación oficial (en inglés) y veas cómo empezar a trabajar con Linq.

Phi
  • 9,913
  • 5
  • 25
  • 47
4

Pues muchísimas gracias a todos por sus aportes, siguiendo los consejos de @YanetSilvaFernández, @WeimarYamitMorenoPerez, @Flxtr y luego de un montón de pruebas el LEFT OUTER JOIN ya quedó:

 var boletaQuery =
        from b in _context.Boletas
        join m in _context.Materiales 
        on new { k1 = (int?)b.Familia, k2 = (int?)b.Material } 
        equals new { k1 = (int?)m.Familia, k2 = (int?)m.Material }
        join c in _context.Clientes on b.NoCliente equals c.NoCliente
        join i in _context.induscomer on c.NoCliente equals i.NoCliente into indus
        from ind in indus.DefaultIfEmpty()
        where b.Fecha.CompareTo(FechaIni) >= 0 && b.Fecha.CompareTo(FechaFin) <= 0 
        && b.Status.Equals("A")
        select new
        {
            b,
            DiaDeLaSemana = SqlFunctions.DatePart("DW", b.Fecha),
            DescripcionMaterial = m.Descripcion,
            NombreCliente = c.Nombre,
            ind
        };

Luego cargo los datos a mi estructura en la que definí el campo induscomerNoCliente como int? (que permite nulos) con el siguiente ciclo:

        int? indusnocliente;
        foreach (var item in boletaQuery.ToList())
        {
            if (item.ind == null)
            {
                indusnocliente = null;
            }
            else
            {
                indusnocliente = item.ind.NoCliente;
            }
            lsOperacion.Add(new OperacionCL
            {
                Base = item.b.Base,
                Boleta = item.b.Boleta,
                Fecha = item.b.Fecha,
                Contado = (float)item.b.Contado.Value,
                Credito = (float)item.b.Credito.Value,
                Material = (int)item.b.Material.Value,
                Neto = (float)item.b.Neto.Value,
                Total = (float)item.b.Total.Value,
                NombreCliente = item.NombreCliente,
                DescripcionMaterial = item.DescripcionMaterial,
                DoW = (int)item.DiaDeLaSemana, 
                induscomerNoCliente = indusnocliente
            });
        }

Saludos y gracias de nuevo

Cyndy
  • 147
  • 10
  • Es bueno que hayas encontrado tu solución pero es aún mejor que la hayas compartido con la comunidad :D – Phi Mar 31 '17 at 00:49
2

Esto me funcionó:

var context = new DBContext();
            var boletaQuery =
                from b in context.Boletas
                from m in context.Materiales
                from c in context.Clientes
                join i in context.Induscomer on c.NoCliente equals i.NoCliente into indus
                from ind in indus.DefaultIfEmpty()
                where
                b.Material == m.Material && b.Familia == m.Familia && b.NoCliente == c.NoCliente && b.Fecha >= fechaIni &&
                b.Fecha <= fechaFin && b.Status.Equals('A')
                select new
                {
                    b.Boleta,
                    DiaDeLaSemana = SqlFunctions.DatePart("DW", b.Fecha),
                    m.Descripcion,
                    NombreCliente = c.Nombre,
                    induscomerNoCliente = ind.NoCliente
                };
            var result = boletaQuery.ToList();

...........................

var boletaQuery =
            from b in context.Boletas
            join m in context.Materiales on new { b.Familia, b.Material } equals new { m.Familia, m.Material }
            join c in context.Clientes on b.NoCliente equals c.NoCliente
            join i in context.Induscomer on c.NoCliente equals i.NoCliente into indus
            from ind in indus.DefaultIfEmpty()
            where b.Fecha >= fechaIni && b.Fecha <= fechaFin && b.Status == 'A'
            select new
            {
                b.Boleta,
                DiaDeLaSemana = SqlFunctions.DatePart("DW", b.Fecha),
                m.Descripcion,
                NombreCliente = c.Nombre,
                induscomerNoCliente = ind.NoCliente
            };

......................... Este es el plan de ejecución de ambas consultas en sql y tienen el mismo costo. (¿Cual es la diferencia entre joins implícitos y explícitos?)

JOIN

WHERE

  • Hola Yanet, utilizar `join` implicitos con Linq no estoy seguro que realmente funcione, y suponiendo que funcione es una funcionalidad deprecada y por tal motivo se recomienda utilizar los `join` explicitos :) – Phi Mar 30 '17 at 16:36
  • El código funciona, pues lo probé antes de subir la respuesta. Con respecto a los joins implicitos o explicitos tienes toda la razón, acá les pongo como ponerlo todo como explicito: – Yanet Silva Fernández Mar 30 '17 at 18:14
  • muchas gracias @YanetSilvaFernández, lo voy a probar, luego te cuento – Cyndy Mar 30 '17 at 18:30
  • Cindy, sería bueno saber los tipos de datos con los que estas trabajando en cada unas de las columnas implicadas en la consulta. – Yanet Silva Fernández Mar 30 '17 at 18:37
  • si @YanetSilvaFernández, de hecho por allí tengo detalles, por ejemplo la **Fecha** es varchar(8) trae datos como _'20170101'_, *Familia (int,null)*, *Material (int,null)*, *NoCliente (int,null)*, *Boleta (int, not null)*, *Clientes.Nombre varchar(75)*, *Materiales.Descripcion varchar(50)* – Cyndy Mar 30 '17 at 18:51
  • Básicamente son los mismo tipos de datos que utilice para el ejemplo. Si no te funciona me avisas y te mando el proyecto por correo y revisas. – Yanet Silva Fernández Mar 30 '17 at 19:03
  • muchas gracias @YanetSilvaFernández, ejecuté la primera opción que me envias (join implicito) y me sale exactamente el mismo error que me salía (el que publiqué en el post) y con la segunda opción (join explicito) no me permite el join que lleva el on new { b.Familia, b.Material } equals new { m.Familia, m.Material }, pues me pone subraya en rojo el join y dice: "El tipo de una de las expresiones de la cláusula join es incorrecto. No se pudo realizar inferencia de tipos en la llamada a join" – Cyndy Mar 30 '17 at 19:16
  • @YanetSilvaFernández , revisando las tablas del join en Basculas, Familia y Material son de tipo (int, null) y en Materiales son (int, not null) pues forman parte del pk, será por eso? – Cyndy Mar 30 '17 at 19:16
  • [Continuemos el debate en el chat](http://chat.stackexchange.com/rooms/56324/discussion-between-yanet-silva-fernandez-and-cyndy). – Yanet Silva Fernández Mar 30 '17 at 19:23
2

Interesante tu pregunta, pero fuera de averiguar como convertirla, sugiero que pruebes este software:

LINQPad

Es una herramienta muy útil, te puede servir para probar el código de linq directo sobre la conexión de la BD:

introducir la descripción de la imagen aquí

introducir la descripción de la imagen aquí

introducir la descripción de la imagen aquí

Este otro programa hace lo que necesitas convertir SQL to linq:

sqltolinq

Al parecer son de paga ambos :(

Cristina Carrasco
  • 5,152
  • 1
  • 15
  • 35