EF Core Update обновляет все столбцы, даже если изменился только один - PullRequest
2 голосов
/ 28 марта 2020

Я новичок в использовании EF Core. Насколько я понимаю, в EF Core есть «Отслеживание изменений», которое просматривает данные, чтобы увидеть, какие столбцы были изменены, и создает оператор SQL UPDATE, который обновляет только измененные столбцы, как описано в ответе здесь:

Сравнивает ли ядро ​​EF значение для включения столбцов в оператор обновления?

Однако это не то, что я вижу. Например, у меня есть эта сущность:

public class Book
{
    public int BookId { get; set; }
    [StringLength(255)]
    public string Title { get; set; }
    public int AuthorId { get; set; }
    public Author Author { get; set; }
    [StringLength(500)]
    public string Description { get; set; }
}

Затем я обновляю существующую строку следующим кодом:

class Program
{
    static void Main(string[] args)
    {
        var context = new TestContext();
        var book = context.Books.Find(1);
        book.Title += " x";
        context.Books.Update(book);
        context.SaveChanges();
    }
}

Я запустил SQL Profiler и запустил этот код. Я ожидал увидеть инструкцию UPDATE, которая обновляла только столбец «Заголовок», но он всегда обновлял каждый столбец:

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0, [Description] = @p1, [Title] = @p2
WHERE [BookId] = @p3;
SELECT @@ROWCOUNT;
',N'@p3 int,@p0 int,@p1 nvarchar(500),@p2 nvarchar(255)',@p3=1,@p0=1,@p1=N'',@p2=N'Some Title x'

Например, описание столбца не изменилось, хотя оно находится в операторе UPDATE, как AuthorId.

Почему это? Разве это не просто заголовок в предложении SET?

Ответы [ 2 ]

2 голосов
/ 29 марта 2020

Насколько я понимаю, в EF Core есть «Отслеживание изменений»

Это правильно, и поэтому, когда сущности присоединяются к контексту, вы освобождаетесь от пометки их как обновлено. После строки ...

book.Title += " x";

... EF обнаруживает это изменение и помечает метки Title как измененные. Нет необходимости вызывать метод Update.

Это так называемый сценарий "подключен".

Метод Update предназначен для сценария отключен . Это когда объектный объект не привязан к контексту, но его значения должны быть сохранены в базе данных, например, в бэкэнде веб-API. В его базовой c форме:

public void SaveBook(Book book)
{
    // Here, 'book' is the book with the changed Title.
    using(var context = new TestContext())
    {
        context.Books.Update(book);
        context.SaveChanges();
    }
}

Теперь EF не может обнаружить изменение, потому что book уже изменено, когда входит в метод. Вы должны сказать EF, что книга должна быть обновлена. Но EF не знает, что было изменено; лучшее, что он может сделать - пометить все свойства (кроме первичного ключа) как измененные.

Тем не менее, EF по-прежнему может обновлять только те свойства, которые фактически обновлены, путем преобразования отключенного сценария в подключенный:

public void SaveBook(Book book)
{
    // Here, 'book' is the book with the changed Title.
    using(var context = new TestContext())
    {
        var dbBook = context.Books.Find(book.ID);

        // Copy book's property values to dbBook.
        context.Entry(dbBook).CurrentValues.SetValues(book);

        context.SaveChanges();
    }
}

Могут быть веские причины , чтобы предпочесть второй метод выше первого.

1 голос
/ 29 марта 2020

В подключенном сценарии вам не нужно вызывать метод Update.

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