none
.Net - C#: Entity Framework Querys complejos y dinamicos

    Pregunta

  • Saludos a todos.

    Estoy empezando a estudiar Entity Framework y me han surgido un par de dudas:

    Con el enfoque tradicional de ADO.Net puedo crear consultas o querys complejos, es decir, que haga uso de INNER JOIN, LEFT JOIN, de funciones como MAX(), SUM(), GROUP BY, ORDER BY y haga uso de varias tablas y en el SELECT traiga campos especificos o querys dinamicos si se envia o no un parametro, haciendo uso de strings, de AddParameters y posteriormente haciendo el ExecuteQuery(). Como podría lograr lo mismo con Entity Framework ?

    Un ejemplo de un query seria:

    SELECT ic_clie.cclie, ic_clie.cclex, ic_clie.nombr, ic_dire.telef AS contacto, ic_prod.cprod, ic_prod.cprex,  ic_prod.nombr, atr01.nombr AS atr01_nombr, atr02.nombr AS atr02_nombr, atr03.nombr AS atr03_nombr, atr04.nombr AS atr04_nombr, 
    atr05.nombr AS atr05_nombr, atr06.nombr AS atr06_nombr, atr07.nombr AS atr07_nombr, atr08.nombr AS atr08_nombr, 
    atr09.nombr AS atr09_nombr, atr10.nombr AS atr10_nombr, sum(ic_pedd.cannd) AS cannd, ic_inve.canti ,ic_prod.unmev, SUM(ic_pedd.cannd*ic_pedd.precu) AS ValorPedido, imone.cmone,im_mone.cemon 
    FROM ic_pedc
                INNER JOIN ic_pedd ON ic_pedd.cempr= ic_pedc.cempr AND ic_pedd.cpedi = ic_pedc.cpedi 
                INNER JOIN ic_clie ON ic_clie.cempr= ic_pedc.cempr AND ic_clie.cclie = ic_pedc.cclie 
                INNER JOIN ic_prod ON ic_prod.cempr= ic_pedd.cempr AND  ic_prod.cprod = ic_pedd.cprod 
                INNER JOIN ic_inve ON ic_inve.cempr= ic_pedd.cempr AND  ic_inve.cprod = ic_pedd.cprod 
                INNER JOIN ic_dire ON ic_dire.cclie = ic_clie.cclie AND ic_dire.princ = 'S' 
                LEFT JOIN ic_atrv AS atr01 ON atr01.catri = 1 AND atr01.ccatv = ic_prod.atr01 AND atr01.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr02 ON atr02.catri = 2 AND atr02.ccatv = ic_prod.atr02 AND atr02.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr03 ON atr03.catri = 3 AND atr03.ccatv = ic_prod.atr03 AND atr03.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr04 ON atr04.catri = 4 AND atr04.ccatv = ic_prod.atr04 AND atr04.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr05 ON atr05.catri = 5 AND atr05.ccatv = ic_prod.atr05 AND atr05.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr06 ON atr06.catri = 6 AND atr06.ccatv = ic_prod.atr06 AND atr06.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr07 ON atr07.catri = 7 AND atr07.ccatv = ic_prod.atr07 AND atr07.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr08 ON atr08.catri = 8 AND atr08.ccatv = ic_prod.atr08 AND atr08.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr09 ON atr09.catri = 9 AND atr09.ccatv = ic_prod.atr09 AND atr09.cempr = 'PARAMETRO' 
                LEFT JOIN ic_atrv AS atr10 on atr10.catri = 10 AND atr10.ccatv = ic_prod.atr10 AND atr10.cempr = 'PARAMETRO' 
                LEFT JOIN im_mone ON im_mone.cmone = ic_pedc.cmone 
    WHERE ic_pedd.cannd > 0 AND ic_pedc.cempr = 'PARAMETRO' AND ic_pedc.estad >= 2 AND DATE(ic_pedc.fecho) >= PARAMETRO_FECHA' AND DATE(ic_pedc.fecho) <= 'PARAMETRO_FECHA' AND ic_prod.cprex = 'PARAMETRO' 
    GROUP BY ic_clie.cclie, ic_prod.cprod, ic_prod.cprex;

    El anterior query podría implementarlo facilmente en un metodo en mi DAL, haciendo uso de if(parametros) para que evalúe si se debe agregar un parametro de búsqueda y asi volverlo dinamico. Pero como podría hacer lo mismo con EF ?

    Gracias a todos de antemano.

    miércoles, 4 de julio de 2018 18:51

Todas las respuestas

  • hola

    Habria que definie que seria dinamicos, si apuntas a generar un string concatenando las parte para luego ejecutar el select en ese caso lo veo complicado de lograr con EF, porque no esta pensado para aplicarlo de esa forma

    Ahora unir varias tablas mediante join, aplicar agrupadores max, sum, etc eso puedes hacerlo sin problema usando linq

    Recuerda que cuando mapeas uan clase a una tabla defines ademas las relaciones

    [Entity Framework][Code First] Asociación uno a muchos

    entonces esos join a veces los puedes lograr mediante esta navegacion

    cuando el linq se ejecute se convierte el sql

     How To Use Joins, and Group By Clause In Entity Framework With LINQ C#

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    martes, 10 de julio de 2018 22:59
  • Gracias por tu respuesta.

    En el caso que de los querys dinámicos que me aconsejarías ? No se que tan aconsejable seria el uso de Vistas y/o Stored Procedure, el principal problema que veria en ellos seria que si es un sistemas o aplicación en el cual haya gran cantidad de querys como la arriba mostrada me llenaría de ellas.

    El resto de funcionalidades (GROUP BY, ORDER BY, SUM())estarían soportadas por medio de LINQ, es correcto ?

    No si tengas algún ejemplo el cual represente lo arriba detallado en EF.

    Tambien tengo la duda si usando este tipo de querys EF pierde potencia frente al estilo "clasico"

    viernes, 13 de julio de 2018 15:18
  • Hola Julian_Lopez:

    No es sólo porque sean complicadas de programar, que lo son, sino porque además no son eficaces. Desde el punto de vista de entity framework, cuando le entrega las consultas al SQL, básicamente por cada tipo de relación, el utiliza una tabla derivada, sobre la primera consulta, al estilo de 

    SELECT [IDENTIDAD1].ID, [IDENTIDAD2].ID 
    FROM [TABLA1] AS [IDENTIDAD1] 
    INNER JOIN (
        SELECT B.ID FROM [TABLA2]
        ) AS [IDENTIDAD2] ON [IDENTIDAD1].ID = [IDENTIDAD2].ID

    La consulta te la he escrito de memoria, pero hace algo similar. Imagínate cuando tienes 300 columnas por tabla y como tu consulta 15 tablas......no funciona nada bien

    El resultado es que cuando tienes, como en tu caso muchas entidades a relacionar, se vuelve del todo ineficaz.

    Sin embargo tu misma consulta la creas con un stored procedure, al cual pones los parámetros que te apetezca, y la consumes desde entity consumir procedimiento desde entity

    Tu aplicación no tiene nada de consultas, tan solo el nombre del procedimiento. 

    Si el procedure devuelve un tipo de objeto que no pertenece a tu modelo de datos, puedes trabajarlo como anónimo, o haber definido un modelo personalizado para que entity te devuelva la colección que implemente IEnumerable o Iqueryable que te parezca de ese tipo de objeto.

    Personalmente pienso, que el Linq es genial, pero los datos que tienen que llegar a la memoria para utilizar linq, tienen que ser los justos, no porque sepamos hacer un group by o un sum en linq la base de datos va a tener que trasladar al servidor 800.000 millones de bytes porque no supe hacer un group by en la bbdd.

    En cuanto a la perdida de potencia, de EF, para nada. El mismo establece una simple conexión con la bbdd y le pide lo que quiere consumir y listo.

    Un saludo

    Pd. Existen multitud de ejemplos para consumir procedimientos almacenados en la web, y hay dos vertientes, quienes definen la navegación al procedimiento almacenado con la aplicación y quienes no.

    Se dice que si defines un procedure para una entidad, todo tiene que ir contra procedures, y no es correcto. Puedes jugar todo lo que quieras y cuando quieras contra procedures, o contra entity

    viernes, 13 de julio de 2018 18:00