EF Core中无需客户端评估如何将实体属性展平为单个列表
问题说明
存在如下自引用表对应的实体类:
MyEntity { public string Id { get; set; } public string ParentId { get; set; } public bool isRelevant { get; set; } public virtual List<MyEntity> Children }
初始写法尝试用SelectMany同时选择每行的Id和ParentId合并为扁平列表,执行时抛出LINQ翻译错误,要求不使用客户端评估,返回形如["Id1", "parentId1", "Id2", "ParentId2"]的结果。
初始错误代码:
var result = await MyEntities .SelectMany(o => new List<string> { o.Id, o.ParentId }) .ToListAsync();
抛出的错误信息:
The LINQ expression could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable'...
正确实现
报错原因是EF Core无法将查询中手动初始化List<string>的C#逻辑翻译成对应SQL语句,要实现全服务端执行,使用Concat方法分别投影两列后拼接即可,EF Core会将该逻辑翻译为UNION ALL语句,完全在数据库侧执行,不会触发客户端评估:
var result = await MyEntities.Select(e => e.Id) .Concat(MyEntities.Select(e => e.ParentId)) .ToListAsync();
如果不需要返回空的ParentId值(比如根节点无父级的场景),可以在第二个投影前增加过滤条件:
var result = await MyEntities.Select(e => e.Id) .Concat(MyEntities.Where(e => !string.IsNullOrEmpty(e.ParentId)).Select(e => e.ParentId)) .ToListAsync();
注意:该写法返回的结果包含所有Id和所有ParentId,但数据库UNION ALL操作不保证两个结果集的行严格按「单条实体的Id紧跟自身ParentId」的顺序排列,如果强依赖相邻顺序,无法通过纯服务端查询实现,必须借助客户端评估。
内容的提问来源于stack exchange,提问作者Bolly
相关产品推荐
相关产品推荐

