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

将含FORMAT命令的SQL查询转换为可在Entity Framework Core中使用的实现方案

解决方案

你之前调用.FromSqlRaw()报错的原因是直接在绑定了完整表结构的DbSet<ScrapLog>上执行查询,EF要求返回结果必须和ScrapLog实体的字段完全匹配,你返回自定义的两列自然无法适配,可通过以下两种方案实现需求:

方案1:沿用原生SQL执行

如果不想修改原有SQL逻辑,只要新增一个接收结果的DTO类,再配置无键实体即可:

  1. 定义结果接收类
public class ScrapCountDto
{
    public string Date { get; set; }
    public int Quantity { get; set; }
}
  1. 在你的DbContext中注册该类为无键实体
    在OnModelCreating方法中添加配置:
modelBuilder.Entity<ScrapCountDto>().HasNoKey();
  1. 在DbContext中添加对应DbSet属性
public DbSet<ScrapCountDto> ScrapCounts { get; set; }
  1. 执行查询即可
var result = await _context.ScrapCounts
    .FromSqlRaw(@"SELECT 
                FORMAT(datetime_scrapped, 'MMMM-yy') as Date, 
                count(*) as Quantity 
                FROM scrap_log 
                GROUP BY FORMAT(datetime_scrapped, 'MMMM-yy')")
    .ToListAsync();

方案2:使用原生EF Core LINQ实现(推荐)

不需要写硬编码的SQL,完全由EF自动生成查询语句,性能更好也更易维护,还能避免SQL注入风险:

var result = await _context.ScrapLogs
    // 先按年、月数字分组,比直接按格式化字符串分组效率更高
    .GroupBy(s => new 
    { 
        s.DateTimeScrapped.Year, 
        s.DateTimeScrapped.Month 
    })
    .Select(g => new ScrapCountDto
    {
        // 内存中拼接成需要的年月格式,避免数据库侧的格式化性能损耗
        Date = new DateTime(g.Key.Year, g.Key.Month, 1).ToString("MMMM-yy"),
        Quantity = g.Count()
    })
    // 可选:按时间倒序排列
    .OrderByDescending(x => x.Date)
    .ToListAsync();

如果需要固定返回英文月份全称,只要在ToString时指定区域信息即可:

Date = new DateTime(g.Key.Year, g.Key.Month, 1).ToString("MMMM-yy", CultureInfo.GetCultureInfo("en-US"))

EF Core原生支持上述写法,会自动转换为符合数据库语法的SQL语句,不需要手动处理FORMAT函数的映射逻辑。

注意事项

如果你需要适配除SQL Server之外的其他数据库,优先使用方案2的LINQ写法,不需要调整SQL语句,EF会自动处理不同数据库的时间函数差异。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 14:36:04