Я стараюсь избегать вызова SaveChanges внутри цикла и вызывать его только один раз, когда цикл завершается.
Похоже, что в этом случае мне приходится вызывать SaveChanges на каждой итерации, вот небольшой пример.
У меня есть два объекта:
public class OrderRow
{
public int Id { get; set; }
public string PartNumber {get; set; }
public List Rows { get; set; }
}
public class ShipmentRow
{
public int Id { get; set; }
public string PartNumber {get; set; }
public int? OrderRowId { get; set; }
public OrderRow? OrderRow { get; set; }
}
Теперь мне нужно сопоставить одну или несколько строк таблицы отгрузки с одной строкой заказа, скажем, это данные внутри двух таблиц:
Таблица OrderRows
Идентификатор
Номер детали
111
A789
222< /td>
A789
< /div>
Таблица строк поставок
Идентификатор
Номер детали
OrderRowId
333
A789
null
В цикле я сопоставляю одну строку с другой (очень упрощенный пример):
foreach(var item in dbContext.OrderRow.ToList())
{
List sRows = dbContext.ShipmentRow
.Where(x=> x.PartNumber == item.PartNumber
&& x.OrderRowId == null)
.ToList();
foreach(var s in sRows)
{
item.Rows.Add(s)
}
dbContext.SaveChanges();
}
Теперь я хочу переместить SaveChanges() за пределы цикла и сохранить все сразу, но проблема в том, что если я удалю SaveChanges() из цикла на второй итерации, sRows будет содержать уже сопоставленные данные.
На первой итерации строка отгрузки с идентификатором 333 сопоставляется со строкой заказа с идентификатором 111, на второй итерации строка отгрузки 333 сопоставляется с заказом 222, даже если это никогда не следует извлекать из БД, поскольку он уже связан, но внешний ключ не добавляется до вызова SaveChanges.
Я пробовал добавить его вручную, но вызов базы данных sRow все равно видит OrderRowId как нулевой .
Мне нужно переместить SaveChanges наружу, потому что это слишком сильно замедляет работу.
Я думал, что EF достаточно умен, чтобы обнаружить это изменение... но возможно, я делаю что-то не так.
Возможное решение: проверьте, связана ли уже строка отгрузки, полученная из БД, с заказами:List orders = dbContext.OrderRow.ToList();
foreach(var item in orders)
{
List sRows = dbContext.ShipmentRow
.Where(x=> x.PartNumber == item.PartNumber
&& x.OrderRowId == null)
.ToList();
foreach(var s in sRows)
{
if(orders.SelectMany(x => x.Rows).Any(x => x.Id == s.Id))
continue;
item.Rows.Add(s)
}
}
dbContext.SaveChanges();
Вот решение ChatGPT: получить все и работать в оперативной памяти, может привести к большому использованию памяти при увеличении размера БД
var orderRows = dbContext.OrderRow.ToList();
var shipmentRows = dbContext.ShipmentRow.Where(x => x.OrderRowId == null).ToList();
foreach (var orderRow in orderRows)
{
var matchingShipmentRows = shipmentRows
.Where(x => x.PartNumber == orderRow.PartNumber && x.OrderRowId == null)
.ToList();
foreach (var shipmentRow in matchingShipmentRows)
{
orderRow.Rows.Add(shipmentRow);
shipmentRow.OrderRowId = orderRow.Id;
}
}
dbContext.SaveChanges();
Подробнее здесь: https://stackoverflow.com/questions/784 ... ge-tracker
Цикл Entity Framework Core 6 и трекер изменений ⇐ C#
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Привязка моделей Entity Framework Core к методу действия в контроллере ASP.NET Core
Anonymous » » в форуме C# - 0 Ответы
- 121 Просмотры
-
Последнее сообщение Anonymous
-
-
-
.NET Core/Entity Framework Core: извлечение настраиваемого поля из таблицы UserRoles
Anonymous » » в форуме C# - 0 Ответы
- 57 Просмотры
-
Последнее сообщение Anonymous
-