LINQ to Entities 中的查询

查询是一种从数据源检索数据的表达式。查询通常用专用查询语言表示,如用于关系数据库的 SQL 和用于 XML 的 XQuery。因此,开发人员对于他们查询的每种类型的数据源或数据格式,都不得不学习一种新的查询语言。语言集成查询 (LINQ) 为跨各种数据源和格式处理数据提供了一种更简单的、一致的模型。在 LINQ 查询中,您始终可以使用编程对象。

LINQ 查询操作包含三个操作:获得一个或多个数据源、创建查询并执行查询。

可以通过 LINQ 查询实现 IEnumerable 泛型接口或 IQueryable 泛型接口的数据源。ObjectQuery 泛型类(可实现 IQueryable 泛型接口)的实例可充当 LINQ to Entities 查询的数据源。ObjectQuery 泛型类表示一个查询,此查询返回一个由类型化实体组成的实例或集合。开发人员从 ObjectContext 中构造一个实例,而它是作为 CLR 对象与 实体数据模型 (EDM) 进行交互的主要类。

在查询中,您可以确切指定要从数据源检索哪些信息。查询也可以指定返回信息之前信息的排序、分组和表现方式。在 LINQ 中,查询存储在变量中。如果查询返回一系列值,则查询变量本身必须为可查询的类型。此查询变量不执行任何操作,也不返回任何数据;它只存储查询信息。创建查询后必须执行该查询以检索任何数据。

在返回一系列值的查询中,查询变量本身从不保存查询结果,它只存储查询命令。查询的执行将推迟到在 foreachFor Each 循环中循环访问查询变量之后进行。这称为“延迟执行”**;也就是说,查询将会在构造之后的某个时间执行。这意味着您可以根据需要频繁地执行查询。例如,当您的数据库由其他应用程序不断更新时,此功能将会很有用。在您的应用程序中,您可以创建查询以检索最新信息并重复执行查询,每次返回更新的信息。

与返回一系列值的延迟查询相反,返回单一实例值的查询将立即执行。CountMaxAverageFirst 是单一实例查询的一些示例。这些查询将立即执行,因为需要查询结果才能计算单一实例结果。您也可以对查询使用 ToListToArray 方法以强制立即执行不生成单一实例值的查询。当想要缓存查询结果时,这些强制立即执行的技术可能会很有用。有关延迟和立即执行查询的更多信息,请参见 LINQ 介绍

查询

可以通过两种语法编写 LINQ to Entities 查询:查询表达式语法和基于方法的查询语法。查询表达式语法是 C# 3.0 和 Visual Basic 9.0 中的新增功能,它由一组用类似于 Transact-SQL 或 XQuery 的声明性语法所编写的子句组成。不过,.NET Framework 公共语言运行库 (CLR) 无法读取查询表达式语法本身。因此,在编译时,查询表达式将转换为 CLR 能理解的形式,即方法调用。这些方法称为“标准查询运算符”**。作为开发人员,您可以选择使用方法语法而不使用查询语法直接调用这些方法。有关更多信息,请参见查询语法与方法语法 (LINQ)。有关如何使用标准查询运算符的更多信息,请参见 LINQ 常规编程指南

查询表达式语法

查询表达式是一种声明性查询语法。通过这一语法,开发人员可以使用类似于 Transact-SQL 的高级语言格式编写查询。通过使用查询表达式语法,您可以用最少的代码对数据源执行复杂的筛选、排序和分组操作。有关更多信息,请参见 LINQ 查询表达式(C# 编程指南)基本查询操作 (Visual Basic)

以下示例使用 Select 以返回 Product 中的所有行并显示产品名称。

Using AWEntities As New AdventureWorksEntities
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productNames = _
       From p In products _
       Select p.Name

    Console.WriteLine("Product Names:")
    For Each productName In productNames
        Console.WriteLine(productName)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<string> productNames =
       from p in products
       select p.Name;

    Console.WriteLine("Product Names:");
    foreach (var productName in productNames)
    {
        Console.WriteLine(productName);
    }
}

基于方法的查询语法

另一种编写 LINQ to Entities 查询的方法是使用基于方法的查询。基于方法的查询语法是一系列针对 LINQ 运算符方法的直接方法调用,同时将 lambda 表达式作为参数传递。有关更多信息,请参见 Lambda 表达式(C# 编程指南)

此示例使用 Select 返回 Product 中的所有行并显示产品名称。

Using AWEntities As New AdventureWorksEntities


    Dim productNames = AWEntities.Product.Select(Function(p) p.Name)


    Console.WriteLine("Product Names:")
    For Each productName In productNames
        Console.WriteLine(productName)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<string> productNames = products.Select(p => p.Name);


    Console.WriteLine("Product Names:");
    foreach (var productName in productNames)
    {
        Console.WriteLine(productName);
    }
}

编写查询

如本主题前面所述,当查询旨在返回一系列值时,查询变量本身只存储查询命令。如果查询不包含可使查询立即执行的方法,则查询的实际执行将会推迟,直到在 foreachFor Each 循环中循环访问查询变量。延迟执行可使多个查询组合在一起或使查询得到扩展。扩展查询时,将修改查询以包括新操作,最终执行将反映这些更改。在下面的示例中,第一个查询返回所有产品。第二个查询通过使用 Where 扩展第一个查询,以返回大小为“L”的所有产品:

Using AWEntities As New AdventureWorksEntities()
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productsQuery = _
        From p In products _
        Select p

    Dim largeProducts = _
        productsQuery.Where(Function(p) p.Size = "L")

    Console.WriteLine("Products of size 'L':")
    For Each product In largeProducts
        Console.WriteLine(product.Name)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{

    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<Product> productsQuery =
        from p in products
        select p;

    IQueryable<Product> largeProducts = productsQuery.Where(p => p.Size == "L");

    Console.WriteLine("Products of size 'L':");
    foreach (var product in largeProducts)
    {
        Console.WriteLine(product.Name);
    }
}

在执行查询后,所有后续查询都将使用内存中的 LINQ 运算符。通过使用 foreachFor Each 语句或者调用某个 LINQ 转换运算符来循环访问查询变量会使查询立即执行。这些转换运算符包括:ToListToArrayToLookupToDictionary

在下面的示例中,第一个查询返回所有产品。第二个查询在执行后,将扩展第一个查询以返回红色的产品。

Using AWEntities As New AdventureWorksEntities()
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productsQuery = _
        From p In products _
        Select p

    Console.WriteLine("The list of products:")
    For Each Product As Product In productsQuery
        Console.WriteLine(Product.Name)
    Next

    Dim redProducts = productsQuery _
        .Where(Function(p) p.Color = "Red") _
        .Select(Function(p) p)

    Console.WriteLine("")
    Console.WriteLine("The list of red products:")
    For Each redProduct As Product In redProducts
        Console.WriteLine(redProduct.Name)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{

    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<Product> productsQuery =
        from p in products
        select p;

    Console.WriteLine("The list of products:");
    foreach (Product product in productsQuery)
    {
        Console.WriteLine(product.Name);
    }

    IQueryable<Product> redProducts = productsQuery
        .Where(p => p.Color == "Red")
        .Select(p => p);

    Console.WriteLine("");
    Console.WriteLine("The list of red products:");
    foreach (Product redProduct in redProducts)
    {
        Console.WriteLine(redProduct.Name);
    }

}

另请参见

其他资源

LINQ to Entities
C# 中的 LINQ 入门
Visual Basic 中的 LINQ 入门