1

这是一个例子:

假设我有 3 张表,国家、人和城市。城市记录具有标识国家/地区的不可为空的外键字段。人员记录有一个可以为的外键字段来标识一个国家 - 他们可能来自一个不再存在的东欧国家。

我想从人员列表和城市列表中创建国家/地区的组合列表:

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 虚拟列调用“[test]”来完成的

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 端它肯定存在,并且当我将它与正常的 Country 选择联合时导致查询被拒绝陈述。

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

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

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

4

1 回答 1

1

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

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));
于 2009-09-01T17:08:41.023 回答