【问题标题】:Debugging a complex linq query调试复杂的 linq 查询
【发布时间】:2014-12-02 11:58:59
【问题描述】:

我正在处理一个复杂的linq 查询,如下所示,它在运行时引发System.NullReferenceException。不幸的是,visual studio 没有提供任何其他信息,我无法对值执行QuickWatch 来检查哪个为空。有没有办法调试这种查询,以便我可以看到问题所在?

var dataSource = (from c in session.Query<PortChannel>()
        select
            new PortChannelData
            {
                Location = c.Port.MagazineSlot.SiteMagazine.Site.SiteName,
                MagazineName =
                    String.Format("{0}-{1}", c.Port.MagazineSlot.SiteMagazine.MagazineType.MagazineName,
                        c.Port.MagazineSlot.SiteMagazine.MagazineNo),
                SlotNo = c.Port.MagazineSlot.SlotNo,
                PortNo = c.Port.PortNo,
                Klm = c.Klm,
                StmNo = c.StmNo,
                Label = c.SiteName == null ? null : String.Format("{0}_{1}", c.SiteName, c.E1No),
                ChannelFullName = c.ChannelFullName,
                BscRncPort = c.BscRncPort,
                MgwPort = c.MgwPort,
                ReservedBy = c.ReservedBy,
                CrossFullName = c.CrossConnection == null ? null : c.CrossConnection.ChannelFullName
            }).ToList();
}

【问题讨论】:

  • 你试过LINQPad吗?
  • @Luca 不,我会看看谢谢!
  • 这个 LINQ 查询几乎没有任何复杂之处

标签: c# linq debugging visual-studio-2013


【解决方案1】:

在您的查询中,您可以使用let 关键字来存储子表达式的结果。然后在创建新的PortChannelData 对象时分配结果。

var dataSource = 
    (from c in session.Query<PortChannel>()
        let flName = c.CrossConnection == null ? null : c.CrossConnection.ChannelFullName
        let magName = String.Format("{0}-{1}", c.Port.MagazineSlot.SiteMagazine.MagazineType.MagazineName,
                    c.Port.MagazineSlot.SiteMagazine.MagazineNo)
        // and so on
        select new PortChannelData
        {
            MagazineName = magName,
            CrossFullName = flName,
            // ...
        }).ToList();

这样,当您调试并进入查询时(F11 是标准的 Visual Studio 快捷方式),您将看到每个子表达式的结果。

【讨论】:

  • 注意查询末尾的 .ToList() 调用 - 这会覆盖延迟执行,允许您逐步执行代码(更多信息请参见:stackoverflow.com/a/29556281/2696616
  • 即使在复杂的 Linq 查询中也经常忘记 F11
【解决方案2】:

我之前也遇到过同样的问题,下面的技巧帮了我很多。

我已将提取的值定义为我的 select 表达式中的属性,并且在执行 new ObjectName() 提取语句之前,这样当错误发生时,Visual Studio 将指向导致 null 的特定部分参考。

考虑以下示例:

var returnNews = reportResult.Select(n =>
            {
                var createdBy = allUsersInfoForReport.FirstOrDefault(u => u.ID == n.CreatedBy);
                var publishedBy = allUsersInfoForReport.FirstOrDefault(u => u.ID == n.Publishedby);
                var modifiedBy = allUsersInfoForReport.FirstOrDefault(u => u.ID == n.LastModifiedBy);

                newsViewCountEntity = newsViewCountCollection.FirstOrDefault(nv => nv.News_ID == n.ID);
                newsCommentsCount = newsCommentsCollection.Count(s => s == n.ID);

                return new ReportItemViewModel()
                {
                    ID = n.ID,

                    AddedBy = createdBy != null ? createdBy.UserName : "",
                    UserSectionName = createdBy != null ? createdBy.RelatedSectionName : "",
                    PublishedBy = publishedBy != null ? publishedBy.UserName : "",
                    LastModifiedBy = modifiedBy != null ? modifiedBy.UserName : "",
                }
});

在此示例中,如果以下任一属性 (createdBy - publishedBy - modifiedBy) 未能获得有效值,则会引发异常,但该行被正确突出显示,而不是突出显示整个 LINQ表达。

尝试使用相同的技术,然后告诉我结果。

【讨论】:

    【解决方案3】:

    你可以在new PortChannelData这一行下一个断点,像往常一样调试(每次执行select语句都会打断点,也就是session.Query&lt;PortChannel&gt;()中的每个元素)。

    如果您将selectnew PortChannelData 放在同一行,那么设置断点会在Linq 查询的开头放置一个断点。该断点只被命中一次 - 就在执行查询之前 - 并且不允许您“跳入”查询。但是,您可以通过右键单击装订线中的红色断点点并选择“位置...”来更改 Visual Studio 中断点的位置。将位置设置为new PortChannelData的起始行和字符,断点将放在select语句中。

    您还可以向断点添加条件,以便它们仅在满足条件时才会激活。如果session.Query&lt;PortChannel&gt;() 返回大量端口通道,那么检查您正在访问的任何属性或字段是否为空的条件可以为您节省一些时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-08
      • 2014-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多