将GridView绑定到IQueryable<T>

5

这个问题纯粹是学术性质的,因为我从不会在实际代码中做这件事。

使用LINQ to SQL,我想将一个IQueryable<T>绑定到GridView。我尝试使用以下代码来完成这个过程,但是我收到了异常:

无法访问已释放的对象。 对象名称:“在Dispose后访问的DataContext。”

这里是使用LINQ to SQL获取IQueryable<tabGenre>的代码:

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

这是将GridView绑定到返回的 IQueryable<T> 的代码。

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

那么为什么这个不起作用呢?我可以使用.ToList<tabGenre>(),然后将其返回并绑定它,那么它就会起作用,但是为什么IQueryable不能以同样的方式工作呢?我真正想要实现的是对IQueryable的理解。
编辑:我还尝试禁用延迟加载,但没有效果。
3个回答

16
您可以把IQueryable视为执行查询所需的指令。当您调用.ToList()时,会执行IQueryable()以返回实际数据。当您绑定到IQueryable()时,它将期望有一个数据源在DataBind()被调用时获取实际数据。
当您设置 gvGenre.DataSource() = Genre.GetGenres2() 时,用于基于您的IQueryable获取实际数据的DataContext会在调用DataBind()之前被销毁。
如果调用.ToList(),它将正常工作,因为您是实际获取数据,然后将其放入内存中。
存储IQueryable就像只存储查询。如果它期望的数据源不存在,您就无法执行查询。

现在我完全明白了。我实际上需要向我的一些同事在工作中解释这个问题,而你的解释非常清晰易懂,我会借鉴它。谢谢! - Jagd

2
那个using代码块的唯一作用是将“ctx”的生命周期限制在该代码块本身。
“iq”的有用生命周期取决于“ctx”的生命周期。您在使用“iq”之前明确处理了“ctx”。
要解决问题,可以摆脱using代码块,或者强制在该代码块内评估“iq”(例如,“iq = iq.ToList()”),并仅返回该评估的结果。如果您不想这样做,只需摆脱using代码块。“ctx”将在没有人需要它之后的某个时刻被处理掉。这可能不是最完美的解决方案,但这就是垃圾收集器的运行方式。您确定如果保留它会产生问题吗?不要修复尚未出现问题的内容。

感谢您的回复。去掉Using块确实可以解决问题,我知道。我尝试过并且它有效,但我不太喜欢让GC为我清理DataContext。我甚至尝试在返回之前加载IQ,希望它能够工作,但它没有。在那时,我开始怀疑IQ可能会无限期地绑定到DataContext上,但我想与StackOverflow的聪明成员核实一下。再次感谢。 - 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();
}

就像这样做


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接