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

如何在Dapper中传入列表参数?现有查询实现求优化

优化你的用户课程查询方法

你的现有代码能运行,但存在多次数据库往返、手动SQL拼接易出错的问题,下面是几种更优的实现方式:

1. 合并为单条SQL查询(首推)

直接通过JOIN或子查询把两个操作合并成一次数据库请求,减少网络开销,代码更简洁:

方式一:使用INNER JOIN

public List<Course> GetMyCourses(int id)
{
    string query = @"
        SELECT c.Id, c.Image, c.CourseStateId, c.Price, c.Title, c.TeacherId, u.UserName, u.Id
        FROM Courses c
        INNER JOIN Users u ON u.Id = c.TeacherId
        INNER JOIN CourseUsers cu ON cu.CourseId = c.Id
        WHERE cu.UserId = @id";
    
    var courses = db.Query<Course>(query, new { id }).ToList();
    return courses.Count == 0 ? null : courses;
}

方式二:使用子查询

public List<Course> GetMyCourses(int id)
{
    string query = @"
        SELECT c.Id, c.Image, c.CourseStateId, c.Price, c.Title, c.TeacherId, u.UserName, u.Id
        FROM Courses c
        INNER JOIN Users u ON u.Id = c.TeacherId
        WHERE c.Id IN (SELECT CourseId FROM CourseUsers WHERE UserId = @id)";
    
    var courses = db.Query<Course>(query, new { id }).ToList();
    return courses.Count == 0 ? null : courses;
}

这两种方式都只需要一次数据库查询,避免了先查ID列表再拼接SQL的繁琐,同时语法更规范,不易出错。

2. 必须分两次查询时,用参数化IN语句

如果因为业务限制必须先获取ID列表,不要手动拼接字符串,改用参数化方式处理IN子句,避免潜在的语法错误和SQL注入风险:

public List<Course> GetMyCourses(int id)
{
    string secQuery = "SELECT CourseId FROM CourseUsers WHERE UserId = @id";
    var courseIds = db.Query<int>(secQuery, new { id }).ToList();
    
    if (!courseIds.Any())
    {
        return null;
    }
    
    // 生成带参数的IN子句
    var paramList = courseIds.Select((cid, idx) => new { ParamName = $"@cid{idx}", Value = cid }).ToList();
    string inClause = string.Join(", ", paramList.Select(p => p.ParamName));
    
    string query = $@"
        SELECT c.Id, c.Image, c.CourseStateId, c.Price, c.Title, c.TeacherId, u.UserName, u.Id
        FROM Courses c
        INNER JOIN Users u ON u.Id = c.TeacherId
        WHERE c.Id IN ({inClause})";
    
    // 构建参数集合
    var dynamicParams = new DynamicParameters();
    foreach (var param in paramList)
    {
        dynamicParams.Add(param.ParamName, param.Value);
    }
    
    return db.Query<Course>(query, dynamicParams).ToList();
}

3. 用ORM的LINQ查询(如果使用EF Core等ORM)

如果你的项目用的是Entity Framework Core这类ORM,可以直接用LINQ查询,代码可读性更强,ORM会自动生成优化的SQL:

public List<Course> GetMyCourses(int id)
{
    var courses = _context.Courses
        .Include(c => c.Teacher) // 假设Course实体有Teacher导航属性
        .Where(c => c.CourseUsers.Any(cu => cu.UserId == id))
        .Select(c => new Course
        {
            Id = c.Id,
            Image = c.Image,
            CourseStateId = c.CourseStateId,
            Price = c.Price,
            Title = c.Title,
            TeacherId = c.TeacherId,
            UserName = c.Teacher.UserName
        })
        .ToList();
    
    return courses.Count == 0 ? null : courses;
}

原代码的几个小问题

  • 手动拼接SQL时逻辑复杂,容易出现语法错误(比如括号遗漏、逗号位置不对);
  • 两次数据库查询增加了网络延迟;
  • 虽然整数ID的SQL注入风险低,但手动拼接字符串不是最佳实践,参数化查询才是规范做法。

内容的提问来源于stack exchange,提问作者Bob-Programming

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 11:35:19