#c# #entity-framework #asp.net-core #entity-framework-core
#c# #entity-framework #asp.net-ядро #сущность-структура-ядро
Вопрос:
Каков рекомендуемый способ обновления как книги, так и страниц в этом сценарии «один ко многим» (ядро EF)?
Книга содержит одну или несколько страниц. Каждая страница принадлежит только одной книге, и страницы не существуют сами по себе.
Сущности:
class Book
{
public int Id {get; set;}
public string Title {get; set;}
public string ISBN {get; set;}
public virtual ICollection<Page> Pages {get; set;}
}
class Page
{
public int Id { get; set; }
public int PageNumber { get; set; }
public string Text { get; set; }
public int BookId { get; set; }
public virtual Book Book { get; set; }
}
способ обновления существующей книги:
/// <summary>
/// Save an existing book including pages
/// </summary>
public void SaveExistingBook(Book bookToUpdate)
{
var bookEntity = _databaseContext.Books.Including(b => b.Pages).SingleOrDefault(b => b.Id == bookToUpdate.Id);
... etc....
}
Параметр bookToUpdate содержит все свойства книги и страницы с их свойствами, какими они должны стать.
(Возможно, изменились свойства книги (название, ISBN), а также свойства на страницах (изменения текста).).
Кроме того, страницы могли быть добавлены или удалены.)
Каков правильный способ реализации такого метода?
- Удалить исходную книгу со страницами и вставить новую книгу и страницы?
- Выполните итерацию по всем страницам и удалите / вставьте удаленные / новые страницы и обновите свойства на измененных страницах. Обновите свойства книги.
- Другие предложения?
Спасибо!
Ответ №1:
Перебирать множество записей для обновления не рекомендуется из-за проблем с производительностью, необходимо загрузить объекты, а затем выполнить операцию обновления, что требует времени и производительности.
Лучший подход — использовать стороннюю библиотеку, такую как Entity Framework Plus, она предлагает пакетное обновление и пакетное удаление.
Итак, для вашего случая все, что вам нужно сделать, это создать выражение условного обновления и вызвать метод пакетного обновления:
_databaseContext.Books.Where(b => b.Id == bookToUpdate.Id)
.Update(b => /* your update expression */);
Ответ №2:
Вот мой предпочтительный способ обновления отношения «один ко многим»:
public void SaveExistingBook(Book bookToUpdate)
{
var bookInDb = _databaseContext.Books.Including(b => b.Pages).FirstOrDefault(b => b.Id == bookToUpdate.Id);
if (bookInDb == null) return;
// First update book properties
bookInDb.Name = bookToUpdate.Name;
//...
// Delete all removed pages
var pagesToDelete = (from page in bookInDb.Pages
let item = bookToUpdate.Pages.SingleOrDefault(p => p.Id == page.Id)
where item == null
select page).ToList();
if (pagesToDelete.Any())
foreach (var page in pagesToDelete)
_databaseContext.Entry(page).State = EntityState.Deleted;
// Add all new pages
foreach (var page in bookInDb.Pages.Where(p => p.Id < 1).ToList())
{
page.BookId = bookInDb.Id;
_databaseContext.Pages.Add(page);
}
// Modify existing pages
foreach (var pageToUpdate in bookInDb.Pages.Where(p => p.Id > 0 amp;amp; pagesToDelete.All(pg.Id == p.Id)).ToList())
{
var updatedPage = bookToUpdate.Pages.First(p => p.Id == pageToUpdate.Id);
db.Entry(pageToUpdate).CurrentValues.SetValues(updatedPage);
}
}
Вы также можете использовать DbContext.Update
метод. этот метод приводит к тому, что объект отслеживается контекстом как измененный. Еще раз, контекст не имеет никакого способа определить, какие значения свойств были изменены, и будет генерировать SQL для обновления всех свойств. Где этот метод отличается от явного задания свойства состояния.