首页 > 解决方案 > 如何使用需要返回行的 EF Core 执行原始 sql 插入查询?

问题描述

我使用 EF Core for PostgreSQL,如此所述。我想执行一些返回行的原始 sql 查询。

最简单的是这个(它可能看起来很奇怪,因为它返回的正是插入的内容,但它很简单,可以用作示例):

INSERT INTO public."TodoItems" ("Id", "Todo") VALUES ('915714b6-1c67-444d-8106-d778fcb4bb1a', 'Hi') RETURNING "Id", "Todo"

这是我的上下文类:

public class DoContext : DbContext
{
    public DoContext(DbContextOptions<DoContext> options) : base(options)
    {
        Console.WriteLine("Context created");
    }

    public DbSet<TodoItem> TodoItems { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        Console.WriteLine("OnModelCreating");
    }
}

这是实体类。

public class TodoItem
{
    public Guid Id { get; set; }

    public string Todo { get; set; }
}

这是我执行查询的代码:

string query = "INSERT INTO public.\"TodoItems\" (\"Id\", \"Todo\") VALUES ('915714b6-1c67-444d-8106-d778fcb4bb1a', 'Hi') RETURNING \"Id\", \"Todo\"";
var result = context.TodoItems.FromSqlRaw(query).First();

我的查询很好。它在表为空并且查询在 DataGrip 中执行时工作。但是,在运行我的代码时,最后一行会导致以下异常:

Npgsql.PostgresException 42601:“INTO”处或附近的语法错误

我从文档中了解到,FromSqlRaw 是预期返回行时使用的正确方法。但是,此方法似乎无法理解我的(经过测试且有效的)查询。

那么如何使用 EF 核心执行这个查询呢?这里重要的是我真的要使用 EF Core,因为我需要 sql 世界和我拥有的实体之间的映射。我使用.NET 5。

标签: postgresqlentity-framework-core

解决方案


避免使用类似First和类似的查询限制运算符,因为 EF Core 将尝试组合提供的 SQL - 基本上将其包装在外部SELECT(SELECT * FROM (Your_SQL)为了应用TOP N或类似的运算符。这会导致无效的 SQL 语法。

所以它可能看起来很奇怪,但是使用物化运算符代替 - ToList()ToArray()或者AsEnumerable()在此时停止IQueryable处理并执行数据库查询,例如

var result = context.TodoItems.FromSqlRaw(query)
    .AsEnumerable() // <-- database query ends here
    .First(); // <-- this runs in LINQ to Objects context

推荐阅读