代码之家  ›  专栏  ›  技术社区  ›  David

影响联合操作的Linq和可空键关系

  •  1
  • David  · 技术社区  · 16 年前

    下面是一个例子:

    假设我有三张桌子,国家,人民和城市。城市记录有一个标识国家的不可为空的外键字段。人物记录有 可空的 识别一个国家的外国关键领域——它们可能来自不再存在的东欧国家。

    我想从人口和城市列表中创建一个国家的组合列表:

    var people = dbContext.People.Where(...);
    var cities = dbContext.Cities.Where(...);
    
    var countries = cities.Select(c=>c.Country);
    countries = countries.Union(people.Select(p=>p.Country));
    

    问题出在最后一行。由于并非所有人员记录都有匹配的国家/地区记录,因此Linq(正确地)正在创建一个查询,以确保每个国家/地区以外的人员都有一个填充了空值的行。对于调试器,这似乎是通过创建entra虚拟列调用“[测试]”来完成的。

    SELECT [t2].[test], [t2].[CountryID], [t2].[Name]
    FROM [dbo].[People] AS [t0]
    LEFT OUTER JOIN (
        SELECT 1 AS [test], [t1].[CountryID], [t1].[Name]
        FROM [dbo].[Countries] AS [t1]
        ) AS [t2] ON [t2].[CountryID] = [t0].[CountryID]
    

    当代码端的额外列[test]被静默地删除(结果被标识为iqueryable)时,在SQL端,它最明显地在那里,当我将它与一个正常的国家选择语句结合时,会导致查询被拒绝。

    在最后一种情况下,我不需要或不需要额外的虚拟行-在我已经包含的完整程序中 people.Where(p=>p.CountryID != null).Select(p=>p.Country) 以及尝试 p=>Country != null .

    但是,Linq不认识到这将阻止空行,因此仍然插入测试列。由于测试列是不可见的,所以我没有明显的方法可以将它从另外报告为IQueryable对象的对象中“删除”。最终的结果是关于我的union构造具有不相等的列数的运行时错误。

    如何在可为空的关系上强制内部联接,或者通过排除不可见的测试列使联合按我的意愿工作?

    1 回复  |  直到 16 年前
        1
  •  1
  •   Amy B    16 年前

    我知道理想情况下,您可以在映射中使用关系,但这可能是一个很好的解决方案。

    var people = dbContext.People.Where(...);
    var cities = dbContext.Cities.Where(...);
    
    var countryIds =
      cities
        .Select(c => c.CountryID)
      .Union(people
        .Select(p => p.CountryID)
        .Where(cID => cID.HasValue)
        .Select(cID => cID.Value));
    
    var countries = dbContext.Countries
      .Where(c => countryIds.Contains(c.CountryID));