从 LINQ 生成的 SQL 不一致

Posted

技术标签:

【中文标题】从 LINQ 生成的 SQL 不一致【英文标题】:SQL generated from LINQ not consistent 【发布时间】:2016-11-30 15:54:47 【问题描述】:

我正在针对 ORACLE 使用 Telerik Open/Data Access 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 生成的查询返回,显然当我只想要一条时,表中的每条记录。数以百万计的记录使这令人望而却步。

【问题讨论】:

看起来投影被 ORM 返回为IEnumerable。在第一个语句之后的两种情况下query 的类型是什么? 它们都是 IQueryable(更新原帖) 具体类型呢? 这不是 PL/SQL 问题。我想你的意思是sql 【参考方案1】:

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

【讨论】:

【参考方案2】:

第一个查询返回定义的完整对象,因此可以在实际运行之前将任何其他限制(如Where)附加到它。因此,可以按照您的说明组合查询。

第二个返回一个新对象,它可以是任何类型并包含任何信息。因此,查询以“返回所有内容”的形式发送到数据库,并且在创建对象后,除了与 Where 子句匹配的对象之外的所有对象都将被丢弃。

即使两者的类型相同,想想这种情况:

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

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

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

【讨论】:

在像实体框架这样的 ORM 中,整个表达式(包括 wiTranmits.MessageID * 4 - 2)将被翻译成 SQL,因此按 MessageID 进行排序/过滤也将显示在查询中。我认为 Telerik 在这里有不同的策略。 也许更好的检查是 MessageID = LocalFunction(wiTransmits.MessageID),

以上是关于从 LINQ 生成的 SQL 不一致的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 管理对象 (SMO) 的默认约束不一致

LINQ to SQL [npgsql] 从 SelectMany 生成不正确的查询

sql 2012主从怎么总是不同步

Linq查询条件怎么查询呢

Linq-to-SQL 和 DateTime 的怪异

使用 ODBC 的 SQL 查询时间不一致