2011-03-04 17 views
5

Esta pregunta es puramente académica, porque nunca soñaría con hacer esto en código real.Encuadernación GridView a IQueryable <T>

Usando LINQ to SQL, quiero enlazar un IQueryable<T> a un GridView. Intenté hacer esto con el siguiente código, pero obtengo la excepción:

No se puede acceder a un objeto eliminado. Nombre del objeto: 'DataContext se accede después de deshacerse de.'.

Aquí está mi código que recibe un IQueryable<tabGenre> usando LINQ a SQL:

public static IQueryable<lu_Genre> GetGenres2() { 
    using (BooksContextDataContext ctx = new BooksContextDataContext()) { 
     IQueryable<tabGenre> iq = from g in ctx.tabGenre 
            select g; 
     return iq; 
    } 
} 

Y aquí es mi código que une el GridView a la IQueryable<T> devuelto.

private void GetGenres() { 
    gvGenre.DataSource = Genre.GetGenres2(); 
    gvGenre.DataBind(); 
} 

¿Por qué no funciona? Podría simplemente un .ToList<tabGenre>(), devolverlo, enlazarlo y luego funcionaría, pero ¿por qué IQueryable no funciona de la misma manera? Lo que estoy tratando de lograr aquí es una comprensión de lo que IQueryable puede hacer.

EDIT: También intenté desactivar la carga diferida, pero no afectó.

Respuesta

16

Puede pensar en IQueryable como las instrucciones necesarias para ejecutar la consulta. Cuando llama a .ToList(), está ejecutando IQueryable() para devolver datos reales. Cuando se vincula a IQueryable(), esperará tener una fuente de datos para obtener los datos reales cada vez que se llame a DataBind().

Cuando establece gvGenre.DataSource() = Genre.GetGenres2(), el DataContext requerido para obtener los datos reales basados ​​en su IQueryable se destruye antes de que se produzca la llamada a DataBind().

Funciona si llama a .ToList() porque está físicamente saliendo y obteniendo los datos, y luego poniéndole memoria.

Almacenar IQueryable es como almacenar solo la consulta. No puede ejecutar una consulta si el origen de datos con el que espera trabajar no existe.

+0

Esto tiene mucho sentido para mí ahora. De hecho, tengo que explicar esto a algunos compañeros aquí en el trabajo, y su explicación es libro de texto, así que lo usaré. ¡¡Gracias!! – Jagd

2

El único efecto de ese bloque de uso es limitar la vida útil de ctx al propio bloque.

La vida útil de iq depende de la vida útil de ctx. Usted es explícitamente desechando ctx antes de que se use iq alguna vez.

La forma de solucionar el problema sería deshacerse del bloque de uso o forzar iq para evaluar dentro del bloque (por ejemplo, iq = iq.ToList()) y devolver solo los resultados de esa evaluación. Si no estás interesado en hacer esto último, simplemente abandona el uso. ctx se eliminarán en algún momento después de que nadie lo necesite. No es perfecto, tal vez, pero así es la vida con un recolector de basura. ¿Estás seguro de que creará un problema si permanece? No arregles lo que aún no se muestra roto.

+0

Gracias por su entrada. Deshacerse del bloque de uso realmente lo arregla, lo sé. Lo probé y funcionó, pero no soy un gran admirador de permitir que el GC limpie el DataContext para mí. De hecho, incluso intenté cargar el cociente intelectual antes de devolverlo, esperando que funcionase, pero no fue así. En ese momento, empiezo a sospechar que IQ podría estar vinculado indefinidamente a DataContext, pero quería verificar con los astutos miembros de StackOverflow solo para estar seguro. Gracias de nuevo. – Jagd

0
public IQueryable MembershipGetAll() 
    { 


      var obj = (from mem in db.GetTable<MEMBERSHIP>() 
          select new 
          { 
           NAME = mem.MEMBERSHIP.NAME, 
           TYPE = mem.MEMBERSHIP.TYPE, 
           TAX_ID = mem.TAX_RATE.TAX_ID, 
           DISCOUNT = mem.DISCOUNT, 
           DISCOUNT_PERCENT = mem.DISCOUNT_PERCENT, 

          } 
         ).AsQueryable(); 
      return obj; 

    } 


private void LoadMembership() 
{ 
    IQueryable mem = null; 
    mem = eb.MembershipGetAll(); 
    grdMembership.DataSource = mem; 
    grdMembershipRates.DataBind(); 
} 

Sólo hacemos así

Cuestiones relacionadas