You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在LINQ表达式树中访问TPH类型的属性?

问题描述

我有两个SQL Server表:Order和OrderDetail。基于这些表定义了三个C#类:Order映射至Order表,OrderDetail(抽象基类)和SpecialOrderDetail(继承自前者)采用TPH(表每层次继承)方式映射至OrderDetail表。

我需要获取所有满足以下条件的Order:

  • Type为0,或者
  • 关联的Detail是SpecialOrderDetail且其SpecialType为0

尝试了以下代码:

var orders = database.Order.Where(od => od.Type == 0
    || (od.Detail is SpecialOrderDetail sp && sp.SpecialType == 0)).ToList();

但Visual Studio报错:CS8122: An expression tree may not contain an 'is' pattern-matching operator。

因为无法将SpecialOrderDetail的SpecialType属性移至OrderDetail类,目前采用的替代方案是:

var orders = database.Order.Where(od => od.Type == 0
    || od.Detail is SpecialOrderDetail).ToList();
orders.RemoveAll(od => od.Type != 0
    && od.Detail is SpecialOrderDetail sp && sp.SpecialType != 0);

但这个方案需要重复检查Type,还会从数据库拉取不必要的记录后再过滤。请问在不使用原生SQL语句的情况下,能否将SpecialType检查直接放入数据库查询中?我使用的是.NET Framework 4.8和Entity Framework 6.1.3。

解决方案

EF6.1.3的表达式树不支持is模式匹配操作,但可以通过以下两种方式将过滤条件推送到数据库执行,避免内存中二次过滤:

方法1:显式类型转换+空值检查

利用TPH的映射特性,EF6会自动将类型转换和属性检查翻译成对应的SQL(包含判别列校验和属性值过滤):

var orders = database.Order.Where(od => od.Type == 0
    || ((od.Detail as SpecialOrderDetail) != null && (od.Detail as SpecialOrderDetail).SpecialType == 0)).ToList();

方法2:使用OfType<T>关联查询

如果Order和OrderDetail是一对多关系(导航属性为Order.Details集合),可以结合Any和OfType实现过滤:

var orders = database.Order.Where(od => od.Type == 0
    || od.Details.OfType<SpecialOrderDetail>().Any(sp => sp.SpecialType == 0)).ToList();

如果是一对一关系(Order.Detail为单个实体),可以通过关联主键的方式查询:

var orders = database.Order.Where(od => od.Type == 0
    || database.OrderDetail.OfType<SpecialOrderDetail>().Any(sp => sp.OrderId == od.Id && sp.SpecialType == 0)).ToList();

以上两种方法都会让数据库直接执行完整的过滤逻辑,不会拉取冗余数据。

内容的提问来源于stack exchange,提问作者formicini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 12:15:32