使用 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");
}
}
}
确保安装了以下软件包:
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');
因此,当您在调试时运行 Main 程序并放置一个断路器时,您会注意到没有任何对象返回在检查过程中由该过程更新的值。在调试过程中,如果您在表上运行 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
请注意最后一个项目符号。他们所做的基本上是所谓的客户端获胜策略的实现(与您正在寻找的数据库获胜相反),目前除了使用无跟踪查询之外没有其他方法可以改变它。
在您的示例中,插入
AsNotTracking()
在查询中的某个地方(在 ToList
之前,在 dbContext.TestTables
之后 - 这真的无关紧要,因为它适用于整个查询),或者只是dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
现在您将看到更新的值(从您的 SP 调用或从其他 session 到同一数据库)。
关于sql-server - EF Core 存储过程 FromSqlRaw 不提供更新值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60101625/