【问题标题】:Eager-loading using LINQ to SQL with Include()使用带有 Include() 的 LINQ to SQL 进行预加载
【发布时间】:2016-01-04 02:31:07
【问题描述】:

我已经花了 2 天的时间来解决这个问题,但我似乎无法破解它(即问题所在)。在我添加数据库关系之前,相同的代码运行良好,此后我阅读了一篇关于延迟加载的很多

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

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

在 Dispose 之后访问的 DataContext。

我的函数当前返回表中的所有条目:

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

我阅读了许多文章/页面/答案,他们都说要使用.Include() 方法。但这对我不起作用:

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

我也尝试过“魔术字符串”版本:

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

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

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

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

return toReturn;

我尝试在查询中添加.Where() 条件,我尝试过.Select(),我尝试在.Where() 之后移动.Include()this answer 说要最后做,但是我认为这只是由于嵌套查询)。我读过关于.Include()will silently fail 的场景,毕竟我离这更近了。

我错过了什么?语法问题?逻辑问题?一旦我得到这个“简单”的案例,我还需要嵌套Includes(即如果CustomerPromo表与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 错误(仅此而已!)。

【问题讨论】:

  • 你能分享一下引发实际异常的代码片段吗?根据您上面的内容,这将在您返回 PromoCodes 的列表并对其进行处理之后发生。
  • 如果是这样,那是因为它在 WCF 数据服务中。它正在转换为 JSON。日志文件中有大量异常堆栈跟踪,但唯一可识别的部分是WriteArrayOfPromoCodeToJsonWritePromoCodeToJsonWriteArrayOfCustomerPromoToJson
  • 到目前为止,您唯一想到的就是您正在尝试在 Using 块之外使用您的数据上下文。
  • 仅仅从阅读你的错误我建议不要返回你的 using (MsSqlDataContext db) 来创建一个数组变量,分配给它并调用 ToArray(),离开使用上下文,然后返回.这有什么改变吗?
  • @Ian 这可能会有所帮助link

标签: c# linq lazy-loading eager-loading


【解决方案1】:

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

现在,当我实际上也需要子数据时,我发现它并不能完全发挥作用。我发现this article 表示.Include()(他说Including() 但我不确定这是不是错字)已被删除,正确的解决方案是使用DataLoadOptions。另外,我还需要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 后,它会愉快地返回一个父对象,而无需加载子对象,或者显式设置DeferredLoadingEnabled = false;

【讨论】:

    【解决方案2】:

    编辑:这并没有完全解决问题。在测试时没有任何子数据,我也没有尝试使用它。这只允许我返回 parent 对象,它不返回子对象。如需完整解决方案,请参阅this answer

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

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

    This link 发布在问题 cmets 中(感谢@Virgil)提示答案。但是,我找不到为 LINQ to SQL 访问LazyLoadingEnabled 的方法(我怀疑它是用于 EntityFramework 的)。 This page 表示 LINQ to SQL 的解决方案是 DeferredLoadingEnabled

    这是DeferredLoadingEnabled 上 MSDN 文档的链接。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多