znlgis 博客

GIS开发与技术分享

第六章:高级查询与Lambda表达式

目录

6.1 Lambda表达式基础

6.1.1 Lambda表达式语法

Lambda表达式是SqlSugar查询的核心,提供了类型安全和智能提示:

public class LambdaBasics
{
    private readonly SqlSugarClient _db;

    public LambdaBasics(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础Lambda表达式
    public List<User> BasicLambda()
    {
        // 单个参数
        return _db.Queryable<User>()
            .Where(u => u.Age > 18)
            .ToList();
    }

    // 多个条件
    public List<User> MultipleConditions()
    {
        return _db.Queryable<User>()
            .Where(u => u.Age > 18 && u.Age < 60)
            .Where(u => u.Status == 1)
            .ToList();
    }

    // 字符串操作
    public List<User> StringOperations()
    {
        return _db.Queryable<User>()
            .Where(u => u.Name.Contains("张"))
            .Where(u => u.Email.StartsWith("test"))
            .Where(u => u.Email.EndsWith("@test.com"))
            .ToList();
    }

    // 数值比较
    public List<User> NumericComparisons()
    {
        return _db.Queryable<User>()
            .Where(u => u.Age >= 18)
            .Where(u => u.Age <= 60)
            .Where(u => u.Status != 0)
            .ToList();
    }

    // 日期比较
    public List<User> DateComparisons()
    {
        var today = DateTime.Today;
        var lastMonth = today.AddMonths(-1);

        return _db.Queryable<User>()
            .Where(u => u.CreateTime >= lastMonth)
            .Where(u => u.CreateTime < today)
            .ToList();
    }

    // 集合操作
    public List<User> CollectionOperations()
    {
        var ids = new List<int> { 1, 2, 3, 4, 5 };
        var statuses = new[] { 1, 2 };

        return _db.Queryable<User>()
            .Where(u => ids.Contains(u.Id))
            .Where(u => statuses.Contains(u.Status))
            .ToList();
    }
}

6.1.2 表达式树

理解和使用表达式树:

public class ExpressionTreeExample
{
    private readonly SqlSugarClient _db;

    public ExpressionTreeExample(SqlSugarClient db)
    {
        _db = db;
    }

    // 动态构建表达式
    public List<User> DynamicExpression(string fieldName, object value)
    {
        var parameter = Expression.Parameter(typeof(User), "u");
        var property = Expression.Property(parameter, fieldName);
        var constant = Expression.Constant(value);
        var equal = Expression.Equal(property, constant);
        var lambda = Expression.Lambda<Func<User, bool>>(equal, parameter);

        return _db.Queryable<User>()
            .Where(lambda)
            .ToList();
    }

    // 组合表达式
    public List<User> CombineExpressions()
    {
        Expression<Func<User, bool>> expr1 = u => u.Age > 18;
        Expression<Func<User, bool>> expr2 = u => u.Status == 1;

        return _db.Queryable<User>()
            .Where(expr1)
            .Where(expr2)
            .ToList();
    }

    // 可重用的表达式
    private Expression<Func<User, bool>> ActiveUserExpression()
    {
        return u => u.Status == 1 && u.IsDeleted == false;
    }

    public List<User> GetActiveUsers()
    {
        return _db.Queryable<User>()
            .Where(ActiveUserExpression())
            .ToList();
    }
}

6.2 复杂条件查询

6.2.1 多条件组合

组合多个查询条件:

public class ComplexConditions
{
    private readonly SqlSugarClient _db;

    public ComplexConditions(SqlSugarClient db)
    {
        _db = db;
    }

    // AND条件组合
    public List<User> AndConditions()
    {
        return _db.Queryable<User>()
            .Where(u => u.Age > 18 && u.Age < 60)
            .Where(u => u.Status == 1 && u.IsDeleted == false)
            .Where(u => u.Name.Contains("张") && u.Email.Contains("@test.com"))
            .ToList();
    }

    // 复杂条件嵌套
    public List<User> NestedConditions()
    {
        return _db.Queryable<User>()
            .Where(u => (u.Age > 18 && u.Age < 30) || (u.Age > 40 && u.Age < 60))
            .Where(u => u.Status == 1)
            .ToList();
    }

    // 多字段OR查询
    public List<User> MultiFieldSearch(string keyword)
    {
        return _db.Queryable<User>()
            .Where(u => u.Name.Contains(keyword) || 
                       u.Email.Contains(keyword) || 
                       u.Phone.Contains(keyword))
            .ToList();
    }
}

6.2.2 OR条件

使用OR条件进行查询:

public class OrConditions
{
    private readonly SqlSugarClient _db;

    public OrConditions(SqlSugarClient db)
    {
        _db = db;
    }

    // 简单OR条件
    public List<User> SimpleOr()
    {
        return _db.Queryable<User>()
            .Where(u => u.Age < 18 || u.Age > 60)
            .ToList();
    }

    // 复杂OR条件
    public List<User> ComplexOr()
    {
        return _db.Queryable<User>()
            .Where(u => (u.Status == 1 && u.Age > 18) || 
                       (u.Status == 2 && u.Age > 16))
            .ToList();
    }

    // 使用WhereOr
    public List<User> UseWhereOr(List<int> ids, string name)
    {
        return _db.Queryable<User>()
            .Where(u => ids.Contains(u.Id))
            .Or()
            .Where(u => u.Name == name)
            .ToList();
    }
}

6.2.3 动态条件构建

根据运行时条件动态构建查询:

public class DynamicConditionBuilder
{
    private readonly SqlSugarClient _db;

    public DynamicConditionBuilder(SqlSugarClient db)
    {
        _db = db;
    }

    // 使用WhereIF动态添加条件
    public List<User> SearchUsers(UserSearchDto dto)
    {
        return _db.Queryable<User>()
            .WhereIF(!string.IsNullOrEmpty(dto.Name), u => u.Name.Contains(dto.Name))
            .WhereIF(dto.MinAge.HasValue, u => u.Age >= dto.MinAge.Value)
            .WhereIF(dto.MaxAge.HasValue, u => u.Age <= dto.MaxAge.Value)
            .WhereIF(dto.Status.HasValue, u => u.Status == dto.Status.Value)
            .WhereIF(dto.StartDate.HasValue, u => u.CreateTime >= dto.StartDate.Value)
            .WhereIF(dto.EndDate.HasValue, u => u.CreateTime < dto.EndDate.Value)
            .ToList();
    }

    // 使用Expressionable动态构建
    public List<User> AdvancedDynamicQuery(UserSearchDto dto)
    {
        var exp = Expressionable.Create<User>();

        if (!string.IsNullOrEmpty(dto.Name))
        {
            exp.And(u => u.Name.Contains(dto.Name));
        }

        if (dto.MinAge.HasValue && dto.MaxAge.HasValue)
        {
            exp.And(u => u.Age >= dto.MinAge.Value && u.Age <= dto.MaxAge.Value);
        }
        else if (dto.MinAge.HasValue)
        {
            exp.And(u => u.Age >= dto.MinAge.Value);
        }
        else if (dto.MaxAge.HasValue)
        {
            exp.And(u => u.Age <= dto.MaxAge.Value);
        }

        if (dto.Keywords != null && dto.Keywords.Any())
        {
            var orExp = Expressionable.Create<User>();
            foreach (var keyword in dto.Keywords)
            {
                orExp.Or(u => u.Name.Contains(keyword));
            }
            exp.And(orExp.ToExpression());
        }

        return _db.Queryable<User>()
            .Where(exp.ToExpression())
            .ToList();
    }
}

public class UserSearchDto
{
    public string Name { get; set; }
    public int? MinAge { get; set; }
    public int? MaxAge { get; set; }
    public int? Status { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public List<string> Keywords { get; set; }
}

6.3 动态查询

6.3.1 表达式拼接

动态拼接查询表达式:

public class ExpressionCombination
{
    private readonly SqlSugarClient _db;

    public ExpressionCombination(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础表达式拼接
    public List<User> CombineExpressions(bool includeAge, bool includeStatus)
    {
        var query = _db.Queryable<User>();

        if (includeAge)
        {
            query = query.Where(u => u.Age > 18);
        }

        if (includeStatus)
        {
            query = query.Where(u => u.Status == 1);
        }

        return query.ToList();
    }

    // 使用PredicateBuilder
    public List<User> UsePredicateBuilder(List<string> names, List<int> ages)
    {
        var predicate = PredicateBuilder.False<User>();

        foreach (var name in names)
        {
            var temp = name;
            predicate = predicate.Or(u => u.Name == temp);
        }

        foreach (var age in ages)
        {
            var temp = age;
            predicate = predicate.Or(u => u.Age == temp);
        }

        return _db.Queryable<User>()
            .Where(predicate)
            .ToList();
    }
}

// PredicateBuilder辅助类
public static class PredicateBuilder
{
    public static Expression<Func<T, bool>> True<T>() => f => true;
    public static Expression<Func<T, bool>> False<T>() => f => false;

    public static Expression<Func<T, bool>> Or<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof(T));
        var combined = new ParameterReplaceVisitor(parameter)
            .Visit(Expression.OrElse(expr1.Body, expr2.Body));
        return Expression.Lambda<Func<T, bool>>(combined, parameter);
    }

    public static Expression<Func<T, bool>> And<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof(T));
        var combined = new ParameterReplaceVisitor(parameter)
            .Visit(Expression.AndAlso(expr1.Body, expr2.Body));
        return Expression.Lambda<Func<T, bool>>(combined, parameter);
    }
}

class ParameterReplaceVisitor : ExpressionVisitor
{
    private readonly ParameterExpression _parameter;

    public ParameterReplaceVisitor(ParameterExpression parameter)
    {
        _parameter = parameter;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return _parameter;
    }
}

6.3.2 条件构建器

使用条件构建器简化动态查询:

public class ConditionBuilder
{
    private readonly SqlSugarClient _db;

    public ConditionBuilder(SqlSugarClient db)
    {
        _db = db;
    }

    // 使用Conditionals进行条件构建
    public List<User> BuildWithConditionals(UserFilter filter)
    {
        var conditionals = new List<IConditionalModel>();

        if (!string.IsNullOrEmpty(filter.Name))
        {
            conditionals.Add(new ConditionalModel
            {
                FieldName = "Name",
                ConditionalType = ConditionalType.Like,
                FieldValue = filter.Name
            });
        }

        if (filter.MinAge.HasValue)
        {
            conditionals.Add(new ConditionalModel
            {
                FieldName = "Age",
                ConditionalType = ConditionalType.GreaterThanOrEqual,
                FieldValue = filter.MinAge.Value.ToString()
            });
        }

        if (filter.MaxAge.HasValue)
        {
            conditionals.Add(new ConditionalModel
            {
                FieldName = "Age",
                ConditionalType = ConditionalType.LessThanOrEqual,
                FieldValue = filter.MaxAge.Value.ToString()
            });
        }

        return _db.Queryable<User>()
            .Where(conditionals)
            .ToList();
    }
}

public class UserFilter
{
    public string Name { get; set; }
    public int? MinAge { get; set; }
    public int? MaxAge { get; set; }
}

6.4 Select投影

6.4.1 匿名类型投影

将查询结果投影到匿名类型:

public class AnonymousProjection
{
    private readonly SqlSugarClient _db;

    public AnonymousProjection(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础投影
    public List<object> BasicProjection()
    {
        return _db.Queryable<User>()
            .Select(u => new { u.Id, u.Name, u.Email })
            .ToList<object>();
    }

    // 计算字段投影
    public List<object> ComputedProjection()
    {
        return _db.Queryable<User>()
            .Select(u => new
            {
                u.Id,
                u.Name,
                AgeGroup = u.Age < 18 ? "未成年" : u.Age < 60 ? "成年" : "老年",
                CreateYear = u.CreateTime.Year
            })
            .ToList<object>();
    }

    // 字符串拼接投影
    public List<object> ConcatProjection()
    {
        return _db.Queryable<User>()
            .Select(u => new
            {
                u.Id,
                FullInfo = u.Name + " (" + u.Email + ")",
                DisplayName = u.Name + " - " + u.Age
            })
            .ToList<object>();
    }
}

6.4.2 DTO投影

投影到数据传输对象(DTO):

public class DtoProjection
{
    private readonly SqlSugarClient _db;

    public DtoProjection(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础DTO投影
    public List<UserDto> ProjectToDto()
    {
        return _db.Queryable<User>()
            .Select(u => new UserDto
            {
                Id = u.Id,
                Name = u.Name,
                Email = u.Email,
                Age = u.Age
            })
            .ToList();
    }

    // 包含计算字段的DTO
    public List<UserDetailDto> ProjectToDetailDto()
    {
        return _db.Queryable<User>()
            .Select(u => new UserDetailDto
            {
                Id = u.Id,
                Name = u.Name,
                Email = u.Email,
                Age = u.Age,
                IsAdult = u.Age >= 18,
                AccountAge = SqlFunc.DateDiff(DateType.Day, u.CreateTime, DateTime.Now)
            })
            .ToList();
    }

    // 使用Mapper投影
    public List<UserDto> UseMapper()
    {
        return _db.Queryable<User>()
            .Select(u => new UserDto(), true)  // true表示自动映射
            .ToList();
    }
}

public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
}

public class UserDetailDto : UserDto
{
    public bool IsAdult { get; set; }
    public int AccountAge { get; set; }
}

6.4.3 动态字段选择

根据需要动态选择字段:

public class DynamicFieldSelection
{
    private readonly SqlSugarClient _db;

    public DynamicFieldSelection(SqlSugarClient db)
    {
        _db = db;
    }

    // 动态选择字段
    public List<Dictionary<string, object>> SelectDynamicFields(List<string> fields)
    {
        var query = _db.Queryable<User>();

        if (fields != null && fields.Any())
        {
            var selectFields = string.Join(",", fields);
            return query.Select(selectFields).ToList();
        }

        return query.Select("*").ToList();
    }

    // 根据权限选择字段
    public List<object> SelectByPermission(bool includeEmail, bool includePhone)
    {
        return _db.Queryable<User>()
            .Select(u => new
            {
                u.Id,
                u.Name,
                Email = includeEmail ? u.Email : null,
                Phone = includePhone ? u.Phone : null
            })
            .ToList<object>();
    }
}

6.5 Join操作

6.5.1 内连接

使用内连接查询多表数据:

public class InnerJoinExample
{
    private readonly SqlSugarClient _db;

    public InnerJoinExample(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础内连接
    public List<object> BasicInnerJoin()
    {
        return _db.Queryable<User, Department>((u, d) => u.DepartmentId == d.Id)
            .Select((u, d) => new
            {
                UserId = u.Id,
                UserName = u.Name,
                DepartmentName = d.Name
            })
            .ToList<object>();
    }

    // 使用InnerJoin方法
    public List<UserDeptDto> UseInnerJoinMethod()
    {
        return _db.Queryable<User>()
            .InnerJoin<Department>((u, d) => u.DepartmentId == d.Id)
            .Select((u, d) => new UserDeptDto
            {
                UserId = u.Id,
                UserName = u.Name,
                UserEmail = u.Email,
                DepartmentName = d.Name
            })
            .ToList();
    }

    // 带条件的内连接
    public List<UserDeptDto> InnerJoinWithCondition(int minAge)
    {
        return _db.Queryable<User>()
            .InnerJoin<Department>((u, d) => u.DepartmentId == d.Id)
            .Where((u, d) => u.Age >= minAge)
            .Where((u, d) => d.Status == 1)
            .Select((u, d) => new UserDeptDto
            {
                UserId = u.Id,
                UserName = u.Name,
                DepartmentName = d.Name
            })
            .ToList();
    }
}

6.5.2 左连接

使用左连接保留主表所有记录:

public class LeftJoinExample
{
    private readonly SqlSugarClient _db;

    public LeftJoinExample(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础左连接
    public List<UserDeptDto> BasicLeftJoin()
    {
        return _db.Queryable<User>()
            .LeftJoin<Department>((u, d) => u.DepartmentId == d.Id)
            .Select((u, d) => new UserDeptDto
            {
                UserId = u.Id,
                UserName = u.Name,
                DepartmentName = d.Name ?? "未分配"
            })
            .ToList();
    }

    // 多个左连接
    public List<object> MultipleLeftJoins()
    {
        return _db.Queryable<User>()
            .LeftJoin<Department>((u, d) => u.DepartmentId == d.Id)
            .LeftJoin<Role>((u, d, r) => u.RoleId == r.Id)
            .Select((u, d, r) => new
            {
                UserId = u.Id,
                UserName = u.Name,
                DepartmentName = d.Name,
                RoleName = r.Name
            })
            .ToList<object>();
    }
}

6.5.3 右连接

使用右连接保留从表所有记录:

public class RightJoinExample
{
    private readonly SqlSugarClient _db;

    public RightJoinExample(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础右连接
    public List<object> BasicRightJoin()
    {
        return _db.Queryable<User>()
            .RightJoin<Department>((u, d) => u.DepartmentId == d.Id)
            .Select((u, d) => new
            {
                DepartmentName = d.Name,
                UserCount = SqlFunc.AggregateCount(u.Id)
            })
            .GroupBy((u, d) => d.Name)
            .ToList<object>();
    }
}

6.5.4 多表连接

连接多个表进行复杂查询:

public class MultiTableJoin
{
    private readonly SqlSugarClient _db;

    public MultiTableJoin(SqlSugarClient db)
    {
        _db = db;
    }

    // 三表连接
    public List<OrderDetailDto> ThreeTableJoin()
    {
        return _db.Queryable<Order, User, Product>((o, u, p) => new JoinQueryInfos(
                JoinType.Left, o.UserId == u.Id,
                JoinType.Left, o.ProductId == p.Id
            ))
            .Select((o, u, p) => new OrderDetailDto
            {
                OrderNo = o.OrderNo,
                OrderTime = o.CreateTime,
                UserName = u.Name,
                ProductName = p.Name,
                Quantity = o.Quantity,
                TotalPrice = o.Quantity * p.Price
            })
            .ToList();
    }

    // 四表连接
    public List<object> FourTableJoin()
    {
        return _db.Queryable<Order, User, Product, Category>(
                (o, u, p, c) => new JoinQueryInfos(
                    JoinType.Left, o.UserId == u.Id,
                    JoinType.Left, o.ProductId == p.Id,
                    JoinType.Left, p.CategoryId == c.Id
                ))
            .Select((o, u, p, c) => new
            {
                OrderNo = o.OrderNo,
                UserName = u.Name,
                ProductName = p.Name,
                CategoryName = c.Name,
                TotalAmount = o.Quantity * p.Price
            })
            .ToList<object>();
    }
}

public class OrderDetailDto
{
    public string OrderNo { get; set; }
    public DateTime OrderTime { get; set; }
    public string UserName { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal TotalPrice { get; set; }
}

6.6 分组与聚合

6.6.1 GroupBy分组

对数据进行分组统计:

public class GroupByExample
{
    private readonly SqlSugarClient _db;

    public GroupByExample(SqlSugarClient db)
    {
        _db = db;
    }

    // 单字段分组
    public List<object> SingleFieldGroup()
    {
        return _db.Queryable<User>()
            .GroupBy(u => u.Age)
            .Select(u => new
            {
                Age = u.Age,
                Count = SqlFunc.AggregateCount(u.Id)
            })
            .ToList<object>();
    }

    // 多字段分组
    public List<object> MultipleFieldsGroup()
    {
        return _db.Queryable<User>()
            .GroupBy(u => new { u.Age, u.Status })
            .Select(u => new
            {
                u.Age,
                u.Status,
                Count = SqlFunc.AggregateCount(u.Id)
            })
            .ToList<object>();
    }

    // 分组后排序
    public List<object> GroupWithOrder()
    {
        return _db.Queryable<User>()
            .GroupBy(u => u.Age)
            .Select(u => new
            {
                Age = u.Age,
                Count = SqlFunc.AggregateCount(u.Id)
            })
            .OrderBy("Count DESC")
            .ToList<object>();
    }
}

6.6.2 Having条件

对分组结果进行过滤:

public class HavingExample
{
    private readonly SqlSugarClient _db;

    public HavingExample(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础Having
    public List<object> BasicHaving()
    {
        return _db.Queryable<User>()
            .GroupBy(u => u.Age)
            .Having(u => SqlFunc.AggregateCount(u.Id) > 5)
            .Select(u => new
            {
                Age = u.Age,
                Count = SqlFunc.AggregateCount(u.Id)
            })
            .ToList<object>();
    }

    // 复杂Having条件
    public List<object> ComplexHaving()
    {
        return _db.Queryable<Order>()
            .GroupBy(o => o.UserId)
            .Having(o => SqlFunc.AggregateSum(o.Amount) > 10000)
            .Having(o => SqlFunc.AggregateCount(o.Id) >= 10)
            .Select(o => new
            {
                UserId = o.UserId,
                TotalAmount = SqlFunc.AggregateSum(o.Amount),
                OrderCount = SqlFunc.AggregateCount(o.Id)
            })
            .ToList<object>();
    }
}

6.6.3 聚合函数

使用各种聚合函数:

public class AggregateFunctions
{
    private readonly SqlSugarClient _db;

    public AggregateFunctions(SqlSugarClient db)
    {
        _db = db;
    }

    // 常用聚合函数
    public object CommonAggregates()
    {
        return _db.Queryable<User>()
            .Select(u => new
            {
                TotalCount = SqlFunc.AggregateCount(u.Id),
                AvgAge = SqlFunc.AggregateAvg(u.Age),
                MinAge = SqlFunc.AggregateMin(u.Age),
                MaxAge = SqlFunc.AggregateMax(u.Age),
                SumAge = SqlFunc.AggregateSum(u.Age)
            })
            .First();
    }

    // 分组聚合
    public List<object> GroupAggregates()
    {
        return _db.Queryable<Order>()
            .GroupBy(o => o.UserId)
            .Select(o => new
            {
                UserId = o.UserId,
                TotalOrders = SqlFunc.AggregateCount(o.Id),
                TotalAmount = SqlFunc.AggregateSum(o.Amount),
                AvgAmount = SqlFunc.AggregateAvg(o.Amount),
                MaxAmount = SqlFunc.AggregateMax(o.Amount),
                MinAmount = SqlFunc.AggregateMin(o.Amount)
            })
            .ToList<object>();
    }

    // 多维度聚合
    public List<object> MultiDimensionAggregates()
    {
        return _db.Queryable<Order>()
            .GroupBy(o => new { Year = o.CreateTime.Year, Month = o.CreateTime.Month })
            .Select(o => new
            {
                Year = o.CreateTime.Year,
                Month = o.CreateTime.Month,
                OrderCount = SqlFunc.AggregateCount(o.Id),
                TotalAmount = SqlFunc.AggregateSum(o.Amount)
            })
            .OrderBy("Year DESC, Month DESC")
            .ToList<object>();
    }
}

6.7 去重与合并

6.7.1 Distinct去重

使用Distinct去除重复数据:

public class DistinctExample
{
    private readonly SqlSugarClient _db;

    public DistinctExample(SqlSugarClient db)
    {
        _db = db;
    }

    // 单字段去重
    public List<int> DistinctAges()
    {
        return _db.Queryable<User>()
            .Select(u => u.Age)
            .Distinct()
            .ToList();
    }

    // 多字段去重
    public List<object> DistinctMultipleFields()
    {
        return _db.Queryable<User>()
            .Select(u => new { u.Age, u.Status })
            .Distinct()
            .ToList<object>();
    }

    // 去重后统计
    public int CountDistinct()
    {
        return _db.Queryable<User>()
            .Select(u => u.Email)
            .Distinct()
            .Count();
    }
}

6.7.2 Union合并

合并多个查询结果:

public class UnionExample
{
    private readonly SqlSugarClient _db;

    public UnionExample(SqlSugarClient db)
    {
        _db = db;
    }

    // Union合并(去重)
    public List<User> UnionQuery()
    {
        var query1 = _db.Queryable<User>().Where(u => u.Age < 20);
        var query2 = _db.Queryable<User>().Where(u => u.Age > 60);

        return _db.Union(query1, query2).ToList();
    }

    // UnionAll合并(不去重)
    public List<User> UnionAllQuery()
    {
        var query1 = _db.Queryable<User>().Where(u => u.Status == 1);
        var query2 = _db.Queryable<User>().Where(u => u.Status == 2);

        return _db.UnionAll(query1, query2).ToList();
    }

    // 多个查询合并
    public List<object> MultipleUnion()
    {
        var query1 = _db.Queryable<User>()
            .Where(u => u.Age < 20)
            .Select(u => new { u.Id, u.Name, Category = "未成年" });

        var query2 = _db.Queryable<User>()
            .Where(u => u.Age >= 20 && u.Age < 60)
            .Select(u => new { u.Id, u.Name, Category = "成年" });

        var query3 = _db.Queryable<User>()
            .Where(u => u.Age >= 60)
            .Select(u => new { u.Id, u.Name, Category = "老年" });

        return _db.UnionAll(query1, query2, query3).ToList<object>();
    }
}

6.8 子查询

6.8.1 标量子查询

返回单个值的子查询:

public class ScalarSubquery
{
    private readonly SqlSugarClient _db;

    public ScalarSubquery(SqlSugarClient db)
    {
        _db = db;
    }

    // 在Select中使用子查询
    public List<object> SubqueryInSelect()
    {
        return _db.Queryable<User>()
            .Select(u => new
            {
                u.Id,
                u.Name,
                OrderCount = SqlFunc.Subqueryable<Order>()
                    .Where(o => o.UserId == u.Id)
                    .Count()
            })
            .ToList<object>();
    }

    // 在Where中使用子查询
    public List<User> SubqueryInWhere()
    {
        return _db.Queryable<User>()
            .Where(u => u.Age > SqlFunc.Subqueryable<User>()
                .Select(s => SqlFunc.AggregateAvg(s.Age)))
            .ToList();
    }
}

6.8.2 IN子查询

使用IN进行子查询:

public class InSubquery
{
    private readonly SqlSugarClient _db;

    public InSubquery(SqlSugarClient db)
    {
        _db = db;
    }

    // 基础IN子查询
    public List<User> BasicInSubquery()
    {
        var orderUserIds = _db.Queryable<Order>()
            .Where(o => o.Amount > 1000)
            .Select(o => o.UserId)
            .ToList();

        return _db.Queryable<User>()
            .Where(u => orderUserIds.Contains(u.Id))
            .ToList();
    }

    // 使用SqlFunc.Subqueryable
    public List<User> UseSubqueryable()
    {
        return _db.Queryable<User>()
            .Where(u => SqlFunc.Subqueryable<Order>()
                .Where(o => o.UserId == u.Id && o.Amount > 1000)
                .Any())
            .ToList();
    }
}

6.8.3 EXISTS子查询

使用EXISTS判断存在性:

public class ExistsSubquery
{
    private readonly SqlSugarClient _db;

    public ExistsSubquery(SqlSugarClient db)
    {
        _db = db;
    }

    // EXISTS子查询
    public List<User> ExistsQuery()
    {
        return _db.Queryable<User>()
            .Where(u => SqlFunc.Subqueryable<Order>()
                .Where(o => o.UserId == u.Id && o.Amount > 1000)
                .Any())
            .ToList();
    }

    // NOT EXISTS子查询
    public List<User> NotExistsQuery()
    {
        return _db.Queryable<User>()
            .Where(u => !SqlFunc.Subqueryable<Order>()
                .Where(o => o.UserId == u.Id)
                .Any())
            .ToList();
    }
}

6.9 最佳实践

public class AdvancedQueryBestPractices
{
    private readonly SqlSugarClient _db;

    public AdvancedQueryBestPractices(SqlSugarClient db)
    {
        _db = db;
    }

    // 1. 使用AsQueryable提高可维护性
    public IQueryable<User> GetBaseQuery()
    {
        return _db.Queryable<User>()
            .Where(u => u.IsDeleted == false)
            .Where(u => u.Status == 1);
    }

    public List<User> GetActiveUsers()
    {
        return GetBaseQuery()
            .Where(u => u.Age >= 18)
            .ToList();
    }

    // 2. 避免N+1查询问题
    public List<UserWithOrdersDto> AvoidNPlusOne()
    {
        // 错误方式 - N+1查询
        // var users = _db.Queryable<User>().ToList();
        // foreach(var user in users)
        // {
        //     user.Orders = _db.Queryable<Order>().Where(o => o.UserId == user.Id).ToList();
        // }

        // 正确方式 - 使用Join
        return _db.Queryable<User>()
            .Mapper(u => u.Orders, u => u.Orders.First().UserId)
            .Select(u => new UserWithOrdersDto
            {
                User = u,
                Orders = u.Orders
            })
            .ToList();
    }

    // 3. 使用投影减少数据传输
    public List<UserSummaryDto> UseProjection()
    {
        // 只查询需要的字段
        return _db.Queryable<User>()
            .Select(u => new UserSummaryDto
            {
                Id = u.Id,
                Name = u.Name
            })
            .ToList();
    }

    // 4. 合理使用索引
    public List<User> UseIndexEfficiently()
    {
        // 确保查询条件使用了索引字段
        return _db.Queryable<User>()
            .Where(u => u.Email == "test@test.com")  // Email有索引
            .ToList();
    }

    // 5. 批量操作优化
    public List<User> BatchQuery(List<int> ids)
    {
        // 使用IN而不是多次单条查询
        return _db.Queryable<User>()
            .Where(u => ids.Contains(u.Id))
            .ToList();
    }
}

public class UserSummaryDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class UserWithOrdersDto
{
    public User User { get; set; }
    public List<Order> Orders { get; set; }
}

本章小结

本章深入介绍了SqlSugar的高级查询与Lambda表达式:

  1. Lambda表达式: 掌握了Lambda表达式的基础语法和表达式树
  2. 复杂条件查询: 学习了多条件组合、OR条件和动态条件构建
  3. 动态查询: 了解了表达式拼接和条件构建器的使用
  4. Select投影: 掌握了匿名类型投影、DTO投影和动态字段选择
  5. Join操作: 学习了内连接、左连接、右连接和多表连接
  6. 分组与聚合: 掌握了GroupBy、Having和各种聚合函数
  7. 去重与合并: 了解了Distinct去重和Union合并操作
  8. 子查询: 学习了标量子查询、IN子查询和EXISTS子查询
  9. 最佳实践: 总结了高级查询的性能优化和设计模式

通过本章的学习,你应该能够构建复杂的数据库查询,并能够根据实际需求进行性能优化。

下一章: 第七章-多表联查与导航属性