为啥此 LINQ 表达式返回只有一项的子列表
Posted
技术标签:
【中文标题】为啥此 LINQ 表达式返回只有一项的子列表【英文标题】:Why this LINQ expressoin returns the sublist with only one item为什么此 LINQ 表达式返回只有一项的子列表 【发布时间】:2020-03-10 02:52:30 【问题描述】:这是我的对象模型。
public class ItemViewModel
public Item ItemObject get; set;
public IEnumerable<LineItem> Fields get; set; = new List<LineItem>();
public class Item
public int ItemId get; set;
public DateTime DatePurchased get; set;
public class LineItem
public int ItemId get; set;
public string Name get; set;
数据库包含Items和LineItems表,对应对象模型。我正在使用下面编写的 LINQ 表达式来检索 ItemViewModel
对象,并提供了一个项目 ID。
var i = from i in _dbContext.Items
where i.ItemId == 123
select new ItemViewModel
ItemObject = i,
Fields = from field in _dbContext.LineItems
where field.ItemId == i.ItemId
select field
;
var viewModel = await i.SingleOrDefaultAsync();
代码编译良好,但在执行后viewModel.Fields
属性仅包含一个列表项,而在数据库表中针对 ItemID:123 有三个 Line Items。
此 sn-p 生成的 SQL(通过 SQL Profiler 捕获)通过 LEFT JOIN 返回三个行项目。这意味着生成的 SQL 很好,但 Entity Framework 的某些方面不太好,但我不知道是什么?
更新: 这是生成的 SQL 查询,它正确地给了我三行:
SELECT
[t].[ItemId], [t].[DatePurchased],
[s0].[ItemId], [s0].[Name]
FROM
(
SELECT
TOP(2) [s].[ItemId], [s].[DatePurchased]
FROM
[Items] AS [s]
WHERE
[s].[ItemId] = 123
) AS [t]
LEFT JOIN [LineItems] AS [s0] ON [t].[ItemId] = [s0].[ItemId]
ORDER BY [t].[ItemId]
技术栈是 .NET Core 3.1 和 Entity Framework Core。
【问题讨论】:
你能提供这个生成的对应SQL吗? @John 是的,我可以,但这会使这个问题变得不必要地冗长。你认为生成的 SQL 对你有帮助吗? 我不能肯定,但它可能会。 是LineItems
keyless 实体类型吗?如果是,这是我第二次听到这个消息,我可以确认这是 EFC 错误。此外,它不仅返回每个父母 1 个孩子,而且还返回一个相同的(可能是第一个)记录,对吗?我在 EF Core 问题跟踪器中找不到错误,请考虑在此处发布问题 - github.com/dotnet/efcore/issues。
@IvanStoev 错误提交:github.com/dotnet/efcore/issues/20247
【参考方案1】:
正如 Ivan Stoev 在该问题下的 cmets 中所建议的那样,原因是 Entity Framework Core 中的一个错误,在将无密钥实体作为子实体处理时。我通过将主键添加到我之前的无键表中,然后验证相同的 LINQ 语句,对它进行了第一手测试。添加主键后,它开始给我一个包含 3 个项目的列表,而不是只有 1 个。所以在这个问题和我的测试之后,我已将其报告给 EF Core issue tracker。
对于在寻找答案时偶然发现此问题的任何人,我们有两种选择。向无键表添加主键或在 EF 实体模型中定义复合主键。我使用以下行修复了我的情况:
modelBuilder.Entity<LineItem>().HasKey(i => new i.ItemId, i.Name );
之所以有效,是因为 LineItem.ItemId
和 LineItem.Name
的组合对于我的实体来说是独一无二的。这个答案的功劳归于an answer(虽然不是官方接受的答案)到较早的SO问题。
【讨论】:
以上是关于为啥此 LINQ 表达式返回只有一项的子列表的主要内容,如果未能解决你的问题,请参考以下文章