EF Core 存储过程 FromSqlRaw 不提供更新值

Pau*_*ton 8 sql-server stored-procedures entity-framework-core ef-core-3.1

当使用FromSqlRaw更新表中的值在EF Core 3 上运行过程时,当我查询数据库中的那些更改的值时,EF不会返回更新的值。

我已经能够重现这种行为。要使用 .net core 3.1 重现创建一个新的控制台应用程序 c#。

将下面的代码复制粘贴到您的主 Program.cs 文件中:

using System;
using System.Linq;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;

namespace EfCoreTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            // testing proc
            var dbContext = new TestContext();
            var tables = dbContext.TestTables.ToList();
            var updated = dbContext.TestTables
                .FromSqlRaw("execute testProc @Id=@Id, @Comments=@Comments", new object[]
                {
                    new SqlParameter("Id", 1),
                    new SqlParameter("Comments", "testing comments 2"),
                })
                .ToList();
            var again = dbContext.TestTables.ToList();
        }
    }


    public class TestTable
    {
        public int TestTableId { get; set; }

        public string Comment { get; set; }
    }

    public class TestContext : DbContext
    {
        public DbSet<TestTable> TestTables { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Server=localhost\SQLEXPRESS;Database=TestDb;Trusted_Connection=True");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

确保安装了以下软件包:

Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.SqlServer.Design
Run Code Online (Sandbox Code Playgroud)

如有必要,更改连接字符串。

跑 dotnet ef migrations add initial

跑 dotnet ef database update

在您的数据库中运行以下代码:

Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.SqlServer.Design
Run Code Online (Sandbox Code Playgroud)

因此,当您在调试时运行 Main 程序并放置一个断路器时,您会注意到在检查过程中没有任何对象返回由该过程更新的值。在调试过程中,如果您在表上运行 select 语句,您将看到“Comment”字段确实已更新。

为什么是这样?

Iva*_*oev 6

这不是特定于FromSql,而是 EF Core(所有版本)跟踪查询的工作方式。

以下是 EF Core How Queries Work文档主题的摘录:

以下是每个查询所经历的过程的高级概述。

  1. LINQ 查询由 Entity Framework Core 处理以构建准备由数据库提供程序处理的表示
    • 结果被缓存,这样就不需要每次执行查询时都做这个处理
  2. 结果传递给数据库提供者
    • 数据库提供者标识可以在数据库中评估查询的哪些部分
    • 查询的这些部分被转换为特定于数据库的查询语言(例如,关系数据库的 SQL)
    • 一个或多个查询被发送到数据库并返回结果集(结果是来自数据库的值,而不是实体实例)
  3. 对于结果集中的每个项目
    • 如果这是一个跟踪查询,EF 检查数据是否表示上下文实例的更改跟踪器中已有的实体如果是,则返回现有实体如果不是,则创建一个新实体,设置更改跟踪,并创建新实体被退回

请注意最后一个项目符号。他们所做的基本上是所谓的客户端获胜策略的实现(与您正在寻找的数据库获胜相反),目前除了使用无跟踪查询之外没有其他方法可以改变它。

在您的示例中,AsNotTracking()在查询中的某处插入(之前ToList,之后dbContext.TestTables- 这真的无关紧要,因为它适用于整个查询),或者只是

dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
Run Code Online (Sandbox Code Playgroud)

现在您将看到更新的值(从您的 SP 调用或从其他会话到同一数据库)。