@trauus

Почему EntityFramework пожирает память на множестве простых запросов?

Осваиваю EntityFramework 6.2 в связке с SQLite в десктопном приложении на .NET 4.

При первом запуске необходимо загрузить с сервера список из 20 000 продуктов и записать их в локальную БД, проверив на уникальность по одному из полей.

При отладке приложение стало падать с OutOfMemoryException, оказалось, что обработка каждых 700 элементов отъедает ~100 МБ памяти. Приложение 32-битное, поэтому память кончается до того, как все элементы обработаются.

В процессе отладки пришел к минимальному куску кода, который воспроизводит ситуацию.

Почему выполнение нескольких сотен запросов db.Products.Where(pr => pr.SomeUniqueId == p.SomeUniqueId).FirstOrDefault(); даже на пустой таблице так съедает память?

И что с этим делать?

[TestMethod]
public void MemoryUseTest()
{
	using (DbContext db = DbContextFactory.Create())
	{
		db.Configuration.AutoDetectChangesEnabled = false;
		db.Configuration.LazyLoadingEnabled = false;
		db.Configuration.ProxyCreationEnabled = false;
	
		var products = CreateRandomProducts(2000);		

		foreach (var p in products)
		{
			Product existing = db.Products.Where(pr => pr.SomeUniqueId == p.SomeUniqueId).FirstOrDefault();
		}
	}	
}

public class Product
{
	public int Id { get; set; }

	public String UniqueId { get; set; }
	public String FullName { get; set; }
	public decimal Capacity { get; set; }
}

private List<Product> CreateRandomProducts(int count)
{
	List<Product> prods = new List<Product>();

	for (int i = 0; i < count; i++)
	{
		Product p = new Product();

		p.Code = Guid.NewGuid().ToString();
		p.UniqueId = Guid.NewGuid().ToString();
		p.FullName = Guid.NewGuid().ToString();
		p.Capacity = 11.0m;

		prods.Add(p);
	}
	return prods;
}
  • Вопрос задан
  • 35 просмотров
Пригласить эксперта
Ответы на вопрос 1
@CHolfield
ты извращенец, в цикле по одному выбирать записи когда готовый список есть.
вместо
foreach (var p in products)
    {
      Product existing = db.Products.Where(pr => pr.SomeUniqueId == p.SomeUniqueId).FirstOrDefault();
    }


надо делать
var listOfSomeUniqueId = products.Select(a => a.SomeUniqueId);
var listOfExisting = db.Products.Where(b => listOfSomeUniqueId.Contains(b.RoleId));


и далее обходим готовый список существующих в БД записей
foreach (var p in listOfExisting)
    {
      p.SomeProperty1 = "HuiPizdaDzhigurda";
      p.SomeProperty2 = 123;
    }

и в конце концов
db.SaveChanges();

сравни скорость с твоими извратами.

кстати чуть не забыл ответить на твои вопросы:
1. потому что каждый раз поднимается в память вся таблица db.Products и в ней ищется одна запись, сборщик мусора не успевает очистить память, а ты сам не озаботился этим вопросом.
2. Думать головой.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы