LinqDataSource 控件通过 ASP.NET 数据源控件结构向 Web 开发人员公开语言集成查询 (LINQ)。LINQ 提供一种用于在不同类型的数据源中查询和更新数据的统一编程模型,并将数据功能直接扩展到 C# 和 Visual Basic 语言中。LINQ 通过将面向对象编程的准则应用于关系数据,简化了面向对象编程与关系数据之间的交互。
通过使用声明性标记,可以创建一个 LinqDataSource 控件,连接到数据库或内存中数据集合(如数组)中的数据。在声明文本中,可以编写对数据进行检索、筛选、排序和分组操作所需的所有条件。当从 SQL 数据库表检索数据时,也可以配置 LinqDataSource 控件以处理数据的更新、插入和删除。该控件可做到这一点,而无需您编写 SQL 命令来执行这些任务。LinqDataSource 类还提供一个事件模型,使您能够处理自定义方案。
一、方案
当您创建网页以检索或修改数据,并希望利用 LINQ 提供的统一编程模型时,可使用 LinqDataSource 控件。通过使 LinqDataSource 控件能够自动创建与数据进行交互的命令,可以简化网页中的代码。
二、背景
LinqDataSource 控件为您提供了一种将数据控件连接到多种数据源的方法,其中包括数据库数据、数据源类和内存中集合。通过使用 LinqDataSource 控件,您可以针对所有这些类型的数据源指定类似于数据库检索的任务(选择、筛选、分组和排序)。可以指定针对数据库表的修改任务(更新、删除和插入)。
可以将 LinqDataSource 控件连接到存储在公共字段或属性中的任何类型的数据集合。对于所有数据源来说,用于执行数据操作的声明性标记和代码都是相同的。当您与数据库表中的数据或数据集合(与数组类似)中的数据进行交互时,不必使用不同的语法。
2.1、连接到数据库中的数据
当您与数据库中的数据进行交互时,不会将 LinqDataSource 控件直接连接到数据库,而是与表示数据库和表的实体类进行交互。通过对象关系设计器或运行 SqlMetal.exe 实用工具可生成实体类。创建的实体类通常位于 Web 应用程序的 App_Code 文件夹中。O/R 设计器或 SqlMetal.exe 实用工具将生成一个表示数据库的类,并为该数据库中的每个表生成一个类。
表示数据库的类将负责检索和设置数据源中的值。LinqDataSource 控件读取和设置表示数据表的类中的属性。若要支持更新、插入和删除操作,数据库类必须从 DataContext 类派生,且表类必须引用 Table<(Of <(TEntity>)>) 类。
通过将 ContextTypeName 属性设置为表示数据库的类的名称,将 LinqDataSource 控件连接到数据库类。通过将 TableName 属性设置为代表数据表的类的名称,将 LinqDataSource 控件连接到特定表。例如,若要连接到 AdventureWorks 数据库中的 Contacts 表,可将 ContextTypeName 属性设置为 AdventureWorksDataContext(或您为数据库对象指定的任何名称)。将 TableName 属性设置为 Contacts。下面的示例显示连接到 AdventureWorks 数据库的 LinqDataSource 控件的标记。
<asp:LinqDataSource
ContextTypeName="AdventureWorksDataContext"
TableName="Contacts"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
此示例不显示由 O/R 设计器生成的类,因为生成的代码对于本主题来说太长。不过,若要此示例正常运行,生成的代码必须存在。
2.2、连接到内存中的集合中的数据
当连接到内存中的数据集合(与数组类似)时,将 ContextTypeName 属性设置为包含该集合的类的名称。将 TableName 属性设置为集合本身的名称。
下面的示例显示一个类,其中包含一个字符串值数组。
public class MovieLibrary
{
string[] _availableGenres = { "Comedy", "Drama", "Romance" };
public MovieLibrary()
{
}
public string[] AvailableGenres
{
get
{
return _availableGenres;
}
}
}
下面的代码显示一个 LinqDataSource 控件,该控件从上一示例中的类读取影片流派列表。若要检索流派数组,请将 ContextTypeName 属性设置为 MovieLibrary,并将 TableName 属性设置为 AvailableGenres。
<asp:LinqDataSource
ContextTypeName="MovieLibrary"
TableName="AvailableGenres"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
2.3、将 LinqDataSource 控件与数据绑定控件一起使用
若要显示 LinqDataSource 控件中的数据,可将数据绑定控件绑定到 LinqDataSource 控件。例如,将 DetailsView 控件、GridView 控件或 ListView 控件绑定到 LinqDataSource 控件。为此,将数据绑定控件的 DataSourceID 属性设置为 LinqDataSource 控件的 ID。下面的示例说明一个 GridView 控件,该控件显示 LinqDataSource 控件中的所有数据。
<asp:LinqDataSource
runat="server"
ContextTypeName="AdventureWorksDataContext"
TableName="Contacts"
ID="LinqDataSource1">
</asp:LinqDataSource>
<asp:GridView
ID="GridView1"
runat="server"
DataSourceID="LinqDataSource1" >
</asp:GridView>
数据绑定控件将自动创建用户界面以显示 LinqDataSource 控件中的数据。它还提供用于对数据进行排序和分页的界面。在启用数据修改后,数据绑定控件会提供用于更新、插入和删除记录的界面。
通过将数据绑定控件配置为不自动生成数据控件字段,可以限制显示的数据(属性)。然后可以在数据绑定控件中显式定义这些字段。虽然 LinqDataSource 控件会检索所有属性,但数据绑定控件仅显示指定的属性。下面的示例演示一个 GridView 控件,该控件仅显示 AdventureWorks 数据库的 Products 表中的 Name 和 StandardCost 属性。AutoGenerateColumns 属性设置为 false。
<asp:LinqDataSource
ContextTypeName="AdventureWorksDataContext"
TableName="Products"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
<asp:GridView
DataSourceID="LinqDataSource1"
AutoGenerateColumns="false"
ID="GridView1"
runat="server">
<Columns>
<asp:BoundField DataField="Name" />
<asp:BoundField DataField="StandardCost" />
</Columns>
</asp:GridView>
如果必须限制查询中返回的属性,请通过设置 LinqDataSource 控件的 Select 属性来定义那些属性。
2.4、将 LinqDataSource 控件与其他数据源控件进行比较
与使用 SqlDataSource 或 ObjectDataSource 控件相比,通过使用 LinqDataSource 控件,可以编写较少的代码来执行数据操作。LinqDataSource 控件可推断有关要连接到的数据源的信息,并动态创建用于选择、更新、插入和删除数据的命令。当使用 LinqDataSource 控件时,您只需了解一个编程模型就可以与不同类型的数据源进行交互。
2.5、比较 SqlDataSource 控件
与 SqlDataSource 控件不同(该控件仅可用于关系数据库表),使用 LinqDataSource 控件可连接到存储在内存中的集合中的数据。当使用 SqlDataSource 控件时,必须将 SelectCommand、UpdateCommand、InsertCommand 和 DeleteCommand 属性显式设置为 SQL 查询。不过,借助于 LinqDataSource 控件,您就无需显式设置这些命令,因为 LinqDataSource 控件将使用 LINQ to SQL 自动创建它们。如果希望修改从数据源中选择的列,则不必编写完整的 SQL Select 命令,只需在 Select 属性中提供要在查询中返回的列名称即可。
当更新或插入数据时,无需为将保存到数据库中的每个值创建参数。LinqDataSource 控件可创建包含适当值的更新命令,方法是将 DataField 属性与实体类中的属性名进行匹配。
2.6、比较 ObjectDataSource 控件
当使用 ObjectDataSource 控件时,必须手动创建表示数据的对象,然后编写用于与数据进行交互的方法。然后,必须将 SelectMethod、UpdateMethod、InsertMethod 和 DeleteMethod 属性与执行这些函数的方法进行匹配。在 LinqDataSource 控件中,可使用 O/R 设计器自动创建表示数据的类。无需编写代码来指定数据库表中存在哪些列或指定如何选择、更新、插入和删除数据。此外,还可以使用 LinqDataSource 控件以类似于数组的方式与数据集合直接进行交互。在此情况下,无需创建一个类来处理与数据集合进行交互的逻辑。
2.7、选择数据
如果不指定 LinqDataSource 控件的 Select 属性的值,则检索数据源类中的所有属性。例如,LinqDataSource 控件为数据库表中的每个列返回一个值。
通过将 Select 属性设置为所需属性的名称,可以限制从数据源中检索的属性。如果希望仅返回一个属性,请将 Select 属性设置为该属性。例如,若要仅返回数据库表的 City 列中的值,请将 Select 属性设置为 City。LinqDataSource 控件将返回 List<(Of <(T>)>) 集合,该集合包含属性中正确键入的项。如果以文本(字符串)形式键入 City 属性,则选择 City 属性会返回字符串值的 List<(Of <(T>)>) 集合。
若要仅检索数据类中的一些属性,请使用 Select 属性中的 new 函数并指定要返回的列。由于您是在动态创建仅包含已指定的属性的类,因此 new 函数是必需的。例如,如果要从包含完整地址的数据源中检索 City 和 PostalCode 属性,请将 Select 属性设置为 new(City, PostalCode)。LinqDataSource 控件将返回 List<(Of <(T>)>) 集合,该集合包含具有这些属性的类的实例。
当您仅选择一个属性时,无需使用 new 函数,因为返回的对象是该属性的值的简单集合。但对于多个属性,LinqDataSource 控件必须创建一个包含您指定的属性的新类。
2.8、使用 Select 子句计算值
可以在 Select 子句中计算值。例如,若要计算某个订单的行项总计,请将 Select 属性设置为 new(SalesOrderDetailID, OrderQty * UnitPrice As LineItemTotal)。使用 As 关键字可为计算的值分配一个名称(别名)。
下面的示例演示如何使用 LinqDataSource 控件检索数据的子集。在此示例中,将设置 Select 属性以便为返回的值分配别名并计算值。
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="OrderDetails"
Select="new(SalesOrderDetailID As DetailID,
OrderQty * UnitPrice As LineItemTotal,
DateCreated As SaleDate)"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
2.9、使用 Where 子句筛选数据
可以对返回的数据进行筛选,以便仅检索满足特定条件的记录。可以通过将 Where 属性设置为要在返回的数据中包含某个记录所必须满足的条件来做到这一点。如果不指定 Where 属性的值,则检索数据源中的所有记录。可通过创建筛选器表达式进行筛选,该表达式通过比较来确定是否应包含某个记录。比较的对象可以是一个静态值,也可以是您通过参数占位符指定的变量值。
2.10、使用静态值创建 Where 子句
当您将一个属性中的值与静态值进行比较时,将使用该属性和静态值定义 Where 属性。例如,若要仅返回其 ListPrice 值大于 1000 的记录,请将 Where 属性设置为 ListPrice > 1000。
可以使用 && 或 and 运算符表示逻辑“与”,也可以使用 || 或 or 运算符表示逻辑 “或”。例如,将 Where 属性设置为 ListPrice > 1000 || UnitCost > 500 || DaysToManufacture > 3 可返回符合以下条件的记录:ListPrice 值大于 1000,或 UnitCost 值大于 500,或 DaysToManufacture 值大于 3。若要指定必须在所有条件为真时才返回记录,则应将 Where 属性设置为 ListPrice > 1000 && UnitCost > 500 && DaysToManufacture > 3。
当比较字符串值时,必须用单引号将条件括起来,并用双引号将文本值括起来。例如,将 Where 属性设置为 'Category = "Sports"' 可仅检索其 Category 列等于“Sports”的记录。
下面的示例演示一个 LinqDataSource 控件,该控件检索已按照字符串值和数值筛选的数据。
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="Product"
Where='Category = "Sports" && Weight < 10'
ID="LinqDataSource1"
runat="server"
</asp:LinqDataSource>
2.11、创建参数化 Where 子句
如果要将属性值与仅在运行时才知道的值进行比较,可以在 WhereParameters 属性集合中定义一个参数。例如,如果要使用由用户提供的值进行筛选,请创建表示该值的参数。LinqDataSource 控件使用参数的当前值创建 Where 子句。
下面的示例演示一个 LinqDataSource 控件,该控件根据用户在名为 DropDownList1 的控件中的选择检索数据。
<asp:DropDownList AutoPostBack="true" ID="DropDownList1" runat="server">
<asp:ListItem Value="Sports">Sports</asp:ListItem>
<asp:ListItem Value="Garden">Garden</asp:ListItem>
<asp:ListItem Value="Auto">Auto</asp:ListItem>
</asp:DropDownList>
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="Products"
AutoGenerateWhereClause="true"
ID="LinqDataSource1"
runat="server">
<WhereParameters>
<asp:ControlParameter
Name="Category"
ControlID="DropDownList1"
Type="String" />
</WhereParameters>
</asp:LinqDataSource>
<asp:GridView
DataSourceID="LinqDataSource1"
ID="GridView1"
runat="server">
</asp:GridView>
将 AutoGenerateWhereClause 属性设置为 true 时,LinqDataSource 控件会自动创建 Where 子句。当您具有多个参数时,此选项很有用,原因是您无需在 Where 属性中指定每个条件。您可以改为在 WhereParameters 属性集合中添加参数,这样 LinqDataSource 控件就会创建包含每个参数的 Where 子句。
当将 AutoGenerateWhereClause 属性设置为 true 时,参数的名称必须与相应属性的名称匹配。例如,若要针对 Category