阶段一:巩固基础之Linq

LINQ(Language Integrated Query)是C#中革命性的数据查询技术,它将查询能力直接嵌入到语言中,统一了对象、数据库、XML等多种数据源的查询方式。以下是LINQ的深度解析,涵盖核心概念、底层机制、性能优化和实战场景

1. LINQ的核心架构

1.1 LINQ三大组件
  1. 标准查询运算符WhereSelectGroupBy等50+方法

  2. LINQ提供程序

    • LINQ to Objects(内存集合)

    • LINQ to Entities(EF Core)

    • LINQ to XML

    • PLINQ(并行LINQ)

  3. 查询表达式语法(SQL-like语法糖):

var query = from p in products
            where p.Price > 100
            orderby p.Name
            select new { p.Name, p.Category };

1.2 延迟执行 vs 立即执行

// 延迟执行(直到遍历时才真正执行)
var deferredQuery = products.Where(p => p.Price > 100);

// 立即执行(触发执行的方法)
var materializedList = products.Where(p => p.Price > 100).ToList();
var count = products.Count(p => p.IsStock);

2. LINQ方法详解

2.1 过滤与投影

// Where + Select组合
var discountedProducts = products
    .Where(p => p.Price > 100)
    .Select(p => new {
        Name = p.Name.ToUpper(),
        DiscountedPrice = p.Price * 0.9
    });

2.2 连接与分组

// Join示例
var productOrders = products.Join(orders,
    p => p.Id,
    o => o.ProductId,
    (p, o) => new { p.Name, o.Quantity });

// GroupBy复杂分组
var salesByCategory = orders
    .GroupBy(o => o.Product.Category)
    .Select(g => new {
        Category = g.Key,
        Total = g.Sum(o => o.Quantity * o.UnitPrice)
    });

2.3 聚合与分区

// 聚合操作
decimal totalRevenue = orders.Sum(o => o.Total);
double avgPrice = products.Average(p => p.Price);

// 分页查询
var page3 = products
    .Where(p => p.IsActive)
    .OrderBy(p => p.Name)
    .Skip(20)
    .Take(10)
    .ToList();

3. 高级LINQ技巧

3.1 表达式树与动态查询
// 动态构建查询条件
public IQueryable<Product> BuildQuery(
    IQueryable<Product> source, 
    string nameFilter, 
    decimal? minPrice)
{
    var query = source;
    
    if (!string.IsNullOrEmpty(nameFilter))
        query = query.Where(p => p.Name.Contains(nameFilter));
    
    if (minPrice.HasValue)
        query = query.Where(p => p.Price >= minPrice.Value);
    
    return query;
}

// 使用
var filtered = BuildQuery(dbContext.Products, "phone", 500)
               .OrderByDescending(p => p.Price)
               .ToList();

3.2 LINQ与EF Core优化
// 避免SELECT N+1问题
var badQuery = db.Orders
                .Select(o => new {
                    Order = o,
                    // 每次循环触发数据库查询
                    CustomerName = o.Customer.Name 
                });

// 正确方式(Eager Loading)
var goodQuery = db.Orders
                 .Include(o => o.Customer)
                 .Select(o => new { 
                     Order = o, 
                     o.Customer.Name 
                 });

3.3 自定义LINQ扩展
// 创建分页扩展方法
public static class LinqExtensions
{
    public static IQueryable<T> Paginate<T>(
        this IQueryable<T> source, 
        int page, 
        int pageSize)
    {
        return source.Skip((page - 1) * pageSize).Take(pageSize);
    }
}

// 使用
var pageData = db.Products
                .Where(p => p.Category == "Electronics")
                .Paginate(2, 10)
                .ToList();

4. LINQ执行原理

4.1 查询翻译机制
  • LINQ to Objects:直接调用委托

  • LINQ to SQL/EF Core:将表达式树翻译为SQL

  • PLINQ:自动并行化处理

4.2 表达式树解析过程
  1. 编译器将Lambda转换为表达式树

  2. 提供程序(如EF Core)解析表达式树

  3. 生成目标语言(如SQL)的查询语句

  4. 执行查询并物化结果

// 查看EF Core生成的SQL
var query = db.Products.Where(p => p.Price > 100);
Console.WriteLine(query.ToQueryString());

5. 性能陷阱与优化

5.1 常见性能问题
  • 过度物化:过早调用ToList()

  • 重复查询:在循环中执行LINQ查询

  • 低效投影Select加载不需要的字段

5.2 优化策略
// 1. 使用AsNoTracking
var products = db.Products
                .AsNoTracking()
                .Where(p => p.IsActive)
                .ToList();

// 2. 批量操作替代循环
// 错误方式
foreach (var id in idsToDelete)
    db.Products.Remove(db.Products.Find(id));

// 正确方式
var toDelete = db.Products.Where(p => idsToDelete.Contains(p.Id));
db.Products.RemoveRange(toDelete);

// 3. 使用Any()代替Count() > 0
bool hasExpensive = products.Any(p => p.Price > 1000);

6. 实战应用场景

6.1 报表生成
// 复杂统计查询
var salesReport = orders
    .Where(o => o.OrderDate.Year == 2023)
    .GroupBy(o => new { o.Product.Category, Month = o.OrderDate.Month })
    .Select(g => new {
        g.Key.Category,
        g.Key.Month,
        TotalSales = g.Sum(o => o.Quantity * o.UnitPrice),
        AvgOrder = g.Average(o => o.Quantity)
    })
    .OrderByDescending(r => r.TotalSales)
    .ToList();
6.2 数据转换
// CSV转对象处理
var csvData = File.ReadAllLines("data.csv");
var records = csvData
    .Skip(1) // 跳过标题行
    .Select(line => line.Split(','))
    .Where(fields => fields.Length == 5)
    .Select(fields => new Product {
        Id = int.Parse(fields[0]),
        Name = fields[1],
        Category = fields[2],
        Price = decimal.Parse(fields[3]),
        Stock = int.Parse(fields[4])
    });
6.3 内存数据库查询
// 使用LINQ to XML处理配置
XDocument config = XDocument.Load("settings.xml");
var enabledFeatures = config.Descendants("feature")
                          .Where(x => (bool)x.Attribute("enabled"))
                          .Select(x => x.Attribute("name").Value)
                          .ToList();

7. LINQ与其他技术结合

7.1 动态LINQ
// 使用System.Linq.Dynamic.Core库
var filtered = db.Products
               .Where("Price > 100 && Category == \"Electronics\"")
               .OrderBy("Name desc")
               .ToList();
7.2 并行处理(PLINQ)
// 并行处理大文件
var largeData = File.ReadLines("bigdata.txt");
var results = largeData
    .AsParallel()
    .Where(line => line.Contains("error"))
    .WithDegreeOfParallelism(4)
    .ToList();
7.3 表达式树与API
// 构建动态API过滤器
public static Expression<Func<T, bool>> CreateFilter<T>(
    string propertyName, 
    object value)
{
    var param = Expression.Parameter(typeof(T));
    var body = Expression.Equal(
        Expression.Property(param, propertyName),
        Expression.Constant(value));
    return Expression.Lambda<Func<T, bool>>(body, param);
}

// 使用
var filter = CreateFilter<Product>("Category", "Books");
var books = db.Products.Where(filter).ToList();

8. 调试与测试

8.1 调试技巧
// 使用OzCode等插件可视化LINQ查询
var debugQuery = products
    .Where(p => p.Price > 100)
    .Select(p => new { p.Name, p.Category })
    .AsEnumerable(); // 设置断点在此处
8.2 单元测试
[Test]
public void Test_ProductFilter()
{
    // Arrange
    var products = new List<Product> { /* 测试数据 */ };
    
    // Act
    var result = products.Where(p => p.Price > 100).ToList();
    
    // Assert
    Assert.That(result, Has.All.Property("Price").GreaterThan(100));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值