Хранимая процедура EF Core FromSqlRaw не дает обновленных значений - PullRequest
2 голосов
/ 06 февраля 2020

При выполнении процедуры в EF Core 3 с использованием FromSqlRaw, которая обновляет значения в таблице, EF НЕ возвращает обновленные значения, когда я запрашиваю базу данных об этих измененных значениях.

Я был в состоянии воспроизвести это поведение. Для воспроизведения создайте новое консольное приложение c# с. net core 3.1.

Скопируйте и вставьте приведенный ниже код в ваш основной файл 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 на отладке и включите прерыватель, вы заметите, что ни один из объектов не возвращает значения, которые были обновлены процедурой при проверке go Это. Находясь в режиме отладки, если вы выполните оператор select для таблицы, вы увидите, что поле «Комментарий» действительно обновлено.

Почему это так?

1 Ответ

1 голос
/ 06 февраля 2020

Это не спецификация c до FromSql, а способ EF Core (все версии) отслеживание запросов .

Вот выдержка из EF Core Как работают запросы документация topi c:

Ниже приводится общий обзор процесса, который проходит каждый запрос.

  1. Запрос LINQ обрабатывается Entity Framework Core для построения представления, которое готово для обработки поставщиком базы данных
    • Результат кэшируется, поэтому эту обработку не нужно выполнять каждый раз, когда выполняется запрос
  2. Результат передается поставщику базы данных
    • Поставщик базы данных определяет, какие части запроса могут быть оценены в базе данных
    • Эти части запроса транслируются в базу данных. Speci c язык запросов (например, SQL для реляционной базы данных)
    • Один или несколько запросов отправляются в базу данных и возвращается набор результатов (результаты являются значениями из базы данных, а не экземпляров сущностей)
  3. Для каждого элемента в наборе результатов
    • Если это запрос отслеживания, EF проверяет, представляют ли данные сущность, уже находящуюся в средство отслеживания изменений для экземпляра контекста. Если это так, возвращается существующий объект. Если нет, создается новый объект, настраивается отслеживание изменений и возвращается новый объект

Обратите внимание на последнюю пулю. В основном они реализуют так называемую стратегию клиент выигрывает (в отличие от выигрыш базы данных , который вы ищете), и в настоящее время нет способа изменить это, кроме используя no-tracking запрос.

В вашем примере вставьте AsNotTracking() где-то в запросах (до ToList, после dbContext.TestTables - это действительно не имеет значения, потому что применяется на весь запрос) или просто

dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

, и теперь вы увидите обновленные значения (из вашего вызова SP или из других сеансов в той же базе данных).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...