Как удалить всю базу данных и сбросить трекер изменений с EF Core, используя SQLite - PullRequest
0 голосов
/ 01 апреля 2019

У меня есть серверная клиентская архитектура, где сервер предоставляет Rest API для клиентов для синхронизации всей базы данных. Они сохраняют его в своей локальной базе данных SQLite. Модель находится в общем проекте и может иногда меняться. Поэтому клиенты должны обновить свою схему локальной базы данных SQLite. Это, конечно, происходит только после обновления программного обеспечения клиента (файл базы данных остается неизменным).

Это просто достигается путем общего удаления файла базы данных и последующего его повторного создания.

_context.Database.EnsureDeleted();
_context.Database.EnsureCreated();

AttachNewDataFromServerToDatabaseContext(_context);

_context.SaveChanges();

Служба Rest API создается как singelton и всегда использует один и тот же объект контекста базы данных. Первая синхронизация работает нормально. Но следующие терпят неудачу:

System.InvalidOperationException: The instance of entity type '***' cannot be tracked because another instance with the key value '{id:  ***}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

Таким образом, трекер изменений все еще знает о "старых" сущностях, хотя вся база данных была удалена.

Мои мысли об этом:

  • Создание нового контекста данных каждый раз, когда база данных синхронизируется, может исправить это, потому что отслеживание изменений начинается с нуля. Не хорошее решение в моих глазах.
  • Было бы замечательно, если EnsureDeleted также «сбрасывает» трекер изменений или вы можете сделать это вручную.

Что вы думаете об этом? Спасибо за вашу помощь!

1 Ответ

2 голосов
/ 01 апреля 2019
  • Создание нового контекста данных каждый раз, когда база данных синхронизируется, может исправить это, потому что отслеживание изменений начинается с нуля. Не очень хорошее решение в моих глазах.

Я бы скорее сказал, что это "правильное" решение. Метаданные контекста (a.k.a. Model) по умолчанию кэшируются для контекста тип , соединение дб поддерживается пулом соединений и открывается / закрывается только при необходимости в любом случае. Таким образом, единственное преимущество повторного использования экземпляра контекста состоит в том, чтобы избежать создания нескольких DbSet экземпляров.

В то же время трекер будет хранить множество экземпляров «сущностей» и не будет позволять им собирать мусор без необходимости после вызова SaveChanges. Не учитывать потенциальные проблемы многопоточного доступа.

Так что ИМХО, это путь - создать новый контекст, сделать что-то с ним и избавиться от него.

  • Было бы замечательно, если EnsureDeleted также «сбрасывает» трекер изменений или вы можете сделать это вручную.

Действительно, это было бы здорово. Но в настоящее время ни EnsureDeleted этого не делает, ни EF Core не предоставляет публичный способ сделать это вручную.

Однако существует внутренний путь с обычным риском того, что он может быть изменен в какой-то будущей версии EF Core. Добавление

using Microsoft.EntityFrameworkCore.Infrastructure;

позволит вам использовать что-то вроде этого

_context.ChangeTracker.GetInfrastructure().ResetState();

вероятно до _context.Database.EnsureDeleted();. Что в основном доказывает, что вы действительно должны использовать первый вариант (новый контекст).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...