使用泛型时LINQ表达式无法转换的C#技术问题求助
解决EF Core泛型查询中反射无法翻译的问题
你这段代码里靠反射获取Id属性的逻辑,EF Core没办法将其转换成对应的SQL语句,所以才会抛出查询无法翻译的异常。直接调用ToList()虽然能绕开这个问题,但会把整张表的数据都加载到内存里,数据量一大性能就会崩。
给你几个合理的解决办法:
1. 用接口约束统一实体的Id属性
定义一个包含Id属性的接口,让所有需要查询的实体都实现这个接口:
public interface IHasId { long Id { get; } }
然后给泛型方法加上约束,确保T实现了这个接口:
public T GetEntity<T>(DbContext context, long Id) where T : class, IHasId { return context.Set<T>() .FirstOrDefault(r => r.Id == Id); }
这种方式最简洁,EF Core能直接把r.Id == Id翻译成SQL的WHERE Id = @Id,只会查询符合条件的单条数据,完全没有性能问题。
2. 用表达式树动态构建查询条件
如果没办法修改实体类添加接口,可以用表达式树动态生成查询条件,代替反射:
using System.Linq.Expressions; public T GetEntity<T>(DbContext context, long Id) where T : class { // 构建参数表达式:r => var parameter = Expression.Parameter(typeof(T), "r"); // 获取Id属性的表达式:r.Id var idProperty = Expression.Property(parameter, "Id"); // 构建常量表达式:传入的Id值 var constant = Expression.Constant(Id, typeof(long)); // 构建相等判断表达式:r.Id == Id var equalCondition = Expression.Equal(idProperty, constant); // 转换成Lambda表达式 var predicate = Expression.Lambda<Func<T, bool>>(equalCondition, parameter); return context.Set<T>().FirstOrDefault(predicate); }
表达式树是EF Core能够识别的语法,会被转换成对应的SQL查询,同样只会加载目标数据,不会有全表扫描的性能问题。
不推荐的方案:显式客户端评估
虽然可以通过AsEnumerable()只对过滤逻辑做客户端评估,但本质还是会先加载表中部分数据到内存再过滤,性能远不如前两种方案,除非数据量极小,否则不建议用。
内容的提问来源于stack exchange,提问作者Shakeel Hussain Mir
相关产品推荐
相关产品推荐

