如何使用Entity Framework Core 2.1执行SqlQuery?

时间:2018-05-18 00:02:46

标签: entity-framework entity-framework-6 entity-framework-core

在Entity Framework 6中,我可以使用以下命令在数据库上执行原始SQL查询:

IEnumerable<string> Contact.Database.SqlQuery<string>("SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10");

在一个新项目中,我正在尝试使用Entity Framework Core 2.1。我需要执行原始SQL查询。谷歌搜索时,我可以看到扩展程序SqlQuery已更改为FromSql。但是,FromSql仅存在于DbSet<>而不是DbContext.Database

如何在FromSql之外运行DbSet<>?数据库对象FromSql上不存在方法DbContext.Database.FromSql<>

2 个答案:

答案 0 :(得分:15)

  

我可以看到扩展SqlQuery已更改为FromSql

但新的FromSql方法比SqlQuery更具有分解性。该方法的documentation解释了它存在一些限制,如:

  

SQL查询只能用于返回属于的 实体类型   你的模特 。我们积压到enable returning ad-hoc types from raw SQL queries的内容有所增强。

     

SQL查询必须返回 实体或查询类型的所有属性 的数据。

     

[...]

因此,在您的情况下,您使用的SQL查询如下:

SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10

正如文档所述,您只能将FromSql实体或查询类型一起使用。您的SQL查询不会返回模型中定义的实体的所有数据,但它只返回实体的一列。顺便说一句,EF Core 2.1中引入了一项新功能,该功能自2018年7月7日起在Release Candidate中发布。微软称:

  

EF Core 2.1 RC1是一个“go live”版本,这意味着一旦你测试了它   您的应用程序与RC1正常工作,您可以使用它   制作并获得微软的支持,但你仍然应该   一旦可用,就更新到最终的稳定版本。

在查询类型

上使用FromSql

什么是query type

  

EF Core模型现在可以包含查询类型。不像   实体类型,查询类型没有在其上定义的键,也不能   插入,删除或更新(即它们是只读的),但它们   可以通过查询直接返回。一些使用场景   查询类型包括:映射到没有主键的视图,映射到没有主键的表,映射到模型中定义的查询,作为FromSql()查询的返回类型

如果要对SQL文本使用查询类型功能,首先要定义一个类,我们将其命名为MySuperClass

public class MySuperClass
{
    public string Title { get; set; }
}

然后在DbContext类中定义了DbQuery<MySuperClass>类型的属性,如下所示:

public DbQuery<MySuperClass> MySuperQuery { get; set; }

最后,您可以使用FromSql,如下所示:

var result = context.MySuperQuery.FromSql("SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10").ToList().First();
var title = result.Title;

不想使用DbQuery<T>

如果您不想使用DbQuery<T>并且不想定义只包含一个属性的类,那么您可以使用ExecuteSqlCommandAsync,例如@ vivek nuna 在他的回答中做了(他的答案部分正确)。但是您必须知道该方法返回的值是您的查询所影响的行数。此外,您必须将标题作为输出参数,以便将查询作为存储过程。使用ExecuteSqlCommandAsyncExecuteSqlCommand,然后读取调用方法时传递的输出参数。

不创建存储过程而不使用ExecuteSqlCommandAsyncExecuteSqlCommand的更简单方法是使用以下代码:

using (var context = new MyDbContext())
{
    var conn = context.Database.GetDbConnection();
    await conn.OpenAsync();
    var command = conn.CreateCommand();
    const string query = "SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10";
    command.CommandText = query;
    var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        var title = reader.GetString(0);
        // Do whatever you want with title 
    }
}  

您可以使此逻辑成为一个辅助方法,它将接收您的SQL查询并返回所需的数据。但是我建议你使用Dapper.Net whcih包含很多帮助器方法,这些方法有助于像上面那样轻松处理RAW SQL,并与DbContext共享smae连接。

答案 1 :(得分:3)

您可以通过以下方式使用ExecuteSqlCommandAsync RelationalDatabaseFacadeExtensionsMicrosoft.EntityFrameworkCore.Relational类中定义的_databaseContext.Database.ExecuteSqlCommandAsync(<Your parameters>) 方法。

{{1}}