You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在LINQ中针对多个可空Int键实现多条件筛选?

基于多可空Int键的数据查询优化需求

问题背景

需要编写一个查询,基于多个可空Int类型的键检索数据,使用的筛选参数DTO如下:

public class FilterParamsDto {
    public int? StudentId { get; set; }
    public int? NationalityId { get; set; }
    public int? CountryId { get; set; }
    public int? SchoolCountryId { get; set; }
    public int? SchoolStateId { get; set; }
    public int? SchoolCityId { get; set; }

    // 更多属性...
}

最初尝试的查询逻辑嵌套复杂,难以维护:

var value = from y in data
            where dto.CountryId == null
                ? y.CountryId != null
                : y.IntakeId == dto.CountryId && dto.StudentId == null
                    ? y.StudentId != null
                    : y.StudentId == dto.StudentId && dto.SchoolCityId == null
                        ? y.SchoolCityId != null
                        : y.SchoolCityId == dto.SchoolCityId
            select y;

核心需求

  • 当DTO的任意属性有值且值不为0时,基于该属性筛选数据;若属性无值或值为0,则跳过该条件
  • 筛选逻辑为链式执行:用第一个有效条件过滤数据集后,再用下一个有效条件过滤上一步的结果,依次类推
  • 覆盖三种场景:所有属性有值、部分属性有值、所有属性无值/值为0(此时返回全部数据)

解决方案

方案1:链式Where查询(直观易维护)

这种方式逻辑清晰,完全符合链式筛选的要求,ORM框架(如EF Core)会自动将多个Where条件合并为单一SQL查询,不会产生性能损耗。

// 初始化为可查询数据集
var query = data.AsQueryable();

// 逐个处理筛选属性,仅当属性有值且不为0时添加筛选条件
if (dto.StudentId.HasValue && dto.StudentId.Value != 0)
{
    query = query.Where(y => y.StudentId == dto.StudentId.Value);
}

if (dto.NationalityId.HasValue && dto.NationalityId.Value != 0)
{
    query = query.Where(y => y.NationalityId == dto.NationalityId.Value);
}

if (dto.CountryId.HasValue && dto.CountryId.Value != 0)
{
    query = query.Where(y => y.CountryId == dto.CountryId.Value);
}

if (dto.SchoolCountryId.HasValue && dto.SchoolCountryId.Value != 0)
{
    query = query.Where(y => y.SchoolCountryId == dto.SchoolCountryId.Value);
}

if (dto.SchoolStateId.HasValue && dto.SchoolStateId.Value != 0)
{
    query = query.Where(y => y.SchoolStateId == dto.SchoolStateId.Value);
}

if (dto.SchoolCityId.HasValue && dto.SchoolCityId.Value != 0)
{
    query = query.Where(y => y.SchoolCityId == dto.SchoolCityId.Value);
}

// 更多属性按相同逻辑添加

// 执行查询
var result = query.ToList();

方案2:反射+表达式树(适合属性较多场景)

如果DTO中有大量可筛选属性,手动写多个if会产生重复代码,可通过反射+表达式树动态生成筛选条件:

var query = data.AsQueryable();
// 获取DTO中所有可空Int类型且有值(非0)的属性
var validFilterProps = typeof(FilterParamsDto).GetProperties()
    .Where(p => p.PropertyType == typeof(int?))
    .Select(p => new 
    {
        PropName = p.Name,
        PropValue = (int?)p.GetValue(dto)
    })
    .Where(x => x.PropValue.HasValue && x.PropValue.Value != 0);

foreach (var prop in validFilterProps)
{
    // 动态构建筛选表达式
    var param = Expression.Parameter(typeof(YourDataModel), "y"); // 替换为实际数据实体类型
    var entityProp = Expression.Property(param, prop.PropName);
    var constantVal = Expression.Constant(prop.PropValue.Value);
    var equalExpr = Expression.Equal(entityProp, constantVal);
    var filterLambda = Expression.Lambda<Func<YourDataModel, bool>>(equalExpr, param);

    query = query.Where(filterLambda);
}

var result = query.ToList();

注意事项

  • 原查询中存在笔误:y.IntakeId == dto.CountryId应为y.CountryId == dto.CountryId,需修正避免逻辑错误
  • 若使用EF Core等ORM,链式Where不会导致多次数据库查询,最终会合并为一个带多个AND条件的SQL语句

内容的提问来源于stack exchange,提问作者Ashwani Bhardwaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 13:16:59