使用 LINQ 预加载到 SQL 和 Include()

Eager-loading using LINQ to SQL with Include()

我花了 2 天的时间来解决这个问题,但我似乎无法破解它(就是这个问题)。在我添加数据库关系之前,相同的代码工作正常,此后我阅读了很多关于延迟加载的文章。

我有两个数据库 table,它们之间有 1:1 关系。 PromoCode table 跟踪代码,并有一个名为 id 的 PK 列。 CustomerPromo table 有一列 PromoId 链接到 PromoCode table id。这两个table没有其他关系。我在 SQL Server Management Studio 中生成了所有这些,然后从数据库中生成了模型。

为了使事情稍微复杂一些,我在 WCF 数据服务中执行此操作,但我认为这不会有什么不同(它在添加数据库关系之前起作用)。启用日志记录后,我总是在日志文件中收到带有文本的异常:

DataContext accessed after Dispose.

我的函数当前 returns 来自 table 的所有条目:

using (MsSqlDataContext db = new MsSqlDataContext())
{
    // This causes issues with lazy-loading
    return db.PromoCodes.ToArray();
}

看了很多articles/pages/answers,都说要用.Include()方法。但这对我不起作用:

return db.PromoCodes.Include(x => x.CustomerPromos).ToArray();

我也试过 "magic string" 版本:

return db.PromoCodes.Include("CustomerPromos").ToArray();

我设法开始工作的唯一代码是:

PromoCode[] toReturn = db.PromoCodes.ToArray();

foreach (var p in toReturn)
    p.CustomerPromos.Load();

return toReturn;

我试过向查询添加 .Where() 条件,我试过 .Select(),我试过将 .Include() 移到 .Where() 之后( this answer says to do it last, but I think that's only due to nested queries). I've read about scenarios where .Include() will silently fail,毕竟我还差得远。

我错过了什么?语法问题?逻辑问题?一旦我得到这个 "simple" 案例,我还需要嵌套 Includes(即如果 CustomerPromo table 与 Customer 有关系)。

编辑
包括所有相关代码。其余部分是 LINQ to SQL 或 WCF 数据服务配置。这就是全部:

[WebGet]
[OperationContract]
public PromoCode[] Test()
{
    using (MsSqlDataContext db = new MsSqlDataContext())
    {
        return db.PromoCodes.Include(x => x.CustomerPromos).ToArray();
    }
}

如果我直接通过浏览器调用它(例如 http://<address>:<port>/DataService.svc/Test),我会收到一条重置连接消息,并且必须查找 WCF 日志以找出“DataContext accessed after Dispose.”。如果我通过网页中的 AJAX 调用进行相同的查询,我会收到状态为 error 的 AJAX 错误(仅此而已!)。

编辑: 这并没有完全解决问题。在测试时没有任何子数据,我也没有尝试使用它。这只允许我 return 父对象 对象,而不是 return 子对象。有关完整解决方案,请参阅 .

与我读过的所有内容相反,答案不是使用 .Include() 而是更改上下文选项。

using (MsSqlDataContext db = new MsSqlDataContext())
{
    db.DeferredLoadingEnabled = false; // THIS makes all the difference
    return db.PromoCodes.ToArray();
}

posted in the question comments (thanks @Virgil) hint at the answer. However I couldn't find a way to access LazyLoadingEnabled for LINQ to SQL (I suspect it's for EntityFramework instead). This page 表示 LINQ to SQL 的解决方案是 DeferredLoadingEnabled

这是 DeferredLoadingEnabled 上的 MSDN 文档的 link。

当我实际上没有任何子数据要获取时,我过早地发布了上一个答案。当时我只对获取父数据感兴趣,并且工作。

现在,当我实际上也需要子数据时,我发现它不能完全工作。我找到 this article which indicates that .Include() (he says Including() but I'm not sure if that's a typo) has been removed, and the correct solution is to use DataLoadOptions. In addition, I also needed to enable Unidirectional Serialisation.

最重要的是,我不再需要 DeferredLoadingEnabled。所以现在最终代码如下所示:

using (MsSqlDataContext db = new MsSqlDataContext())
{
    DataLoadOptions options = new DataLoadOptions();
    options.LoadWith<PromoCode>(p => p.CustomerPromos);
    db.LoadOptions = options;

    return db.PromoCodes.ToArray();
}

设置 Unidirectional Serialisation 后,它会愉快地 return 一个父对象,而不必加载子对象,或者显式设置 DeferredLoadingEnabled = false;.