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>
以表明任何进一步的处理都将在内存中完成.
我正在使用 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>
以表明任何进一步的处理都将在内存中完成.