【发布时间】:2019-12-14 06:08:28
【问题描述】:
我正在使用 Automapper 可查询扩展:http://docs.automapper.org/en/stable/Queryable-Extensions.html#
我想将我的完整实体映射到仅包含几个字段的简化版本。在这种情况下,我的前端 UI 将不知道基本实体,只会发送简化实体的过滤条件。因此,我使用query.ProjectTo<MySimpleEntity>,然后将Where 与过滤条件一起应用。
在这种特定情况下,两个实体都实现了我的自定义接口ITimeLimitedEntity,它确保了ValidFrom 和ValidTo 字段。
当我不使用 Automapper 并对整个实体应用条件时,过滤会按预期工作并生成正确的 SQL 查询。
但只要我添加 ProjectTo<MySimpleEntity>,我就会收到一个警告(我实际上将其作为异常抛出以避免无声的客户端评估):
The LINQ expression 'where ((Convert(new MySimpleEntity() {Id = [dtoMyOriginalEntity].Id, Name = [dtoMyOriginalEntity].Name, ValidFrom = [dtoMyOriginalEntity].ValidFrom}, ITimeLimitedEntity).ValidFrom == null))'
could not be translated and will be evaluated locally.'
因此,该标准应用于 Automapper 的内部 dtoMyOriginalEntity,当然,它并没有实现我的 ITimeLimitedEntity,因此 LINQ 添加了 Convert,这显然不能转换为有效的 SQL 查询,从而导致尝试在内存中对其进行评估。
这很奇怪。当我调试代码时:
projQuery = query.ProjectTo<MySimpleEntity>(_mapper.ConfigurationProvider);
projQuery 是 IQueryable,它实现了ITimeLimitedEntity——那为什么 Linq 需要转换呢?
我如何告诉 Automapper 或 Linq 它应该将我的 where 标准应用到已经是 ITimeLimitedEntity 而不是某些 Automapper 的内部 DTO 实体的最终投影 MySimpleEntity 上?
更新:
我创建了一个简单的 dotnetfiddle 示例 https://dotnetfiddle.net/X2RDGn 当然,它工作得很好,因为它使用的是内存数据库。但我已经评论了在现实世界中失败的问题领域。
更新 2: 我使用真实数据库创建了一个简化的控制台应用 gist.github.com/progmars/eeec32a533dbd2e1f85e551db1bc53f8,当通过通用方法访问时,Linq 表达式仍在本地执行,尽管调试器显示两个表达式主体完全匹配。
更新 3:
正如一些人指出的那样,原因是 Linq-to-entities 本身而不是 Automapper。因此,为一个新的 SO 问题创建了一个新的、不那么复杂的可重现案例,并在这里解决了:Why Linq "where" expression after Select gets evaluated locally when created through a generic method?
【问题讨论】:
-
写一个 LINQ 查询来做你想做的事,没有 AM,然后我们看看
ProjectTo能做什么。 -
@LucianBargaoanu 我用 dotnetfiddle 示例的链接更新了我的问题。
-
因此,如果 LINQ 不能与 EF 一起使用,那么它也不能与 AM 一起使用。
标签: c# linq entity-framework-core automapper