65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 DataLoadOptions 优化 LINQ 查询

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (24投票s)

2009年7月4日

CPOL

4分钟阅读

viewsIcon

93081

downloadIcon

968

使用 DataLoadOptions 优化 LINQ 查询

目录

引言

感谢所有曾经有意/无意帮助我成为微软 MVP 的人,希望我能做到。

在本节中,我们将了解 LINQ 的往返问题以及如何使用 'DataLoadOptions' 克服这个问题。 LINQ to SQL 最大的问题之一是它为每个对象触发 SQL 查询,这对性能有巨大影响。 在本文中,我们将看到如何在一个 SQL 查询中获取所有数据。

LINQ 基础

本文假设您对如何使用 LINQ 丰富实体对象有基本的了解。 如果您不了解 LINQ to SQL 映射的基础知识,您可以 阅读我的文章 来理解基本的 LINQ 概念。

客户、地址和电话 LINQ 实体

首先让我们尝试了解 LINQ 查询实际上是如何工作的,然后我们将看到往返是如何发生的。 让我们考虑以下数据库设计,其中我们有 3 个表 -- customer, addresses phonecustomer addresses 之间存在一对多的关系,而 address 表和 phones 之间存在一对一的关系。

我们根据表设计创建了三个实体

  • ClsCustomerWithAddresses
  • ClsAddresses
  • ClsPhone

我们使用 'EntitySet' 和 'EntityRef' 定义了它们之间的关系。

Click to enlarge image

从表中填充实体对象数据的过程分为 5 个步骤。 作为第一步,使用连接字符串创建 datacontext 连接,创建 LINQ 查询,然后我们开始浏览 customer, address phones

Click to enlarge image

分析 LINQ SQL 往返

好的,现在我们已经分析了执行 LINQ 查询需要 5 个步骤,让我们试着找出 LINQ 查询实际上在哪个步骤向数据库触发 SQL。 所以我们将做的是运行上面的 LINQ 代码并使用 SQL 分析器分析它。

为了避免捕获大量的 SQL Server 噪声,我们只启用了 RPC 和 SQL 批处理事件。

现在,当您运行查询时,您会发现以下内容

  • 当在 LINQ 对象上迭代 foreach 语句时,实际的 SQL 执行发生。
  • 您会注意到的第二件非常令人惊讶的事情是,对于每个实体,都会向 SQL Server 触发一个单独的查询。 例如,为 customer 触发一个查询,然后为 address phones 分别触发查询来丰富实体对象。 换句话说,有很多往返。

Click to enlarge image

使用 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。

Click to enlarge image

源代码

我们还附带了源代码。 运行该项目,看看分析器如何显示不同的 SQL 执行。 您可以先运行 'EntitySet' 示例,看看 SQL 分析器对此的反应,然后运行带有 'DataLoadOptions' 的示例。 SQL 脚本附在一个不同的文件中。

))==:- 您可以从 此处 下载源代码。

如需进一步阅读,请观看以下面试准备视频和分步视频系列。

© . All rights reserved.