首选的场景是更新一对多(one和Manies都应该更新)



在这种一对多场景(EF Core(中,建议使用什么方法来更新Book和Pages?

一本书包含一页或多页。每一页都只属于一本书,并且不存在单独的页面。

实体:

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. 删除带页面的原书并插入一本新书和页面
  2. 遍历所有页面,删除/插入已删除/新建的页面,并更新已更改页面的属性。更新书本的属性
  3. 其他建议

谢谢!

由于性能问题,不建议遍历多个记录进行更新,需要加载实体然后执行更新操作,这是一个耗时且耗性能的过程。

最好的方法是使用第三方库,如EntityFrameworkPlus,它提供批量更新和批量删除。

因此,对于您的情况,您所要做的就是创建条件更新表达式并调用批更新方法:

_databaseContext.Books.Where(b => b.Id == bookToUpdate.Id)
.Update(b => /* your update expression */);

以下是我最喜欢的更新一对多关系的方法:

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 && 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方法。此方法导致上下文将实体跟踪为Modified。同样,上下文无法识别哪些属性值已更改,并且将生成SQL来更新所有属性。如果此方法与显式设置State属性不同。

最新更新