为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 EF Core 执行 RAW SQL 查询?

如何使用 EF Core 执行 RAW SQL 查询?

C#
12345678_0001 2022-12-24 12:12:04
基本上我遇到的问题是我想在数据库中运行一个查询,它不是我的模型的表示。这是我创建与另一个数据库的连接的代码:public static OtherContext GetNewContextGeneric(string connectionString)        {            var builder = new DbContextOptionsBuilder();            builder.UseSqlServer(connectionString);            OtherContext db = new OtherContext(builder.Options);            return db;        }这是我执行查询的代码:public List<IQueryble> Query (string connectionString, string query)        {            try            {                using(var contextGeneric = ContextFactory.GetNewContextGeneric(connectionString))                {                    //I want something like this                    return contextGeneric.Query(query).ToList();                }            }            catch(System.Data.SqlClient.SqlException ex)            {                throw new SQLIncorrectException(ex);            }            catch(System.InvalidOperationException ex)            {                throw new NotImplementedException();            }           }有人可以帮我吗?
查看完整描述

5 回答

?
繁星淼淼

TA贡献1775条经验 获得超11个赞

您可以使用DbDataReader:


using (var command = context.Database.GetDbConnection().CreateCommand())

{

    command.CommandText = "SELECT * From Make";

    context.Database.OpenConnection();

    using (var reader = command.ExecuteReader())

    {

        // Do something with result

        reader.Read(); // Read first row

        var firstColumnObject = reader.GetValue(0);

        var secondColumnObject = reader.GetValue(1);


        reader.Read(); // Read second row

        firstColumnObject = reader.GetValue(0);

        secondColumnObject = reader.GetValue(1);

    }

}

在这里您可以了解更多如何从DbDataReader.

或者,您可以使用FromSql()方法,但这仅适用于DbSet某些实体的预定义,这不是您想要的解决方案。


查看完整回答
反对 回复 2022-12-24
?
catspeake

TA贡献1111条经验 获得超0个赞

在你说的问题中:

基本上我遇到的问题是我想在数据库中运行一个查询,它不是我的模型的表示。

然后在评论中添加:

因为我不知道数据库是如何创建的,所以我不知道数据库中有哪些表我想插入sql查询

好吧,如果您不知道数据库,那么您就不能使用 Entity Framework,因为它要求您对要连接的数据库有详细的了解。
为此,您应该使用普通的 ADO.NET(如果您想将结果映射回已知类,则可以使用Dapper )。


查看完整回答
反对 回复 2022-12-24
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

您仍然可以使用 EF Core 实现外部数据库的用例,无需求助于 ADO.Net,此解决方案基于@ErikEj 的 EF Core 通用解决方案。(请注意,EF Core 3 的一些函数和命名空间发生了变化,因此保留在 .Net 5+ 中,但仍然可以应用相同的通用概念)


public static IList<T> Query<T>(string connectionString, string query, params object[] parameters) where T : class

{

    try

    {

        using (var contextGeneric = new ContextForQuery<T>(connectionString))

        {

            return contextGeneric.Query<T>().FromSql(query, parameters).ToList();

        }

    }

    catch (System.Data.SqlClient.SqlException ex)

    {

        throw new SQLIncorrectException(ex);

    }

    catch (System.InvalidOperationException ex)

    {

        throw new NotImplementedException();

    }

}


private class ContextForQuery<T> : DbContext where T : class

{

    private readonly string connectionString;


    public ContextForQuery(string connectionString)

    {

        this.connectionString = connectionString;

    }


    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

    {

        optionsBuilder.UseSqlServer(connectionString, options => options.EnableRetryOnFailure());


        base.OnConfiguring(optionsBuilder);

    }


    protected override void OnModelCreating(ModelBuilder modelBuilder)

    {

        modelBuilder.Entity<T>().HasNoKey();

        base.OnModelCreating(modelBuilder);

    }

}

那么 this 的使用需要一个具体的类型定义,添加对匿名类型的支持需要付出更多的努力,但是为此创建一个具体的类型并不是一件坏事,这里的重点是让你尝试更多的声明式代码风格因为它们增强了代码的可读性和检查性,并提供文档和其他扩展配置,如相关实体。


public class NamedObject

{

    public int Id { get; set; }

    public string Name { get; set; }

}


...


var connectionString = "Insert your connection string here...";

var data = Query<NamedObject>(connectionString, "SELECT TOP 10 Id, FullName as Name FROM Employee");

foreach (var emp in data)

{

    Console.WriteLine(emp.Name);

}

背景

在 EF 6(.Net Framework)中,我们可以DbContext.Database.FromSQL<T>()用来执行将自动映射到指定类型的T. 此功能未在 EF Core 中复制,因为结果FromSQL与 EF 的其余部分不一致,结果是一次使用IEnumerable<T>。您无法进一步将此查询组合到Include()相关实体,也无法向基础查询添加过滤器。

在 EF Core to Execute Raw SQL中,您想要返回的类型T需要在 DbContext 中定义为DbSet<T>. 这个集合根本不需要映射到数据库中的表,事实上,自从 EF Core 2.1 我们不需要为此类型指定,它只是一种预定义预期结构而不是执行的机制按需临时请求,它为您提供与旧版相同的功能,FromSQL但还允许您定义一组丰富的导航属性,以便在使用 LINQ to SQL 管道插入RawSQL后进一步组合查询。

一旦在上下文中定义了类型,您只需调用DbSet<T>.FromSqlRaw(). 不同之处在于,现在我们有一个IQueryable<T>可以用来进一步组合以包含相关实体或应用将在数据库中评估的过滤器。

此响应中发布的解决方案不允许组合,但按预期顺序使用 EF 运行时来提供与原始 EF 6 实现相同的行为。

在最新版本的 EF Core 中,以及现在在 .Net 5+ 中,需要应用以下细微变化:

  • 核心2.1:return contextGeneric.Query<T>().FromSql(query, parameters).ToList();

  • 核心 3+:return contextGeneric.Set<T>().FromSqlRaw(query, parameters).ToList();


查看完整回答
反对 回复 2022-12-24
?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

您可以使用context.Database.ExecuteSqlRaw("select 1")

不要忘记导入正确的命名空间:using Microsoft.EntityFrameworkCore;


查看完整回答
反对 回复 2022-12-24
?
噜噜哒

TA贡献1784条经验 获得超7个赞

它是这样工作的:


private void SqlCommand (string connectionString, string query)

        {

            using (SqlConnection connection = new SqlConnection(connectionString))

            {

                SqlCommand command = new SqlCommand(query, connection);

                connection.Open();

                SqlDataReader reader = command.ExecuteReader();

                try

                {

                    while (reader.Read())

                    {

                        var a = reader[0];

                    }

                }

                finally

                {

                    // Always call Close when done reading.

                    reader.Close();

                }

            }

        }

要么


using (var connection = ContextFactory.GetNewContextGeneric(connectionString).Database.GetDbConnection())

                {

                    connection.Open();

                    DbCommand command = connection.CreateCommand();

                    command.CommandText = query;


                    using (var reader = command.ExecuteReader())

                    {

                        // Do something with result

                        reader.Read(); // Read first row

                        var firstColumnObject = reader.GetValue(0);

                        /*var secondColumnObject = reader.GetValue(1);


                        reader.Read(); // Read second row

                        firstColumnObject = reader.GetValue(0);

                        secondColumnObject = reader.GetValue(1);*/

                        connection.Close();

                        return firstColumnObject.ToString();

                    }

                }


查看完整回答
反对 回复 2022-12-24
  • 5 回答
  • 0 关注
  • 161 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信