使用场景
当 LINQ 查询难以表达,或者生成的 SQL 性能不佳(如产生多次查询、低效的 CASE 嵌套等)时,可以直接在 DataContext 上执行原生 SQL 语句。
代价: 失去编译期类型检查,SQL 写错只能在运行时发现;且需要预先定义好接收结果的实体类。
基础用法
using (var db = new DataClasses1DataContext())
{
// 直接执行 SELECT,结果映射到 StudentInfo 类
var res = db.ExecuteQuery<StudentInfo>(
"select Student.ID, Student.Name, Classx.Name as ClassName " +
"from Student join Classx on Student.ClassID = Classx.ID"
).ToList();
}Code language: JavaScript (javascript)
要求: StudentInfo 类的属性名必须与查询结果集的列名匹配(不区分大小写,但建议一致):
public class StudentInfo
{
public int ID { get; set; }
public string Name { get; set; }
public string ClassName { get; set; }
}Code language: JavaScript (javascript)
带参数的查询
方式一:参数化传参(推荐,安全)
var res2 = db.ExecuteQuery<StudentInfo>(
"select Student.ID, Student.Name, Classx.Name as ClassName " +
"from Student join Classx on Student.ClassID = Classx.ID AND Student.ID = {0}",
"2"
).ToList();Code language: JavaScript (javascript)
{0}是参数占位符,ExecuteQuery会将其作为参数化查询发送给数据库,等效于:
exec sp_executesql N'select ... AND Student.ID = @p0', N'@p0 nvarchar(1)', @p0=N'2'Code language: JavaScript (javascript)
方式二:字符串拼接(不推荐,有注入风险)
// 直接拼入 SQL 字符串
var res2 = db.ExecuteQuery<StudentInfo>(
"select Student.ID, Student.Name, Classx.Name as ClassName " +
"from Student join Classx on Student.ClassID = Classx.ID AND Student.ID = 2"
).ToList();Code language: JavaScript (javascript)
LIKE 查询的注意事项
// 下面这样写可能查不到结果!
var res3 = db.ExecuteQuery<StudentInfo>(
"select Student.ID, Student.Name, Classx.Name as ClassName " +
"from Student join Classx on Student.ClassID = Classx.ID " +
"AND Student.Name like ''%{0}%''",
"李"
).ToList();Code language: JavaScript (javascript)
问题原因:
ExecuteQuery 的 {0} 占位符会被当作参数传递。当 LIKE '%李%' 作为参数时,数据库收到的是:
exec sp_executesql N'... AND Student.Name like @p0', N'@p0 nvarchar(1)', @p0=N'%李%'Code language: JavaScript (javascript)
在某些数据库配置下(如 varchar vs nvarchar 隐式转换、排序规则不匹配),参数化 LIKE 可能不走索引或匹配失败。
解决方案一:直接在 SQL 中拼接通配符(参数只传纯值)
// 占位符只接收纯值,通配符写在 SQL 里
var res3 = db.ExecuteQuery<StudentInfo>(
"select Student.ID, Student.Name, Classx.Name as ClassName " +
"from Student join Classx on Student.ClassID = Classx.ID " +
"AND Student.Name like '%' + {0} + '%'",
"李"
).ToList();Code language: JavaScript (javascript)
解决方案二:直接拼接完整 SQL(简单场景,确保输入安全)
var keyword = "李";
var res3 = db.ExecuteQuery<StudentInfo>(
"select Student.ID, Student.Name, Classx.Name as ClassName " +
"from Student join Classx on Student.ClassID = Classx.ID " +
$"AND Student.Name like '%{keyword}%'"
).ToList();Code language: JavaScript (javascript)
注意: 方案二仅适用于输入可信场景,生产环境应校验输入或改用方案一的
'%' + {0} + '%'写法。
三种调用方式汇总
| 写法 | SQL 参数化 | 安全性 | 适用场景 |
|---|---|---|---|
ExecuteQuery<T>(sql) | 否 | 依赖 SQL 本身 | SQL 无参数 |
ExecuteQuery<T>(sql, param) | 是,{0} 为参数 | 安全 | 单值/多值条件 |
ExecuteQuery<T>(sql, param1, param2) | 是,{0}、{1} 为参数 | 安全 | 多个条件 |
执行非查询 SQL(INSERT / UPDATE / DELETE)
// 执行无返回结果集的 SQL
db.ExecuteCommand(
"UPDATE Student SET Name = {0} WHERE ID = {1}",
"新名字", 1
);
// 批量删除
db.ExecuteCommand(
"DELETE FROM booklabel WHERE bid = {0}",
12
);Code language: JavaScript (javascript)
ExecuteCommand返回受影响的行数(int)。
Previous: 表关联的两种写法:查询语法 vs 方法语法(Lambda)
Next: 交叉连接、全连接、外连接与自连接