Цикл Entity Framework Core 6 и трекер измененийC#

Место общения программистов C#
Ответить
Anonymous
 Цикл Entity Framework Core 6 и трекер изменений

Сообщение Anonymous »

Я стараюсь избегать вызова 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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»