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

如何通过LINQ按指定字段从MS SQL数据库获取去重数据?

解决LINQ按动态指定字段去重查询的问题

首先说下你原代码的核心问题:e[filterParam]这种动态属性访问在LINQ to Entities里是不被支持的,EF没法把这种写法转换成对应的SQL语句,所以会直接报错。另外,默认的Distinct()是对比整个ScbDataInfo实体的所有属性,除非你重写了实体的Equals和GetHashCode,否则也达不到按指定字段去重的效果。

下面给你两种解决方案,按需选择:

方案1:针对已知字段用Switch-Case(简单易维护)

既然你要筛选的字段只有school和class这几个,直接用switch-case分支处理最直观,也不容易出问题:

如果你要返回按指定字段去重的实体集合

public IEnumerable<ScbDataInfo> GetScbOptionsByFilter(string filterParam)
{
    using (SRSContext entityContext = new SRSContext())
    {
        IQueryable<ScbDataInfo> query = entityContext.Set<ScbDataInfo>();

        switch (filterParam.Trim().ToLower())
        {
            case "school":
                // 按School分组,取每组第一条实现去重
                query = query.GroupBy(e => e.school)
                             .Select(g => g.FirstOrDefault());
                break;
            case "class":
                query = query.GroupBy(e => e.Class)
                             .Select(g => g.FirstOrDefault());
                break;
            default:
                // 处理无效字段,返回空集合或抛出异常都可以
                return Enumerable.Empty<ScbDataInfo>();
        }

        // 按需求排序
        query = query.OrderBy(e => e.RefNo).ThenBy(e => e.datepmt);

        return query.ToArray();
    }
}

如果你只需要返回指定字段的所有唯一值(比如所有不同的学校名称)

可以修改方法返回类型,直接提取字段值:

public IEnumerable<string> GetDistinctFieldValues(string filterParam)
{
    using (SRSContext entityContext = new SRSContext())
    {
        switch (filterParam.Trim().ToLower())
        {
            case "school":
                return entityContext.Set<ScbDataInfo>()
                                    .Select(e => e.school)
                                    .Distinct()
                                    .OrderBy(s => s)
                                    .ToArray();
            case "class":
                return entityContext.Set<ScbDataInfo>()
                                    .Select(e => e.Class)
                                    .Distinct()
                                    .OrderBy(c => c)
                                    .ToArray();
            default:
                return Enumerable.Empty<string>();
        }
    }
}

方案2:用表达式树实现动态字段访问(通用方案)

如果以后要支持更多字段,不想写一堆switch-case,可以用表达式树动态构建查询逻辑,这样不管加多少字段都不用改查询代码:

using System.Reflection;
using System.Linq.Expressions;

public IEnumerable<ScbDataInfo> GetScbOptionsByFilter(string filterParam)
{
    using (SRSContext entityContext = new SRSContext())
    {
        // 反射获取指定字段的属性信息,忽略大小写
        var property = typeof(ScbDataInfo).GetProperty(
            filterParam, 
            BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
        
        if (property == null)
        {
            return Enumerable.Empty<ScbDataInfo>();
        }

        // 构建动态访问属性的表达式
        var param = Expression.Parameter(typeof(ScbDataInfo), "e");
        var propertyAccess = Expression.MakeMemberAccess(param, property);
        var keySelector = Expression.Lambda<Func<ScbDataInfo, object>>(
            Expression.Convert(propertyAccess, typeof(object)), 
            param);

        // 执行分组去重+排序
        var query = entityContext.Set<ScbDataInfo>()
                                .GroupBy(keySelector)
                                .Select(g => g.FirstOrDefault())
                                .OrderBy(e => e.RefNo)
                                .ThenBy(e => e.datepmt);

        return query.ToArray();
    }
}

额外说明

  • 关于GroupBy替代Distinct:因为默认的Distinct()会对比实体的所有属性,用GroupBy按目标字段分组后取第一条,能更精准地实现按指定字段去重的需求。
  • 大小写兼容:代码里都做了大小写处理,不管你传入的是School还是school都能正常识别。

内容的提问来源于stack exchange,提问作者Ande Caleb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:12:45