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

C#结合Session使用LINQ按年周过滤数据解决记录重复问题

当前查询出现重复数据的核心原因
  • 你在LINQ中连续编写5次from m in db.Models这类交叉遍历逻辑,但完全没有给这些Model表的遍历增加任何实体间的关联条件,最终生成的SQL会触发全表笛卡尔积——把ProductionDays、5个无关联的Models集合做所有排列组合的拼接,哪怕后续加了Where过滤条件,重复记录也会被不同的遍历路径放大,和你手动在数据库编写带正确关联的查询结果自然无法对齐。
  • 现有视图模型存在类型不匹配问题:ExtractionViewModel中VW270PA属性定义为int类型,但赋值时传入的是字符串类型的m.Name(车型名称),运行时会直接触发类型转换异常。
  • 你当前的逻辑完全没有接入Session的动态过滤能力,所有过滤条件都是硬编码在查询语句中,根本无法实现类Excel的灵活筛选效果。
正确的功能实现方案

1. 重构基础LINQ查询,从根源消除重复数据

多次无关联遍历Models表的写法完全冗余,你只需要基于有外键关系的ProductionDays、Weeks表做基础关联,再通过子查询匹配对应车型的字段值即可,完全不需要交叉遍历全表:

public IList<ExtractionViewModel> GetExtractionViewModels(Dictionary<string, object> filterConditions)
{
    var db = new ProductionManagementEntities();
    // 基础关联:仅连接存在外键绑定的生产日、周维度表
    var baseQuery = from p in db.ProductionDays
                    join w in db.Weeks on p.WeekId equals w.WeekId
                    where p.InActive == false && w.InActive == false
                    select new ExtractionViewModel
                    {
                        Year = w.Year.ToString(),
                        Day = p.ProductionDate,
                        Week = w.WeekNum,
                        // 子查询匹配对应车型值,避免无关联交叉遍历
                        VW270 = db.Models.Where(m => m.Name == "VW270" && m.InActive == false).Select(m => m.Name).FirstOrDefault(),
                        VW270PA = db.Models.Where(m => m.Name == "VW270PA" && m.InActive == false).Select(m => m.ModelId).FirstOrDefault(),
                        VW250 = db.Models.Where(m => m.Name == "VW250" && m.InActive == true).Select(m => m.Name).FirstOrDefault(),
                        VW2502PA = db.Models.Where(m => m.Name == "VW250/2PA" && m.InActive == false).Select(m => m.Name).FirstOrDefault()
                    };

    // 动态拼接传入的过滤条件
    if (filterConditions.TryGetValue("Year", out var yearVal))
    {
        int targetYear = int.Parse(yearVal.ToString());
        baseQuery = baseQuery.Where(x => int.Parse(x.Year) == targetYear);
    }
    if (filterConditions.TryGetValue("WeekNum", out var weekVal))
    {
        int targetWeek = int.Parse(weekVal.ToString());
        baseQuery = baseQuery.Where(x => x.Week == targetWeek);
    }

    // 按业务规则排序后返回
    return baseQuery
        .OrderByDescending(x => x.Year)
        .ThenByDescending(x => x.Day)
        .ThenByDescending(x => x.Week)
        .ToList();
}

2. 结合Session实现动态过滤逻辑

  • 前端每次触发筛选操作(比如选择2021年、第53周)时,先把用户选择的键值对过滤条件存入Session:
    // 存Session:仅存简单的筛选参数,不要放实体集合占用内存
    Session["ExtractionFilter"] = new Dictionary<string, object>
    {
        {"Year", 2021},
        {"WeekNum", 53}
    };
    
  • 每次查询列表、导出Excel时,统一从Session读取过滤参数,传入上述查询方法即可,保证查询和导出使用完全一致的过滤逻辑。
结果一致性校验要点
  • 如果修改后的查询结果仍和数据库手动执行的结果有差异,可以在LINQ查询末尾调用ToString()输出实际生成的SQL语句,直接复制到数据库管理器中执行,对比和你手写查询的差异,定位是关联条件缺失还是过滤逻辑写错。
  • 注意打通数据源链路:你现有代码中列表页、导出Excel都是从MongoDB读取数据,但基础查询是连接SQL Server,两个数据源不同步的话结果必然不一致。要么把SQL Server查询得到的过滤结果同步到Mongo,要么直接从SQL Server读取数据做导出,不要在链路中跳换数据源。
  • 排查笛卡尔积问题时,只要看到LINQ中写了2次以上对同一张表的from遍历、且没有写关联条件,优先排查是否触发了全表组合拼接。

内容的提问来源于stack exchange,提问作者Gcobani Mkontwana

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 08:06:03