none
Iqueryable podría ser un IEnumerable RRS feed

  • Pregunta

  • Hola

    Se puede mejorar esta consulta

    public IQueryable<List<UniversalExtend>> IdentificacionXComprobante(int id)
            {
                using (var context = new BusinessContext())
                {
                    IQueryable<List<UniversalExtend>> list = from c in context.Comprobantes
                        where c.ComprobanteId == id
                        select
                            c.TipoIdentificaciones.Select(
                                x => new UniversalExtend() {Id = x.TipoIdentificacionId, Descripcion = x.Nombre}).ToList();
                    return list;
                }
            }

    ¿Podría ser un IEnumerable que luego se convierta en list en el return? 


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


    viernes, 10 de agosto de 2018 23:54

Respuestas

  • ¿Podría ser un IEnumerable que luego se convierta en list en el return? 

    Ya es un IEnumerable. El IQueryable implementa IEnumerable.

    Puede tener sentido es que la función devuelva un IQueryable, por ejemplo, podría ser útil si el llamante de la función quiere seguir aplicando filtros en la consulta antes de materializarla.

    Si siempre la vas a materializar tal como está sin añadir filtros adicionales, entonces es preferible que devuelvas un IEnumerable. Basta con que cambies la declaración del método para que devuelva IEnumerable en lugar de IQueryable.

    Si en el return quieres materializar la consulta, puedes poner return list.ToList(); En este caso, necesariamente tiene que ser un IEnumrable, dará un error si el resultado lo dejas como IQueryable.

    Esto puede ser bueno o no, dependiendo de cómo vayas a llamar al método. Si pones el ToList, la consulta se materializa siempre dentro del método, antes de devolver los resultados. Si no pones el ToList, se materializa en el momento en el que el código llamante comienza a enumerar los resultados, cosa que puede ser que te convenga o que no te convenga, dependiendo de cómo uses el método.

    sábado, 11 de agosto de 2018 9:12
    Moderador
  • Sí, es por el "using".

    Como ya te dije, si devuelves el IQueryable en lugar de materializar la consulta, lo que ocurre es que se materializa más tarde, cuando terminas de aplicarle filtros al IQueryable (si es que lo haces) y luego lo enumeras. En el momento de enumerarlo se envía la consulta a la base de datos. Pero para eso, es necesario que en ese momento la conexión a la base de datos esté abierta. Eso se controla con el "using" del DataContext. Como ese "using" lo tienes dentro de la subrutina, al salir de la subrutina se ejecuta el Dispose que cierra el datacontext, y por lo tanto ya no es posible materializar la consulta fuera de esa subrutina.

    Posibles soluciones:

    a) Si planeas aplicar filtros al IQueryable después de haberlo devuelto desde la subrutina, entonces el using del context hay que ponerlo fuera de la subrutina, alrededor del código en el que se llama a la subrutina y luego se utiliza su resultado (y lógicamente, pasarlo como argumento a la subrutina).

    b) Si no vas a hacer nada con el IQueryable, sino que simplemente lo vas a materializar tal como está, entonces cámbialo por un IEnumerable y pon el ToList() dentro de la subrutina, tal como habíamos comentado antes.

    • Marcado como respuesta Pedro Ávila lunes, 13 de agosto de 2018 14:29
    domingo, 12 de agosto de 2018 7:37
    Moderador

Todas las respuestas

  • ¿Podría ser un IEnumerable que luego se convierta en list en el return? 

    Ya es un IEnumerable. El IQueryable implementa IEnumerable.

    Puede tener sentido es que la función devuelva un IQueryable, por ejemplo, podría ser útil si el llamante de la función quiere seguir aplicando filtros en la consulta antes de materializarla.

    Si siempre la vas a materializar tal como está sin añadir filtros adicionales, entonces es preferible que devuelvas un IEnumerable. Basta con que cambies la declaración del método para que devuelva IEnumerable en lugar de IQueryable.

    Si en el return quieres materializar la consulta, puedes poner return list.ToList(); En este caso, necesariamente tiene que ser un IEnumrable, dará un error si el resultado lo dejas como IQueryable.

    Esto puede ser bueno o no, dependiendo de cómo vayas a llamar al método. Si pones el ToList, la consulta se materializa siempre dentro del método, antes de devolver los resultados. Si no pones el ToList, se materializa en el momento en el que el código llamante comienza a enumerar los resultados, cosa que puede ser que te convenga o que no te convenga, dependiendo de cómo uses el método.

    sábado, 11 de agosto de 2018 9:12
    Moderador
  • Hola Alberto

    Me da error cuanto intento acceder al método me dice que el datacontex esta en dispose.

    public IQueryable<IEnumerable<UniversalExtend>> IdentificacionXComprobante(int id)
            {
                using (var context = new BusinessContext())
                {
                    var list = from c in context.Comprobantes.Include("TipoIdentificaciones")
                               where c.ComprobanteId == id
                               select
                                   c.TipoIdentificaciones.Select(
                                       x => new UniversalExtend() { Id = x.TipoIdentificacionId, Descripcion = x.Nombre });
                    return list;
                }
            }

    Me dice: La operación no puede completarse porque el dbContext ha sido eliminado.


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

    sábado, 11 de agosto de 2018 14:10
  • Sí, es por el "using".

    Como ya te dije, si devuelves el IQueryable en lugar de materializar la consulta, lo que ocurre es que se materializa más tarde, cuando terminas de aplicarle filtros al IQueryable (si es que lo haces) y luego lo enumeras. En el momento de enumerarlo se envía la consulta a la base de datos. Pero para eso, es necesario que en ese momento la conexión a la base de datos esté abierta. Eso se controla con el "using" del DataContext. Como ese "using" lo tienes dentro de la subrutina, al salir de la subrutina se ejecuta el Dispose que cierra el datacontext, y por lo tanto ya no es posible materializar la consulta fuera de esa subrutina.

    Posibles soluciones:

    a) Si planeas aplicar filtros al IQueryable después de haberlo devuelto desde la subrutina, entonces el using del context hay que ponerlo fuera de la subrutina, alrededor del código en el que se llama a la subrutina y luego se utiliza su resultado (y lógicamente, pasarlo como argumento a la subrutina).

    b) Si no vas a hacer nada con el IQueryable, sino que simplemente lo vas a materializar tal como está, entonces cámbialo por un IEnumerable y pon el ToList() dentro de la subrutina, tal como habíamos comentado antes.

    • Marcado como respuesta Pedro Ávila lunes, 13 de agosto de 2018 14:29
    domingo, 12 de agosto de 2018 7:37
    Moderador