如何在Entity Framework Core 2.1中执行SQL查询?
在EF Core 2.1中执行非DbSet的原生SQL查询
你提到的问题确实是EF Core和EF6的一个关键区别——EF6的Database.SqlQuery可以直接执行返回任意类型的原生SQL,但EF Core 2.1的FromSql仅绑定到DbSet<T>。下面给你几种可行的解决方案:
方案1:创建一个“虚拟”DbSet映射结果类型
如果你的查询返回的是简单类型(比如string)或者自定义的结果模型,可以在DbContext中定义一个对应的DbSet<T>,即使这个类型没有对应的数据库表。
比如,先定义一个包装类来接收查询结果:
public class TitleResult { public string Title { get; set; } }
然后在你的DbContext里添加这个DbSet:
public DbSet<TitleResult> TitleResults { get; set; }
接下来就可以用FromSql执行查询了,注意要确保查询的列名和类的属性名匹配:
var titles = context.TitleResults.FromSql("SELECT a.title AS Title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10").ToList();
方案2:直接使用ADO.NET原生操作
如果你不想额外定义DbSet,可以直接通过DbContext的数据库连接来执行原始SQL,这和传统的ADO.NET操作类似:
var results = new List<string>(); using (var command = context.Database.GetDbConnection().CreateCommand()) { command.CommandText = "SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10"; // 确保连接打开(如果还没打开的话) if (command.Connection.State != System.Data.ConnectionState.Open) { command.Connection.Open(); } using (var reader = command.ExecuteReader()) { while (reader.Read()) { // 读取第一列的值(对应title) results.Add(reader.GetString(0)); } } } return results;
这种方法的好处是完全灵活,不需要依赖EF Core的实体映射,但需要手动处理数据读取和连接管理。
注意事项(针对EF Core 2.1)
- EF Core 3.0及以后版本支持无键实体类型(通过
[Keyless]特性或HasNoKey()配置),可以更优雅地处理这类无表的查询结果,但2.1版本还没有这个功能,所以上面两种是最适合你的方案。 - 使用
FromSql时,确保SQL语句的列名和实体类的属性名一致,否则需要用AS关键字重命名列。
内容的提问来源于stack exchange,提问作者Junior




