3

我在统一搜索功能中使用了以下 LINQ 代码。

var searchObjects =
    from objectA in this.context.DB.objectAs
    join objectB in this.context.DB.objectBs on objectA equals objectB.objectA into objectAB
    from AB in objectAB.Where(o => o.Type == "BasicGroup").DefaultIfEmpty()
    select new { objectA, objectB = AB};

foreach (var searchWord in searchWords)
{
    var searchObjects =
        searchObjects.Where(p => p.objectA.Name.Contains(searchWord) ||
            (p.objectB != null &&
                (p.objectB.Name.Contains(searchWord) ||
                p.objectB.ID.contains(searchWord))));
}

目标是在 objectA 的 Name 字段或相关 objectB 的 Name 或 ID 字段中查找搜索词。问题是,当我尝试枚举 searchObjects 时,它只返回 NullReferenceException,没有更多详细信息。

查询的第一部分返回组合对象的正确列表(没有任何过滤器),所以我认为问题不在于左连接?

我无法弄清楚是什么导致了异常,所以任何帮助将不胜感激。

我也在使用 Telerik 的 OpenAccess ORM,但我认为这不会造成任何问题吗?

编辑:

原来这是 Telerik OpenAccess ORM 的一个问题,在某些情况下,它只会放弃生成合理的 SQL,将所有内容都绘制到内存中并将其视为 L2Objects(如@Dead.Rabit 所指出的那样,它应该在 null 上失败) . 似乎至少部分问题的条件是 .DefaultIfEmpty() 前面的 .Where(o => o.Type == "BasicGroup")。更新到最新版本的 OpenAccess(我认为是 2013 Q1 SPI)允许我重写该条件作为 equals 语句的一部分

on new { objectA.ID, Type = "BasicGroup" } equals new { ID = objectB.AID, Type = object.Type }

这在 SP1 之前是不可能的。使用这个新查询,我可以将搜索词 Where 子句组合到查询中,并且仍然让它生成 SQL,而不是将其绘制到内存中。

4

2 回答 2

2

AB 可以为空,因为您使用DefaultIfEmpty()函数创建它,但 ifObjectA.Name也可以为空;Contains()在你的第二个语句中会抛出一个错误。同样,如果 ObjectB 不为空时 ObjectB.ID 或 ObjectB.Name 可以为空,那么您的ObjectB != null保护子句将不会产生预期的效果。

尝试对您的对象进行简单枚举,以确保问题出在您的第一个查询上

foreach( var item in searchObjects )
    Console.WriteLine( item.Type );

您在每次迭代中重新定义 searchObjects 变量,我认为这是在 SO 的代码转储中丢失的东西,但值得一提的是 JIC。

最后我不确定 OpenAccess ORM,因为我从来没有使用过它,但是这个查询在 LINQ 的 Dynamics CRM 实现上会失败,它不支持 where 子句中的某些类型的条件(我不会详细介绍因为它无关紧要,但是您在此查询中破坏了所有这些:p)。绝对值得在 3rd 方 LINQ 实现中浏览 gotcha 的文档。

于 2013-05-13T10:33:49.693 回答
1

我不是 100% 确定,但我认为你需要使用AB而不是objectB在你的匿名类型中。

select new { objectA, AB }

因为那是左连接的结果。

于 2013-05-13T10:11:00.420 回答