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


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.