Як оновити запис за допомогою сутності фреймворка сутності?


88

Який найкращий підхід до оновлення даних таблиці бази даних у робочому ядрі сутності сутності?

  1. Отримайте рядок таблиці, внесіть зміни та збережіть
  2. Використовуйте оновлення ключового слова в контексті db та обробляйте винятки для елемента, що не існує

Які покращені функції ми можемо використовувати над EF6?

Відповіді:


104

Щоб оновити сутність за допомогою Entity Framework Core, це логічний процес:

  1. Створити екземпляр для DbContextкласу
  2. Отримати сутність за ключем
  3. Внесіть зміни у властивості сутності
  4. Зберегти зміни

Update()метод у DbContext:

Починає відстежувати дану сутність у зміненому стані таким чином, що вона буде оновлюватися в базі даних при SaveChanges()виклику.

Метод оновлення не зберігає зміни в базі даних; натомість він встановлює стани для записів у екземплярі DbContext.

Отже, ми можемо викликати Update()метод раніше, щоб зберегти зміни в базі даних.

Я прийму деякі визначення об’єктів, щоб відповісти на ваше запитання:

  1. Назва бази даних - Store

  2. Назва таблиці - Product

Визначення класу товару:

Визначення класу DbContext:

Логіка для оновлення сутності:


1
Дякую . Це хороший приклад того, як використовувати 2. Використовуйте оновлення ключових слів у контексті db та обробляйте винятки для елемента, що не існує. Мені більше цікаво вибрати, який із них використовувати як найкращу практику.
— Charith

Чому ви використовували int?для nullable ProductID? Це стає додатковим первинним ключем?
— Штучна дурість

8
Насправді рядок context.Products.Update є зайвим, оскільки сутність буде відстежуватися, як тільки ви отримаєте її з контексту. Ось чудовий огляд різних підходів: Learnentityframeworkcore.com/dbcontext/modifying-data
— Йохан Маес,

67

Згідно з документами Microsoft :

підхід read-first вимагає додаткового зчитування з бази даних і може призвести до складнішого коду для обробки конфлікту паралельності

Однак ви повинні знати, що використання методу оновлення на DbContext позначить усі поля як змінені та включить усі їх у запит. Якщо ви хочете оновити підмножину полів, вам слід скористатися методом Вкласти, а потім позначити потрібне поле як змінене вручну.


31
Просто невеликий випуск, тепер існує більш набрана версія цього API: context.Entry(person).Property(p => p.Name).IsModified = true;
— Guru Stron

2
Також можна просто зробитиcontext.Entry(person).State = EntityState.Modified;
— Ренан Коельо

1
Що означає цей контекст.Entry (person) .State = EntityState.Modified; маю на увазі? Якщо я модифікую кілька полів, чи слід вносити зміни до цього рядка?
— user989988

2
Хороший момент, ехан ян! ; D Крім того, якщо сутність оновлюється користувачем, і ви не знаєте / турбуєтесь, чи змінюються поля, ви можете використовувати, _context.Attach(person).State = EntityState.Modified; щоб вказати, що ця сутність має бути оновлена ​​за методом SaveChanges.
— S.Serpooshan

Чудовий улов. Отже, для цього потрібно, щоб контекст «тримався», тому він знав про сутності в контексті. Я щойно перевірив це .. і якщо ви спробуєте відредагувати неіснуюче, це дає виняток! :) Виникла одна або кілька помилок. (Спроба оновити або видалити сутність, яка не існує в магазині.)
— granadaCoder

31
public async Task<bool> Update(MyObject item)
{
    Context.Entry(await Context.MyDbSet.FirstOrDefaultAsync(x => x.Id == item.Id)).CurrentValues.SetValues(item);
    return (await Context.SaveChangesAsync()) > 0;
}

Я думаю, що цей метод працює дуже добре, але я вважаю, що публікація знаходиться внизу, оскільки вона могла б використовувати більше контексту. але сподобалось!
— Містер Краус,

1
Мені це теж подобається! @Містер. Краузе чи не буде посада низькою (поки що) через те, що їй лише кілька днів?
— джерело джерела

1
Я отримую "Порушення обмеження ОСНОВНОГО КЛЮЧУ" PK_Offer ". Неможливо вставити дублікат ключа в об'єкт" dbo.Offer "." З цього.
— Магнус Карлссон

8

Microsoft Docs пропонує два підходи.

Рекомендований код редагування HttpPost: Прочитайте та оновіть

Це той самий старий спосіб, який ми робили у попередніх версіях Entity Framework. і це те, що рекомендує нам Microsoft.

Переваги

  • Запобігає пересиленню
  • Автоматичне відстеження змін EF встановлює Modified прапор на поля, які змінюються введенням форми.

Альтернатива код редагування HttpPost: Створіть та вкладіть

альтернативою є приєднання сутності, створеної в’язкою моделі, до контексту EF та позначення її як модифікованої.

Як згадувалося в іншій відповіді, підхід читання спочатку вимагає додаткового зчитування бази даних і може призвести до складнішого коду для обробки конфліктів паралельності.



2

Переглянувши всі відповіді, я думав, що додам два простих варіанти

  1. Якщо ви вже отримували доступ до запису за допомогою FirstOrDefault () з увімкненим відстеженням (без використання функції .AsNoTracking (), оскільки це відключить відстеження) і оновили деякі поля, тоді ви можете просто викликати context.SaveChanges ()

  2. В іншому випадку або ви маєте сутність, опубліковану на сервері за допомогою HtppPost, або ви відключили відстеження з якоїсь причини, тоді вам слід викликати context.Update (entityName) перед context.SaveChanges ()

1-й варіант оновить лише поля, які ви змінили, але 2-й варіант оновить усі поля бази даних, хоча жодне значення полів фактично не оновлено :)


0

Більш загальний підхід

Для спрощення цього підходу використовується інтерфейс "id"

public interface IGuidKey
{
    Guid Id { get; set; }
}

Допоміжний метод

    public static void Modify<T>(this DbSet<T> set, Guid id, Action<T> func)
        where T : class, IGuidKey, new()
    {
        var target = new T
        {
            Id = id
        };
        var entry = set.Attach(target);
        func(target);
        foreach (var property in entry.Properties)
        {
            var original = property.OriginalValue;
            var current = property.CurrentValue;

            if (ReferenceEquals(original, current))
            {
                continue;
            }

            if (original == null)
            {
                property.IsModified = true;
                continue;
            }

            var propertyIsModified = !original.Equals(current);
            property.IsModified = propertyIsModified;
        }
    }

Використання

dbContext.Operations.Modify(id, x => { x.Title = "aaa"; });
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.