Entity Framework Core Чтение базы из одного контекста, сохранение в другом контексте и очистка локального контекста

PS Для примера классы сильно упрощены. Версия EFCore 3.1
Есть схема:

class Configure
{
   public int id { get; set; }
   public string name { get; set; }
}
class Value
{
   public int id { get; set; }
   [ForeignKey(nameof(confid))]
   public Configure? conf { get; set; }
   [NotMapped]
   public int? confid { get; set; }
   public long value { get; set; }
}

Данные я получаю в одном контексте и на основании Configure запускаю генерацию Value в бесконечном цикле:

DBContext context1 = new DBContext();
List<Configure> confs = context1.Configures.ToList();
foreach (var conf in confs)
{
  Thread th = new Thread(() => calculate(conf));
  th.Start();
}

Когда нужно добавить новые данные в контекст и сохранить его - возникает ошибка:

void calculate(Configure conf)
{
  while(flagisactive)
  {
    DBContext context2 = new DBContext();
    Value v = new Value()
    {
      Configure = conf,
      confid = conf.id,
      value = DateTime.Now.Ticks
    }
    context2.Values.Add(v);
    context2.SaveChanges(); //тут ошибка:
    //Microsoft.EntityFrameworkCore.DbUpdateException: "An error occurred while updating the entries. See the inner exception for details."
    //MySqlException: Duplicate entry '1' for key 'configures.PRIMARY'
  }
}

Причина в том, что context2 не знает о том, что эти данные по Configure уже есть в БД и были получены в context1 и context2 пытается записать их как новые.
Есть 2 пути решения данной проблемы:

  1. Как раньше и делал - писать всё руками через SQL, но число таких таблиц как Value растёт, как и их сложность и постоянно меняется, значительно повышается вероятность ошибки.
  2. Писать прямо в context1 новые записи по Value - бесконечный рост потребляемой памяти, нужна очистка значений, т.к. приложение будет крутиться месяцами и никто не будет его перезапускать.

В итоге - эти известные мне варианты - не вариант, и нужно как-то сообщать новому контексту, что связанные данные уже есть в БД и нужно добавить только Value и не писать Configure. Я где-то читал что такое возможно, но не могу найти пример.
В качестве альтернативного варианта - передавать context1 в цикл, добавлять новый Value, и затем сразу удалять его после context1.SaveChanges(), но только локально, а не из базы, но есть загвоздка в том, что не везде можно его передать, поэтому т.к. Value может быть не привязан к Configure. Так-же не могу найти информацию о том как можно удалять из локального контекста конкретные записи, чтобы впоследствии EntityFramework их не стёр из БД.

PS Новые данные в такие таблицы будут добавлять редко, поэтому с точки зрения ресурсозатратности (чтобы заводить новый контекст) проблем нет.

В итоге вопрос в следующем: как можно реализовать передачу информации о том что данные уже есть в БД из одного контекста в другой? Или хотя-бы удалять записи только из локального контекста, не трогая сохранённые в БД!?


Ответы (1 шт):

Автор решения: Blackmeser

Нашёл решение по ссылкам:
https://docs.microsoft.com/ru-ru/ef/core/saving/disconnected-entities
https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Saving/Disconnected/
https://www.entityframeworktutorial.net/efcore/changetracker-trackgraph-ef-core.aspx

Нужно было заменить:

context2.Values.Add(v);

на:

context2.ChangeTracker.TrackGraph(v, n =>
  {
    if (n.Entry.Entity == ae) n.Entry.State = Microsoft.EntityFrameworkCore.EntityState.Added;
    else n.Entry.State = Microsoft.EntityFrameworkCore.EntityState.Unchanged;
  });

После чего SaveChanges() сохраняет только текущий объект.
Если кому-нибудь известно о подводных камнях и способах устранения - прошу поделиться информацией в комментариях.

→ Ссылка