EF 7中GroupBy结合EF.Property()提示属性不存在的原因
问题场景
简化后的查询代码如下:
var queryable = _dbContext.Journal.GroupBy(x => x.TicketId) .Select(x => x.OrderByDescending(y => y.BeginDate).First()); queryable = queryable.Where(p => EF.Property<bool>(p, "IsDeleted") == false); await queryable.ToListAsync()
执行时抛出异常:
Translation of
'EF.Property<bool>(ProjectionBindingExpression: 0, "IsDeleted")'failed. Either the query source is not an entity type, or the specified property does not exist on the entity type
已知IsDeleted属性在模型和数据库中均存在,且不使用GroupBy时代码可正常运行。
原因分析
当你使用GroupBy后再通过Select(x => x.OrderByDescending(...).First())获取分组内的第一条数据时,EF Core会将这个结果视为投影绑定表达式(ProjectionBindingExpression),而非明确的Journal实体类型。此时用EF.Property去访问属性,EF无法从这个投影对象中获取实体元数据,自然会判定属性不存在或数据源不是实体类型。
简单说:分组后的投影操作让EF丢失了对原实体类型的明确识别,导致动态属性访问失效。
解决办法
方案1:提前过滤软删除数据(推荐)
先过滤掉已删除的数据,再执行分组操作,既保证EF能正确识别实体属性,又能减少分组的数据量,提升查询效率:
var queryable = _dbContext.Journal .Where(p => !p.IsDeleted) .GroupBy(x => x.TicketId) .Select(x => x.OrderByDescending(y => y.BeginDate).First()); await queryable.ToListAsync();
方案2:显式指定实体类型并直接访问属性
如果必须在分组后过滤,可通过显式类型转换让EF识别原实体类型,同时直接访问属性而非使用EF.Property:
var queryable = _dbContext.Journal.GroupBy(x => x.TicketId) .Select(x => x.OrderByDescending(y => y.BeginDate).First() as Journal); queryable = queryable.Where(p => !p.IsDeleted); await queryable.ToListAsync();
注意:这种方式可能会导致过滤逻辑在内存中执行(取决于EF Core的查询翻译能力),性能不如方案1。
内容的提问来源于stack exchange,提问作者SUDALV

