Binding GridView to IQueryable<T>
Asked Answered
J

3

5

This question is purely academic, because I'd never dream of doing this in real code.

Using LINQ to SQL, I want to bind an IQueryable<T> to a GridView. I tried doing this with the following code, but I get the exception:

Cannot access a disposed object. Object name: 'DataContext accessed after Dispose.'.

Here is my code that gets an IQueryable<tabGenre> using LINQ to SQL:

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

And here is my code that binds the GridView to the returned IQueryable<T>.

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

So why doesn't this work? I could just a .ToList<tabGenre>(), return it, bind to it and then it would work, but why doesn't IQueryable work in the same fashion? What I'm really trying to achieve here is an understanding of what IQueryable can do.

EDIT: I also tried disabling lazy loading, but to no affect.

Jorry answered 4/3, 2011 at 17:24 Comment(0)
C
16

You can think of the IQueryable as the instructions required to execute the query. When you call .ToList(), you are executing the IQueryable() to return actual data. When you bind to IQueryable(), it will expect to have a data source to get the actual data whenever DataBind() is called.

When you set gvGenre.DataSource() = Genre.GetGenres2(), the DataContext required to get actual data based on your IQueryable is destroyed before the call to DataBind() occurs.

It works if you call .ToList() because you're physically going out and getting the data, then putting it memory.

Storing the IQueryable is like storing just the query. You can't execute a query if the datasource it expects to work with doesn't exist.

Coolant answered 4/3, 2011 at 17:32 Comment(1)
This makes perfect sense to me now. I actually have to explain this to some peers here at work, and your explanation is text book, so I'll use it. Thanks!!Jorry
R
2

The sole effect of that using block is to limit the lifespan of ctx to the block itself.

The useful lifespan of iq is dependent on the lifespan of ctx. You are explicitly disposing of ctx before iq is ever used.

The way to fix the problem would be to get rid of the using block, or to force iq to evaluate within the block (e.g. iq = iq.ToList()), and return only the results of that evaluation. If you're not keen on doing the latter, just ditch the using. ctx will be disposed of at some point after nobody needs it. Not perfect, maybe, but that's life with a garbage collector. Are you sure it'll be creating a problem if it stays around? Don't fix what's not yet shown to be broken.

Rumney answered 4/3, 2011 at 17:29 Comment(1)
Thanks for your input. Getting rid of the Using block does indeed fix, I know. I tried it and it worked, but I'm not a big fan of allowing the GC to clean up the DataContext for me. I actually even tried loading up the IQ before returning it, hoping it would then work, but it didn't. At that point, I begin to suspect that IQ might be tied indefinitely to the DataContext, but I wanted to check with the astute members of StackOverflow just to make sure. Thanks again.Jorry
M
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();
}

Just do it like this

Monopolize answered 26/9, 2012 at 9:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.