使用GridView和LINQ搜索引擎友好的自定义分页,到SQL

通过GridView控件提供的内置分页功能发现的主要问题是分页链接由JavaScript管理。对于禁用或没有浏览器没有JavaScript的人来说,这有点尴尬,但更重要的是,搜索引擎无法触发链接。如果您依靠GridView以分解到内容的链接,这可以证明灾难性,并且您的大部分内容将无法访问搜索引擎。激励Scott Guthrie在Linq上的博客条目的系列博客参赛作品,可用在.NET 3.5框架中,我设置了获取一些自定义分页使用HTML分页链接。

我不会打扰Linq到SQL的详细描述。格思里先生在他的一系列文章中做了一项很好的工作。足以说它允许我们在您选择的.NET语言中使用一组标准查询运算符查询数据源(或数据上下文)。我将使用Northwind SQL Server数据库作为此示例的数据上下文的基础。目前,LINQ到SQL类设计器仅支持SQL Server 2000和2005(包括Express)。要将LINQ键入SQL播放,请在右键单击解决方案资源管理器中的项目名称后“添加新项目...”,然后选择LINQ到SQL类。将dataclasses.dbml的名称更改为northwind.dbml。

接下来,从服务器资源管理器窗格拖动订单,订购详细信息,类别和产品表到Designer。结果将显示如下,同时,IDE将忙于为每个表创建实体类。

既然艰苦的工作是不合时宜的,创建一个名为custompaging.aspx的新的web表单,并将网格视图和文字控制拖到它上面。

现在,代码背后。我们将使用在Scott Gu's Blog条目中提供的4列数据(或生成的类的组合)的查询:

 

Northwinddatacontext.db =新的 Northwinddatacontext.();

 

var.查询= p DB.Products.

            在哪里p.order_details.count.> 2

            选择 新的

            {

              ID = p.ProductID,

             name = p.productname,

             numitders = p.order_details.count,

             收入= p.ORDER_DETAILS.SUM(o =>O.UnitPrice * O.Quantity)

            };

 

上面的LINQ查询语法使用新的标准LINQ查询运算符,该操作员可以使用2008版Visual Studio和Visual Web开发人员提供。这是一个声明性速记,它被编译成针对设计者创建的实体类的显式方法调用代码。编译代码利用新的3.5框架扩展方法和lambda表达式。更多关于这可能在这里阅读.

查询语法将被翻译成SQL语句,而且在不知道LINQ标准运算符或查询语法上,您可能已经猜测它将在ID的别名下返回ProductID,ProductName(名称),总计每个产品(Nuborders)的订单和通过将每种产品的单位价格乘以为所有订单(收入)销售的数量来计算的每种产品的收入。结果将返回到一个IEnumerable被叫查询,可以绑定到支持IEnumerable的任何控件。但是,在此刻,代码不会做任何事情,因为在实际尝试用结果进行事项之前执行执行,例如迭代它们。因此,通过添加以下行:

 

gridview1.datasource =查询;

gridview1.databind();

 

代码将在调用Databind()的点处执行,而不是之前。但是,这并不是真正服务于我们的目的。如果将GridView配置为分页,则将出现默认的JavaScript链接,如果不是,则会出现整个结果。我们的当前网格视图未配置为任何内容。所以我们将在代码后面实现分页。

Linq有许多非常有用的运算符,其中两个是skip()和take()。它们具有像分页一样的场景,因为它们被转换为使用SQL Server 2005的row_number,这允许您跳过一定数量的行,并且只需从该点占用有限的数量。这基本上意味着如果只想每页显示10个记录,则只需选择10个记录,而不是GridView和SQLDataSource的默认值,而不是整个结果集。因此,我们需要添加一些代码来计算我们正在进行的页面,以便我们可以告诉数据库跳过和采取多少行。我们还需要知道查询结果中有多少总页数。以下是:

 

totalRecords = query.count();

pageize = 10;

TotalPages = TotalRecords / PageSize;

 

TotalRecords使用count()方法。 LINQ实际上将在对数据库运行时将其转换为SELECT COUNT(*)查询。 intpagesize设置每页显示的记录数。 InttotalPages计算显示所有记录所需的总页数,并且只是作为整个数字返回的页面大小除以记录数量的结果。

现在我们有那个,我们只需要为分页创建HTML:

 

如果(TotalRecords%10> 0)

{

    totalPages += 1;

}

StringBuilder.SB =新的 StringBuilder.();

为了(我= 0;一世< totalPages; i++)

{

    pageno = i + 1;

    sb.Append("<一个href = custompaging.aspx?startrow =“+ PageSize * i +“>"+ pageno.tostring()+" ");

}

 

如果将记录总数除以页数的Modulo大于0,则需要将页面添加到总计以满足额外记录。例如,假设TotalRecords值为73.73 Mod 10为3,并且需要在第8页上显示这些额外的3条记录,以便需要添加到总数,因为TotalRecords / PageSize返回7,是整数从计算中的一部分结果。从那里,在循环中使用StringBuilder来构建将包含分页链接的HTML。我知道这个例子中只有70多个记录,所以我没有迎合了可以返回大量页面的情况。可以为此添加其他逻辑,确保大量的分页链接不会在页面上传播。

您会注意到分页链接包括查询字符串值,startrow,并且每次循环运行时,都会设置为pagesize(10)*循环计数器的值。这提供了具有行号的方法来开始拍摄记录。

现在,记录需要绑定到GridView,并且应用于文字控制的分页链接:

 

liter1.text =.“页: ”+ sb.tostring();

gridview1.dataSource = query.skip(startrow).take(10);

gridview1.databind();

 

take()方法通过PageSize的值,在这种情况下,这告诉LINQ一次获取10行。跳过方法通过另一个变量 - Startrow,它是QueryString ["startrous."] 价值。因此,所有剩余的都是要完成的,是在接受int的方法中包装此代码,然后在page_load()期间调用该方法。这是最终代码:

 

Northwinddatacontext.db =新的 Northwinddatacontext.();

 

var.查询= p DB.Products.

            在哪里p.order_details.count.> 2

            选择 新的

            {

              ID = p.ProductID,

             name = p.productname,

             numitders = p.order_details.count,

             收入= p.ORDER_DETAILS.SUM(o =>O.UnitPrice * O.Quantity)

            };

 

totalRecords = query.count();

pageize = 10;

TotalPages = TotalRecords / PageSize;

如果(TotalRecords%10> 0)

{

  totalPages += 1;

}

StringBuilder.SB =新的 StringBuilder.();

为了 (我= 0;一世< totalPages; i++)

{

  pageno = i + 1;

  sb.Append("<一个href = custompaging.aspx?startrow =“+ PageSize * i +“>"+ pageno.tostring()+" ");

}

liter1.text =.“页: ”+ sb.tostring();

gridview1.dataSource = query.skip(startrow).take(10);

gridview1.databind();

command.text =."

"+ db.getcommand(query.skip(startrow).take(10))。commandtext +"

";

 

这是一个很好的分页结果方式,也是搜索引擎友好的。但是,仍有一个小问题。对数据库执行两个查询:一个以获得10行数据,另一行数据以获取总数的记录。这与使用新的LinqDataSource并内置与GridView的内置分页差,这与GridView完全相同。但是,如果您担心最小化数据库调用,则在应用程序级别变量中存储TotalRecords的值并使用它是一个简单的事情。任何可能更改TotalRecords值的代码,例如插入,更新或删除,可以将应用程序变量的值设置为0,并且下次运行页面时,它将具有重新填充变量的作业:

 

突然学历;

如果 (兑换.Toint32(申请[“数数”])== 0)

{

 totalRecords = query.count();

  Application[“数数”] = TotalRecords;

}

别的

{

  totalRecords = 兑换.Toint32(申请[“数数”]);

}