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

EF Core Stored Procedure FromSqlRaw Does Not Give Updated Values

当运行在 EF Core 3 上使用 FromSqlRaw 更新 table 中的值时,EF 不会 return 当我在数据库中查询这些更改值时更新的值。

我已经能够重现此行为。要使用 .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");
        }
    }
}

确保安装了以下软件包:

Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.SqlServer.Design

必要时更改连接字符串。

运行 dotnet ef migrations add initial

运行 dotnet ef database update

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

drop procedure if exists testProc
go
create procedure testProc
@Id int,
@Comments nvarchar(max)
as
begin
    update dbo.TestTables
    set Comment = @Comments
    where TestTableId = @Id;

    select * from dbo.TestTables;
end

go


INSERT INTO [dbo].[TestTables]
(Comment) VALUES ('Test Comment');

因此,当您 运行 调试主程序并设置断路器时,您会注意到 NONE 的对象 return 值在 go 时由过程更新检查它。在调试时,如果您 运行 在 table 上执行 select 语句,您将看到 "Comment" 字段确实已更新。

这是为什么?

这并非特定于 FromSql,而是 EF Core(所有版本)tracking queries 的工作方式。

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

The following is a high level overview of the process each query goes through.

  1. The LINQ query is processed by Entity Framework Core to build a representation that is ready to be processed by the database provider
    • The result is cached so that this processing does not need to be done every time the query is executed
  2. The result is passed to the database provider
    • The database provider identifies which parts of the query can be evaluated in the database
    • These parts of the query are translated to database specific query language (for example, SQL for a relational database)
    • One or more queries are sent to the database and the result set returned (results are values from the database, not entity instances)
  3. For each item in the result set
    • If this is a tracking query, EF checks if the data represents an entity already in the change tracker for the context instance If so, the existing entity is returned If not, a new entity is created, change tracking is setup, and the new entity is returned

注意最后一个项目符号。他们所做的基本上是实施所谓的 client wins 策略(与您正在寻找的 database wins 相反),目前有除了使用 no-tracking query.

之外没有办法改变它

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

dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

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