我正在从许多不同的来源(例如XML和Web服务)中检索有关书籍的数据,然后我使用EF Code First 6通过Generic Repository存储在数据库中,显然是DbContext。
问题在于表现非常差。
我的模型中有以下(虚构但类似的)POCO
public class Book
{
public int Id {get; set;}
public string Title {get; set;}
}
也
public class BookDataSource
{
public int Id {get; set;}
public virtual List<Book> Books {get; set;};
}
所以我从一些来源检索书籍数据并构建上面的书籍对象。
然后,我需要检查数据库中是否已存在该数据库,如果存在则更新它,如果不存在则更新它。我还需要删除数据源上不再存在的任何书籍。
//以下方法将数据源(类型:IBookDataSource)作为参数进行更新
public string UpdateBooks(BookDatasource dataSource)
{
string successMessage = "";
//Disconnected entities
List<Book> retreivedBooks= dataSource.RetreiveBooks();
foreach (Book retreivedBook in retreivedBooks)
{
//Check if the dataSource already contains a book (based on title)
Book localBook =
dataSource.Books.SingleOrDefault(
b => b.Title== retreivedBook.Title);
if (localBook ==null)
{
//Insert a new one
_unitOfWork.BookRepository.Insert(retreivedBook);
}
else
{
//Update existing
localBook.Title= retreivedPortalMerchant.PortalsMerchantName;
_unitOfWork.PortalMerchantRepository.Update(localPortalMerchant);
}
}
//Soft delete any existing ones that no longer exist in the received data
foreach (Book existingBook in dataSource.Books)
{
if ( !retreivedBooks.Exists(
b => m.Title == existingBook.Title))
{
existingBook.Deleted = true;
_unitOfWork.PortalMerchantRepository.Update(existingBook);
}
}
}
然而表现非常糟糕。有时从数据源中检索到25000本书,我不得不做两个for循环。 ForEach retreived book,检查db中是否存在相应的插入/更新。另一个循环所有现有书籍并检查它是否已不再存在于数据源和软删除中。
是否有更好的方法来附加实体并监控其状态。在上面的例子中,我认为我每次都在查询上下文而不是数据库,所以为什么这么糟糕的表现。我应该恢复到T-SQL吗?
答案 0 :(得分:1)
对于插入 - 更新 - 删除断开连接的实体的正确算法,您可以检查“第4章中的设置图形中的实体状态”部分。使用包括已断开连接的实体N-Tier Applications “of”编程实体框架:DbContext by Julia Lerman,Rowan Miller “book。
同样在this SO answer中解释了提高EF性能的一些方法。答案是批量插入,但它也适用于你的场景。
答案 1 :(得分:1)
最快的方法是使用bulk insert extension
此处maxlego&#39; s description:
它使用SqlBulkCopy和自定义datareader来获得最大性能。因此,它比使用常规插入或AddRange EntityFramework.BulkInsert与EF AddRange
快20多倍context.BulkInsert(hugeAmountOfEntities);