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.
- 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
- 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)
- 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 调用或从其他会话到同一数据库)。
当运行在 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.
- 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
- 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)
- 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 调用或从其他会话到同一数据库)。