使用 DataLoadOptions 优化 LINQ 查询






4.86/5 (24投票s)
使用 DataLoadOptions 优化 LINQ 查询
目录
引言
感谢所有曾经有意/无意帮助我成为微软 MVP 的人,希望我能做到。
在本节中,我们将了解 LINQ 的往返问题以及如何使用 'DataLoadOptions
' 克服这个问题。 LINQ to SQL 最大的问题之一是它为每个对象触发 SQL 查询,这对性能有巨大影响。 在本文中,我们将看到如何在一个 SQL 查询中获取所有数据。
LINQ 基础
本文假设您对如何使用 LINQ 丰富实体对象有基本的了解。 如果您不了解 LINQ to SQL 映射的基础知识,您可以 阅读我的文章 来理解基本的 LINQ 概念。
客户、地址和电话 LINQ 实体
首先让我们尝试了解 LINQ 查询实际上是如何工作的,然后我们将看到往返是如何发生的。 让我们考虑以下数据库设计,其中我们有 3 个表 -- customer
, addresses
和 phone
。 customer
和 addresses
之间存在一对多的关系,而 address
表和 phones
之间存在一对一的关系。
我们根据表设计创建了三个实体
ClsCustomerWithAddresses
ClsAddresses
ClsPhone
我们使用 'EntitySet
' 和 'EntityRef
' 定义了它们之间的关系。
从表中填充实体对象数据的过程分为 5 个步骤。 作为第一步,使用连接字符串创建 datacontext
连接,创建 LINQ 查询,然后我们开始浏览 customer
, address
和 phones
。
分析 LINQ SQL 往返
好的,现在我们已经分析了执行 LINQ 查询需要 5 个步骤,让我们试着找出 LINQ 查询实际上在哪个步骤向数据库触发 SQL。 所以我们将做的是运行上面的 LINQ 代码并使用 SQL 分析器分析它。
为了避免捕获大量的 SQL Server 噪声,我们只启用了 RPC 和 SQL 批处理事件。
现在,当您运行查询时,您会发现以下内容
- 当在 LINQ 对象上迭代
foreach
语句时,实际的 SQL 执行发生。 - 您会注意到的第二件非常令人惊讶的事情是,对于每个实体,都会向 SQL Server 触发一个单独的查询。 例如,为
customer
触发一个查询,然后为address
和phones
分别触发查询来丰富实体对象。 换句话说,有很多往返。
使用 DataLoadOptions 避免往返
我们可以指示 LINQ 引擎使用 'DataLoadOptions
' 加载所有对象。 以下是启用 'DataLoadOptions
' 涉及的步骤。
第一步是创建数据上下文类
DataContext objContext = new DataContext(strConnectionString);
第二步是创建 'DataLoadOption
' 对象
DataLoadOptions objDataLoadOption = new DataLoadOptions();
使用 LoadWith
方法,我们需要定义我们希望在同一个 SQL 中使用 address
加载 customer
。
objDataLoadOption.LoadWith<clsCustomerWithAddresses>
(clsCustomerWithAddresses => clsCustomerWithAddresses.Addresses);
每个 address
对象都有 phone
对象,因此我们还定义了要加载的 phone
对象,用于每个 address
对象,并放入一个 SQL 中。
objDataLoadOption.LoadWith<clsAddresses>(clsAddresses => clsAddresses.Phone);
无论您定义了什么加载选项,您都需要使用 'LoadOptions
' 属性将相同的设置到数据上下文对象。
objContext.LoadOptions = objDataLoadOption;
最后准备好您的查询
var MyQuery = from objCustomer in objContext.GetTable<clsCustomerWithAddresses>()
select objCustomer;
开始循环遍历对象
foreach (clsCustomerWithAddresses objCustomer in MyQuery)
{
Response.Write(objCustomer.CustomerName + "<br>");
foreach (clsAddresses objAddress in objCustomer.Addresses)
{
Response.Write("===Address:- " + objAddress.Address1 + "<br>");
Response.Write("========Mobile:- " + objAddress.Phone.MobilePhone + "<br>");
Response.Write("========LandLine:- " + objAddress.Phone.LandLine + "<br>");
}
}
以下是完整的源代码
DataContext objContext = new DataContext(strConnectionString);
DataLoadOptions objDataLoadOption = new DataLoadOptions();
objDataLoadOption.LoadWith<clsCustomerWithAddresses>
(clsCustomerWithAddresses => clsCustomerWithAddresses.Addresses);
objDataLoadOption.LoadWith<clsAddresses>(clsAddresses => clsAddresses.Phone);
objContext.LoadOptions = objDataLoadOption;
var MyQuery = from objCustomer in objContext.GetTable<clsCustomerWithAddresses>()
select objCustomer;
foreach (clsCustomerWithAddresses objCustomer in MyQuery)
{
Response.Write(objCustomer.CustomerName + "<br>");
foreach (clsAddresses objAddress in objCustomer.Addresses)
{
Response.Write("===Address:- " + objAddress.Address1 + "<br>");
Response.Write("========Mobile:- " + objAddress.Phone.MobilePhone + "<br>");
Response.Write("========LandLine:- " + objAddress.Phone.LandLine + "<br>");
}
}
阿拉卡萨巴拉....现在,如果您运行代码,LINQ 只执行了一个带有正确连接的 SQL,而之前为每个对象显示了 3 个 SQL。
源代码
我们还附带了源代码。 运行该项目,看看分析器如何显示不同的 SQL 执行。 您可以先运行 'EntitySet
' 示例,看看 SQL 分析器对此的反应,然后运行带有 'DataLoadOptions
' 的示例。 SQL 脚本附在一个不同的文件中。
))==:- 您可以从 此处 下载源代码。
如需进一步阅读,请观看以下面试准备视频和分步视频系列。