SQL 从 LINQ 生成不一致

SQL generated from LINQ not consistent

我正在使用 Telerik Open/Data 针对 ORACLE 访问 ORM。

为什么这两个语句会导致不同的 SQL 命令?

语句#1

 IQueryable<WITransmits> query = from wiTransmits in uow.DbContext.StatusMessages
            select wiTransmits;

query = query.Where(e=>e.MessageID == id);

结果如下SQL

SELECT 
    a."MESSAGE_ID" COL1, 
   -- additional fields
FROM "XFE_REP"."WI_TRANSMITS" a 
WHERE 
    a."MESSAGE_ID" = :p0

语句#2

 IQueryable<WITransmits> query = from wiTransmits in uow.DbContext.StatusMessages
            select new WITransmits
            {
                MessageID = wiTranmits.MessageID,
                Name = wiTransmits.Name
            };

query = query.Where(e=>e.MessageID == id);

结果如下SQL

SELECT 
    a."MESSAGE_ID" COL1, 
   -- additional fields
FROM "XFE_REP"."WI_TRANSMITS" a 

用第二条语句#2 returns 生成的查询,显然 table 中的每条记录,而我只想要一条。数以百万计的记录使这令人望而却步。

第一个查询 returns 定义了完整的对象,因此可以在它实际 运行 之前附加任何附加限制(如 Where)。因此,可以按照您显示的方式组合查询。

第二个returns一个新对象,可以是任何类型,包含任何信息。因此,查询将作为 "return everything" 发送到数据库,并且在创建对象之后,除了与 Where 子句匹配的对象之外的所有对象都将被丢弃。

尽管两者的类型相同,但想想这种情况:

var query = from wiTransmits in uow.DbContext.StatusMessages
    select new WITransmits
    {
        MessageID = wiTranmits.MessageID * 4 - 2,
        Name = wiTransmits.Name
    };

您现在如何组合 Where 查询?当然,您可以通过新对象创建中的代码并尝试将其移到外部,但由于可以有 anything,所以这是不可行的。如果检查是一些查找功能怎么办?如果它不是确定性的怎么办?

因此,如果您基于数据库对象创建新对象,将会有一个边界,其中将检索对象,然后将在内存中进行进一步查询。

Telerik Data Access 将尝试将每个查询拆分为数据库端和客户端(如果您愿意,也可以是内存中的 LINQ)。
使用 select new 进行投影肯定会触发,这将使投影后 LINQ 表达式树中的所有内容都转到客户端。
这意味着在你的第二种情况下,你的 LINQ 查询效率低下,因为任何过滤都是在内存中应用的,并且你已经传输了大量不必要的数据。
如果您想按照案例 2 中的方式编写 LINQ 表达式,您可以在最后附加 Select 子句或将结果显式转换为 IEnumerable<T> 以表明任何进一步的处理都将在内存中完成.