Asp.net 简明教程

ASP.NET - LINQ

大多数应用程序以数据为中心,但是大多数数据存储库都是关系数据库。多年来,设计人员和开发人员已经基于对象模型设计应用程序。

这些对象负责连接到数据访问组件 - 称为数据访问层 (DAL)。我们在此处需考虑三点:

  1. 应用程序中所需的所有数据不会存储在同一来源中。该来源可以是关系数据库、某些业务对象、XML 文件或 web 服务。

  2. 访问内存中对象比访问数据库或 XML 文件中的数据更简单、更经济。

  3. 访问的数据不会直接使用,但需要对其进行排序、排序、分组、更改等操作。

因此,如果有一种工具可以简化各种数据访问,允许连接来自此类不同数据源的数据并在几行代码中执行标准数据处理操作,那将会有很大帮助。

LINQ 或语言集成查询就是这样一种工具。LINQ 是 .Net Framework 3.5 及其托管语言的一组扩展,它们将查询设置为了一个对象。它定义了一个通用语法和一个编程模型,用于使用通用语言查询不同类型的数据。

关系运算符(如 Select、Project、Join、Group、Partition、Set 运算等)在 LINQ 和 .Net Framework 3.5 中的 C# 和 VB 编译器中实现,支持 LINQ 语法,使得无需使用 ADO.NET 即可处理已配置的数据存储。

例如,使用 C# 中的 LINQ 查询查询 Northwind 数据库中的 Customer 表,代码将是:

var data = from c in dataContext.Customers
where c.Country == "Spain"
select c;

其中:

  1. “from” 关键字在逻辑上循环遍历集合的内容。

  2. 对于集合中的每个对象,都会对带有 “where” 关键字的表达式进行求值。

  3. “select” 语句会选择要添加到作为返回值的列表中的已求值对象。

  4. “var” 关键字用于变量声明。由于无法已知已返回对象的具体类型,因此,它指示将动态地推断这些信息。

LINQ 查询可以应用到从 IEnumerable<T> 继承的任何承载数据的类,此处 T 是任何数据类型,例如 List<Book>。

我们来看一个示例以理解这个概念。本示例使用以下类:Books.cs

public class Books
{
   public string ID {get; set;}
   public string Title { get; set; }
   public decimal Price { get; set; }
   public DateTime DateOfRelease { get; set; }

   public static List<Books> GetBooks()
   {
      List<Books> list = new List<Books>();
      list.Add(new Books { ID = "001",
         Title = "Programming in C#",
         Price = 634.76m,
         DateOfRelease = Convert.ToDateTime("2010-02-05") });

      list.Add(new Books { ID = "002",
         Title = "Learn Java in 30 days",
         Price = 250.76m,
         DateOfRelease = Convert.ToDateTime("2011-08-15") });

      list.Add(new Books { ID = "003",
         Title = "Programming in ASP.Net 4.0",
         Price = 700.00m,
         DateOfRelease = Convert.ToDateTime("2011-02-05") });

      list.Add(new Books { ID = "004",
         Title = "VB.Net Made Easy",
         Price = 500.99m,
         DateOfRelease = Convert.ToDateTime("2011-12-31") });

      list.Add(new Books { ID = "005",
         Title = "Programming in C",
         Price = 314.76m,
         DateOfRelease = Convert.ToDateTime("2010-02-05") });

      list.Add(new Books { ID = "006",
         Title = "Programming in C++",
         Price = 456.76m,
         DateOfRelease = Convert.ToDateTime("2010-02-05") });

      list.Add(new Books { ID = "007",
         Title = "Datebase Developement",
         Price = 1000.76m,
         DateOfRelease = Convert.ToDateTime("2010-02-05") });

      return list;
   }
}

使用此类的网页具有一个简单的标签控件,该控件会显示书籍的标题。Page_Load 事件会创建一个书籍列表,并使用 LINQ 查询返回这些标题:

public partial class simplequery : System.Web.UI.Page
{
   protected void Page_Load(object sender, EventArgs e)
   {
      List<Books> books = Books.GetBooks();
      var booktitles = from b in books select b.Title;

      foreach (var title in booktitles)
         lblbooks.Text += String.Format("{0} <br />", title);
   }
}

当执行该页时,标签会显示查询结果:

linq result

上述 LINQ 表达式:

var booktitles =
from b in books
select b.Title;

等效于以下 SQL 查询:

SELECT Title from Books

LINQ Operators

除了迄今使用的运算符外,还有其他多个运算符,这些运算符能够实现所有查询子句。我们来看一些运算符和子句。

The Join clause

SQL 中的 “join 子句” 用于连接两个数据表,并显示包含两个表中的列的数据集。LINQ 也能够执行此操作。为检查这一点,在上一个项目中添加名为 Saledetails.cs 的另一个类:

public class Salesdetails
{
   public int sales { get; set; }
   public int pages { get; set; }
   public string ID {get; set;}

   public static IEnumerable<Salesdetails> getsalesdetails()
   {
      Salesdetails[] sd =
      {
         new Salesdetails { ID = "001", pages=678, sales = 110000},
         new Salesdetails { ID = "002", pages=789, sales = 60000},
         new Salesdetails { ID = "003", pages=456, sales = 40000},
         new Salesdetails { ID = "004", pages=900, sales = 80000},
         new Salesdetails { ID = "005", pages=456, sales = 90000},
         new Salesdetails { ID = "006", pages=870, sales = 50000},
         new Salesdetails { ID = "007", pages=675, sales = 40000},
      };

      return sd.OfType<Salesdetails>();
   }
}

将代码添加到 Page_Load 事件处理程序中,以便使用 join 子句查询这两个表:

protected void Page_Load(object sender, EventArgs e)
{
   IEnumerable<Books> books = Books.GetBooks();
   IEnumerable<Salesdetails> sales = Salesdetails.getsalesdetails();

   var booktitles = from b in books join s in sales on b.ID equals s.ID
      select new { Name = b.Title, Pages = s.pages };

   foreach (var title in booktitles)
      lblbooks.Text += String.Format("{0} <br />", title);
}

由此产生如下所示的页面:

linq result2

The Where clause

“where 子句” 允许向查询添加一些条件筛选器。例如,如果您想要查看那些页数超过 500 的书,应将 Page_Load 事件处理程序更改为:

var booktitles = from b in books join s in sales on b.ID equals s.ID
   where s.pages > 500 select new { Name = b.Title, Pages = s.pages };

该查询仅返回页数超过 500 的那些行:

linq result3

Orderby and Orderbydescending Clauses

这些子句允许对查询结果进行排序。若要按价格对书的标题、页数和价格进行查询和排序,请在 Page_Load 事件处理程序中编写以下代码:

var booktitles = from b in books join s in sales on b.ID equals s.ID
   orderby b.Price select new { Name = b.Title,  Pages = s.pages, Price = b.Price};

返回的元组为:

linq result4

The Let clause

let 子句允许定义一个变量,并根据数据值计算的值为其赋值。例如,若要计算上述两笔销售的总销售额,您需要计算:

TotalSale = Price of the Book * Sales

为了实现此目标,添加以下代码段在 Page_Load 事件处理程序中:

let 子句允许定义一个变量,并根据数据值计算的值为其赋值。例如,若要计算上述两笔销售的总销售额,您需要计算:

var booktitles = from b in book join s in sales on b.ID equals s.ID
   let totalprofit = (b.Price * s.sales)
   select new { Name = b.Title, TotalSale = totalprofit};

产生的查询页面如下所示:

linq result5