前言

LINQ to SQL 是 .NET 中运用我这里就不废话了,直接进入主题,所以这期文章没有前言。

是的,你没看错,因为我懒,要写这个,我还得去百度一下文章来复制黏贴,不如你们直接去吧!

准备工作

为了方便大家理解,这里先假设有这么一张表:Product

列名

类型

备注

Id

类型我就不写了

主键

Name

类型我就不写了

商品名称

Category

类型我就不写了

商品类别

Price

类型我就不写了

商品价格

Stock

类型我就不写了

库存数量

Select/Distinct 查询

在查询表达式中,select 操作类似于 SQL 命令中的 select,用于选择和返回查询结果。但与 SQL 不同,查询表达式的 select 通常位于表达式的末尾,用于定义最终返回的变量(即查询的结果),并具有延迟执行的特点。

  • Select :选择特定列的数据或整个对象。

  • Distinct :获取唯一值,去除重复项。

Select/Distinct 操作提供了以下九种形式:

  • 简单形式:直接选择查询结果,不做任何处理。

简单用法:

var products = from product in db.Products
               select new { product.Name, product.Price };
  • 匿名类型形式:返回匿名类型的数据。

    var productNames = from p in context.Products 
                       select new { p.Name, p.Price };
  • 条件形式:根据条件选择特定的数据。

 var expensiveProducts = from p in context.Products 
                         where p.Price > 100 select p;
  • 指定类型形式:将查询结果转换为指定的类型。

var productIds = from p in context.Products 
                 select p.ID;
  • 筛选形式:根据条件筛选和返回部分数据。

var filteredProducts = from p in context.Products
                           where p.Category == "Electronics"
                           select new { p.Name, p.Stock };
  • 整形类型形式:对结果进行整形或转换。

 var roundedPrices = from p in context.Products
                     select new { p.Name, RoundedPrice = Math.Round(p.Price, 2) };
  • 嵌套类型形式:选择的结果为嵌套类型。

  var categorizedProducts = from p in context.Products
                            select new
                            {
                                p.Name,
                                CategoryInfo = new { p.Category, p.Price }
                            };
  • 本地方法调用形式:在查询中调用本地方法来处理数据。

    var upperCaseNames = from p in context.Products
                         select new { Name = p.Name.ToUpper(), p.Price };
  • Distinct 形式:去除重复数据并返回唯一值的集合。

    var uniqueCategories = (from p in context.Products
                            select p.Category).Distinct();

Count 计数

作用:统计满足条件的数据量。

示例:统计库存大于 100 的商品数量。

var productCount = (from product in db.Products
                    where product.Stock > 100
                    select product).Count();

Sum 求和

作用:计算特定列的总和。

示例:计算所有商品的总库存量。

var totalStock = db.Products.Sum(product => product.Stock);

Min 最小值

目的:找到特定列的最小值。

示例:获取最低价格的商品价格。

var minPrice = db.Products.Min(product => product.Price);

Max 最大值

目的:找到特定列的最大值。

示例:获取最高价格的商品价格。

var maxPrice = db.Products.Max(product => product.Price);

Avg 平均值

目的:计算特定列的平均值。

示例:计算所有商品的平均价格。

var avgPrice = db.Products.Average(product => product.Price);

Where 条件过滤

目的:根据特定条件筛选数据。

示例:查询库存大于 50 且价格低于 100 的商品。

var products = db.Products.Where(
                  product => product.Stock > 50 && product.Price < 100);

OrderBy、OrderByDescending、ThenBy、ThenByDescending 排序

目的:对查询结果进行升序( OrderBy )或降序排序( OrderByDescending )。

示例:按价格升序排序,按库存降序排序。

var sortedProducts = db.Products
                    .OrderBy(product => product.Price)
                    .ThenByDescending(product => product.Stock);

Take、Skip 分页

目的:分页处理数据,或提取前几条记录。

示例:获取价格最低的前 5 个商品。

var top5Products = db.Products
                   .OrderBy(product => product.Price).Take(5);

注意:Take() 获取指定数量的记录,Skip() 用于跳过指定数量的记录,是数量、数量、数量,重要的事情说三遍,不是页码和每页最大条数,需要自行计算,适合分页场景。

如果你需要使用页码与每页最大条数,请使用以下这种方式写一个扩展

/// <summary>
/// 分页功能
/// </summary>
/// <typeparam name="T">IQueryable 的元素类型</typeparam>
/// <param name="query">IQueryable 查询</param>
/// <param name="pageIndex">页码(从 1 开始)</param>
/// <param name="pageSize">每页记录数</param>
/// <returns>分页后的 IQueryable</returns>
public static IQueryable<T> PageBy<T>(this IQueryable<T> query, int pageIndex, int pageSize)
{
    if (pageIndex < 1) throw new ArgumentOutOfRangeException(nameof(pageIndex), "页码必须大于等于 1");
    if (pageSize < 1) throw new ArgumentOutOfRangeException(nameof(pageSize), "每页记录数必须大于等于 1");

    // Skip 忽略前面 (pageIndex - 1) * pageSize 条记录,Take 获取 pageSize 条记录
    return query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
}


// 使用方式
int pageIndex = 2; // 第 2 页
int pageSize = 10; // 每页 10 条记录

var pagedProducts = context.Products.PageBy(pageIndex, pageSize).ToList();

First 、FirstOrDefault

目的:返回符合条件的第一条记录,找不到记录时,FirstOrDefault 返回 null。

示例:获取库存大于 50 的第一件商品。

var firstProduct = db.Products.FirstOrDefault(product => product.Stock > 50);

注意First()FirstOrDefault() 都能返回第一条匹配记录,First() 找不到记录时会抛出异常,而 FirstOrDefault() 则返回 null


Single、SingleOrDefault

目的:返回唯一的一条记录,找不到或找到多条时抛出异常。SingleOrDefault 在找不到记录时返回 null。

示例:获取 ID 为 1 的商品。

var singleProduct = db.Products.SingleOrDefault(product => product.ID == 1);

Any 匹配

目的:检查是否有符合条件的记录存在。

示例:检查是否存在价格超过 500 的商品。

var hasExpensiveProducts = db.Products.Any(product => product.Price > 500);

注意:SingleSingleOrDefault 用于确保只有一条记录匹配条件,否则抛出异常或返回 null ,所以一般用来匹配主键或者列是唯一值的数据,亦或者,你能确保数据是唯一的。


All 匹配

目的:检查是否所有记录都满足特定条件。

示例:检查是否所有商品库存都大于 10。

var allProductsInStock = db.Products.All(product => product.Stock > 10);

Contains 包含

目的:判断集合中是否包含指定的值。

示例:判断类别列表中是否包含“Electronics”类别。

var categories = db.Products.Select(p => p.Category).Distinct();
var hasElectronics = categories.Contains("Electronics");

GroupBy 分组

目的:按某个字段分组。

示例:按类别分组,统计每个类别中的商品数量。

var productGroups = db.Products.GroupBy(product => product.Category)
                    .Select(group => new { Category = group.Key, Count = group.Count() });

Join 关联

目的:合并两个数据集,类似于 SQL 的 JOIN 操作。

示例:将 Product 和 Category 表连接,显示每个商品的类别名称(假设我们有 Category 表)。

var productCategories = from product in db.Products
                        join category in db.Categories
                        on product.CategoryID equals category.ID
                        select new { product.Name, CategoryName = category.Name };