C# 实体框架原始SQL查询方法 C# EF Core如何执行原生SQL

来源:这里教程网 时间:2026-02-21 17:40:48 作者:

EF Core 用
FromSqlRaw
执行 SELECT 查询(带实体映射)

想让原生 SQL 返回强类型实体,必须用

FromSqlRaw
配合 DbSet,且 SQL 查询列名、顺序、类型需与实体完全匹配。EF Core 不做字段映射或类型转换,错一个就抛
InvalidOperationException

常见错误:SQL 中用了别名但没和属性名一致;SELECT * 但表里有计算列或 NULL 值导致类型不兼容;忘了加

AsNoTracking()
导致无谓性能开销。

FromSqlRaw
只能用于
DbSet<t></t>
,不能用于普通 IQueryable 或 List
SQL 必须返回所有实体属性对应字段,不可少、不可多(除非实体用
[NotMapped]
标记多余字段)
参数化防注入必须用
{0}
占位符 +
params object[]
,例如:
context.Users.FromSqlRaw("SELECT * FROM Users WHERE Age > {0}", 18)
若只需部分字段,建议新建轻量 DTO 类,并用
FromSqlRaw
+
AsEnumerable()
后手动投影,EF Core 不支持原生 SQL 直接映射到匿名类型或非实体类

EF Core 调用存储过程或无返回结果的 SQL(INSERT/UPDATE/DELETE)

ExecuteSqlRaw
(EF Core 5+)或旧版
ExecuteSqlCommand
,它只返回影响行数
int
,不涉及实体映射。

容易踩的坑:传参时误用字符串拼接;执行含多个语句的 SQL(如先 SET NOCOUNT ON 再 SELECT)导致异常;在事务外调用却期望一致性。

参数仍须用
{0}
占位,不可写成
"WHERE Id = " + id
存储过程中若含
SELECT
结果集,
ExecuteSqlRaw
会忽略,要读结果必须改用
FromSqlRaw
或 ADO.NET
若需获取新插入记录的 ID(如 SQL Server 的
SCOPE_IDENTITY()
),
ExecuteSqlRaw
无法返回,得用
Database.GetDbConnection()
拿底层连接手写 ADO.NET

需要返回标量值或自定义结构?绕过 EF Core 映射直接走 ADO.NET

EF Core 原生 SQL 能力有限:不支持多结果集、不支持 OUT 参数、不能返回

DateTimeOffset
等未映射类型、也不处理存储过程中的临时表逻辑。这时必须切到原始 ADO.NET。

关键点是复用 EF Core 的连接生命周期——别自己 new SqlConnection,而要用

context.Database.GetDbConnection()
,确保连接打开状态与 EF 事务一致。

连接未打开时需手动
Open()
,但注意 EF Core 可能已管理该连接,重复 Open 会报错
DbCommand
设置
CommandType = CommandType.StoredProcedure
调用带 OUT 参数的过程
读多结果集用
reader.NextResult()
,EF Core 的
FromSqlRaw
完全不支持这个
记得用
using
包裹 command 和 reader,避免连接泄漏

为什么
FromSqlInterpolated
FromSqlRaw
更安全?

FromSqlInterpolated
是 C# 字符串插值语法的封装,它自动把插值变量转为参数化查询,从根本上防止 SQL 注入。而
FromSqlRaw
若拼接用户输入,等于裸奔。

但它的限制也很实在:只支持单个插值表达式,不能拼复杂逻辑;不支持插值后加额外 WHERE 条件;且插值内容必须是变量或常量,不能是方法调用(如

$"..." + GetCondition()
会绕过参数化)。

正确用法:
context.Products.FromSqlInterpolated($"SELECT * FROM Products WHERE Price > {minPrice}")
错误写法:
context.Products.FromSqlInterpolated($"SELECT * FROM Products WHERE Price > " + minPrice)
—— 这彻底退化为字符串拼接
不支持插值中嵌套三元运算符或空合并:用
??
?:
会导致编译失败,得提前算好值再插

EF Core 的原生 SQL 支持本质是“有限透传”,不是万能替代。真正复杂的查询、多结果、动态列、权限控制逻辑,迟早得切到 ADO.NET;而日常简单定制查询,选对

FromSqlRaw
/
FromSqlInterpolated
/
ExecuteSqlRaw
这三个入口,比硬套 LINQ 更快也更可控。

相关推荐