Entity Framework 如何筛选子集合最新消息TeamId不为空的Ticket
问题原因分析
你之前的两种写法都存在EF Core翻译逻辑不符合预期的问题:
- 第二种写法用到的
x.Messages.Last()在没有显式指定排序规则的场景下,EF Core会默认按主键正序取第一条数据,完全无法匹配「取最新一条消息」的逻辑,必然返回错误结果。 - 第一种写法的
OrderByDescending(...).First().TeamId != null在部分低版本EF Core中会出现翻译错误,不会正确判断排序后第一条数据的TeamId值,甚至会被翻译为恒真条件,导致返回所有Ticket。
正确写法
兼容所有EF Core版本的稳妥写法
var result = await _context.Tickets .Include(x => x.Messages) // 如果需要排除没有关联消息的Ticket可以保留这一行,不需要的话删除即可 .Where(x => x.Messages.Any()) .Where(x => x.Messages .OrderByDescending(m => m.InsertDate) .Take(1) .Any(m => m.TeamId != null)) .ToListAsync();
这种写法用OrderByDescending + Take(1) + Any的组合,所有版本的EF Core都可以稳定翻译为符合要求的SQL,逻辑是对每个Ticket的关联消息按插入时间倒序,取最新的一条判断TeamId不为空,同时可以避免关联消息为空时调用First()抛出的运行时异常。
EF Core 6+ 简化写法
如果你使用的是EF Core 6及以上版本,可以直接用更简洁的写法:
var result = await _context.Tickets .Include(x => x.Messages) .Where(x => x.Messages.Any()) .Where(x => x.Messages .OrderByDescending(m => m.InsertDate) .First().TeamId != null) .ToListAsync();
内容的提问来源于stack exchange,提问作者Sauron
相关产品推荐
相关产品推荐

