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

如何将SQL查询结果映射到含接口参数构造函数的C#类(EF6转原生SQL)

解决方案

方案1:SQL端直接聚合(推荐,性能最优)

无需硬凑IGrouping参数的构造函数,直接在数据库层面完成分组统计,避免冗余数据传输,是原生SQL实现的最优选择。

  1. 改写SQL为分组统计语句:
SELECT 
    dsm.Name,
    CONCAT(ds.VersionMajor, '.', ds.VersionMinor, '.', ds.VersionPatch) AS Version,
    COUNT(ld.LogDownloadId) AS Count
FROM LogDownloads ld
INNER JOIN DiagSofts ds ON ld.DiagSoftId = ds.DiagSoftId
INNER JOIN DiagSoftMarks dsm ON ds.DiagSoftMarkId = dsm.DiagSoftMarkId
WHERE ld.MemberShipId = @MemberShipId
GROUP BY dsm.Name, ds.VersionMajor, ds.VersionMinor, ds.VersionPatch
ORDER BY Count DESC, Name ASC, Version ASC
  1. 给DiagSoftDownload新增无参构造函数兼容映射,不影响原有逻辑:
public class DiagSoftDownload
{
    // 保留原有构造函数
    public DiagSoftDownload(IGrouping<DiagSoft, LogDownload> data)
    {
        Name = data.Key.DiagSoftMark.Name;
        Version = data.Key.Version;
        Count = data.Count();
    }
    // 新增无参构造用于映射
    public DiagSoftDownload() {}
    public string Name { get; set; }
    public string Version { get; set; }
    public int Count { get; set; }
}
  1. Dapper查询代码:
using (var conn = new SqlConnection("你的数据库连接字符串"))
{
    var result = conn.Query<DiagSoftDownload>(
        "上面的分组SQL语句",
        new { MemberShipId = VM.SelectedMembershipLog.MembershipId }
    ).ToList();
}

方案2:保留原有逻辑,内存分组

如果不想修改原有DiagSoftDownload类的定义,可以先查全量关联数据,在内存中完成分组后实例化对象:

  1. 用Dapper多映射功能关联查询三个表的实体:
using (var conn = new SqlConnection("你的数据库连接字符串"))
{
    var sql = "你从EF提取的原SQL,将WHERE条件的447替换为参数@MemberShipId";
    // 拆分行数据到三个关联实体
    var logDownloads = conn.Query<LogDownload, DiagSoft, DiagSoftMark, LogDownload>(
        sql,
        (log, soft, mark) => 
        {
            soft.DiagSoftMark = mark;
            log.DiagSoft = soft;
            return log;
        },
        splitOn: "DiagSoftId,DiagSoftMarkId", // 按这两个字段拆分列到对应实体
        param: new { MemberShipId = VM.SelectedMembershipLog.MembershipId }
    ).ToList();

    // 内存分组后实例化目标类,和原EF逻辑完全一致
    var result = logDownloads
        // 如果DiagSoft没有重写Equals/HashCode,可改为GroupBy(m=>m.DiagSoft.DiagSoftId)
        .GroupBy(m => m.DiagSoft)
        .Select(g => new DiagSoftDownload(g))
        .OrderByDescending(m => m.Count)
        .ThenBy(m => m.Name)
        .ThenBy(m => m.Version)
        .ToList();
}

如果按DiagSoftId分组,需要自己实现简单的IGrouping实现类:

public class Grouping<TKey, TElement> : IGrouping<TKey, TElement>
{
    public TKey Key { get; }
    public IEnumerable<TElement> Elements { get; }
    public Grouping(TKey key, IEnumerable<TElement> elements)
    {
        Key = key;
        Elements = elements;
    }
    public IEnumerator<TElement> GetEnumerator() => Elements.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

报错原因说明

之前用Dapper/ SqlDataReaderMapper直接映射报错,是因为这些ORM默认只能构造参数为基础类型的实例,你原来的构造函数参数是IGrouping<DiagSoft, LogDownload>这种复杂接口类型,ORM无法直接从查询列生成对应的实例,所以需要先拿到基础数据后自行构造。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 20:45:03