在C#项目中使用Dapper进行数据库操作时,开发者经常会遇到各种类型的错误,这些错误有的源于配置问题,有的源于使用方式不当,掌握常见错误的排查和解决方法能大幅提升开发效率。

Dapper常见错误类型及解决方法
参数映射异常
这是Dapper使用中最常见的错误之一,通常表现为执行SQL时提示参数不存在,或者参数值没有正确传入。出现这类问题的原因大多是参数名称和SQL中的占位符不匹配,或者参数类型不兼容。
比如下面的错误示例,SQL中使用的占位符是@UserName,但传入的参数属性名是Username,大小写不一致就会导致映射失败:
// 错误示例
public class UserParam
{
public string Username { get; set; }
}
using (var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True"))
{
// SQL中占位符是@UserName,和参数属性Username不匹配
var sql = "SELECT * FROM Users WHERE UserName = @UserName";
var result = conn.Query<User>(sql, new UserParam { Username = "张三" }).ToList();
}
解决方法很简单,保证参数属性名和SQL中的占位符完全一致,同时注意参数类型要和数据库字段类型兼容:
// 正确示例
public class UserParam
{
public string UserName { get; set; } // 属性名和SQL占位符一致
}
using (var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True"))
{
var sql = "SELECT * FROM Users WHERE UserName = @UserName";
var result = conn.Query<User>(sql, new UserParam { UserName = "张三" }).ToList();
}
数据库连接未正确释放
Dapper本身不会自动管理连接的生命周期,如果开发者没有正确释放数据库连接,会导致连接池耗尽,后续请求无法获取连接,出现超时错误。
常见错误是手动打开连接后没有关闭,或者没有使用using语句包裹连接对象:
// 错误示例
public List<User> GetUsers()
{
var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True");
conn.Open();
var sql = "SELECT * FROM Users";
return conn.Query<User>(sql).ToList();
// 连接没有关闭,也没有释放
}
正确的做法是用using语句包裹连接对象,确保连接在使用完成后自动释放:
// 正确示例
public List<User> GetUsers()
{
// using会自动释放连接,即使出现异常也会执行释放逻辑
using (var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True"))
{
var sql = "SELECT * FROM Users";
return conn.Query<User>(sql).ToList();
}
}
SQL语句拼接导致的问题
部分开发者为了动态生成SQL,会直接拼接字符串,这很容易引发SQL注入风险,同时如果拼接逻辑处理不当,还会出现SQL语法错误。
比如下面的错误示例,直接拼接用户输入的参数,既不安全也容易因为参数包含特殊字符导致SQL语法错误:
// 错误示例
public List<User> GetUsersByName(string name)
{
using (var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True"))
{
// 直接拼接字符串,存在SQL注入风险,且如果name包含单引号会导致语法错误
var sql = $"SELECT * FROM Users WHERE UserName = '{name}'";
return conn.Query<User>(sql).ToList();
}
}
解决方法是不直接拼接SQL,而是使用Dapper的参数化查询,既安全又能避免语法错误:
// 正确示例
public List<User> GetUsersByName(string name)
{
using (var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True"))
{
var sql = "SELECT * FROM Users WHERE UserName = @UserName";
// 使用参数化查询,Dapper会自动处理参数转义
return conn.Query<User>(sql, new { UserName = name }).ToList();
}
}
实体映射不匹配错误
当查询结果的字段名和实体类的属性名不一致时,Dapper无法自动完成映射,会出现属性值为空或者映射失败的错误。
比如数据库字段是user_name,而实体类属性是UserName,默认情况下Dapper不会自动映射:
// 错误示例
public class User
{
public int Id { get; set; }
public string UserName { get; set; } // 实体属性是UserName
}
using (var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True"))
{
// 数据库字段是user_name,和实体属性UserName不匹配
var sql = "SELECT id, user_name FROM Users";
var result = conn.Query<User>(sql).ToList(); // UserName属性会为空
}
解决方法有两种,一种是在SQL中给字段起别名,和实体属性名一致;另一种是使用自定义映射规则:
// 解决方法1:SQL起别名
using (var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True"))
{
// 给user_name起别名为UserName,和实体属性匹配
var sql = "SELECT id, user_name AS UserName FROM Users";
var result = conn.Query<User>(sql).ToList();
}
// 解决方法2:自定义映射(适合全局统一映射规则)
Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; // 开启下划线转驼峰映射
using (var conn = new SqlConnection("Server=.;Database=Test;Trusted_Connection=True"))
{
var sql = "SELECT id, user_name FROM Users";
var result = conn.Query<User>(sql).ToList(); // 会自动把user_name映射到UserName
}
错误排查通用技巧
遇到Dapper相关错误时,可以按照以下步骤快速排查:
- 首先检查SQL语句是否正确,可以把生成的SQL拿到数据库客户端直接执行,验证语法和结果是否符合预期
- 检查参数是否正确传入,可以在调试时查看参数对象的值和类型,确认和SQL占位符匹配
- 检查数据库连接字符串是否正确,数据库服务是否正常运行,连接是否能正常打开
- 如果是映射问题,检查查询结果字段和实体属性的对应关系,确认是否有名称不一致的情况
- 查看异常堆栈信息,Dapper的异常通常会明确提示错误原因,比如参数缺失、连接失败等,根据提示定位问题
掌握以上常见错误的解决方法和排查技巧,能有效减少使用Dapper时的调试时间,让数据库操作开发更加顺畅。