Поделиться через


Ограничения поставщика базы данных SQLite EF Core

Поставщик SQLite имеет ряд ограничений миграции. Большинство этих ограничений являются результатом ограничений в базовом ядре СУБД SQLite и не относятся к EF.

Ограничения моделирования

Общая реляционная библиотека (совместно с поставщиками реляционных баз данных EF Core) определяет API для моделирования концепций, которые являются общими для большинства реляционных ядер СУБД. Несколько этих понятий не поддерживаются поставщиком SQLite.

  • Схемы
  • Последовательности
  • Маркеры параллелизма, созданные базой данных (см. документацию)

Ограничения запросов

SQLite не поддерживает следующие типы данных. EF Core может считывать и записывать значения этих типов, а также поддерживает запросы на равенство (where e.Property == value). Однако для других операций, таких как сравнение и упорядочение, потребуется оценка на клиенте.

  • DateTimeOffset
  • decimal
  • TimeSpan
  • ulong

Вместо DateTimeOffsetрекомендуется использовать значения DateTime. При обработке нескольких часовых поясов рекомендуется преобразовать значения в формате UTC перед сохранением, а затем вернуться в соответствующий часовой пояс.

Тип decimal обеспечивает высокий уровень точности. Если вам не нужен этот уровень точности, рекомендуется использовать double вместо этого. Можно использовать преобразователь значений , чтобы продолжать использовать decimal в ваших классах.

modelBuilder.Entity<MyEntity>()
    .Property(e => e.DecimalProperty)
    .HasConversion<double>();

Ограничения миграции

Ядро СУБД SQLite не поддерживает ряд операций схемы, поддерживаемых большинством других реляционных баз данных. Если вы попытаетесь применить одну из неподдерживаемых операций к базе данных SQLite, будет выброшено исключение NotSupportedException.

Для того, чтобы выполнить определенные операции, будет предпринята попытка перестроения. Перестроение возможно только для объектов базы данных, которые являются частью модели EF Core. Если артефакт базы данных не является частью модели — например, если он был создан вручную внутри миграции — то ошибка NotSupportedException все равно выбрасывается.

Операция Поддерживается?
ДобавитьОграничениеПроверки ✔ (реконструкция)
AddColumn (добавить столбец)
ДобавитьВнешнийКлюч ✔ (реконструкция)
ДобавитьПервичныйКлюч ✔ (реконструкция)
ДобавитьУникальноеОграничение ✔ (реконструкция)
AlterColumn ✔ (реконструкция)
CreateIndex
СоздатьТаблицу
УдалитьПроверочноеОграничение ✔ (реконструкция)
DropColumn ✔ (реконструкция)
УдалитьВнешнийКлюч ✔ (реконструкция)
DropIndex
УдалитьПервичныйКлюч ✔ (реконструкция)
DropTable
УдалитьУникальноеОграничение ✔ (реконструкция)
ПереименоватьСтолбец
ПереименоватьИндекс ✔ (реконструкция)
ПереименованиеТаблицы
ОбеспечениеСхемы ✔ (no-op)
DropSchema ✔ (no-op)
Вставить
Обновить
Удалить

Обходное решение для ограничений миграции

Чтобы обойти некоторые из этих ограничений, вы можете вручную добавить код для перестроения в процессе ваших миграций. Перестроения таблиц включают создание новой таблицы, копирование данных в новую таблицу, удаление старой таблицы, переименование новой таблицы. Для выполнения некоторых этих действий вам потребуется использовать Sql метод.

Дополнительные сведения см. в разделе Внесение изменений в схемы других типов таблиц документации по SQLite.

Ограничения идемпотентных скриптов

В отличие от других баз данных, SQLite не включает процедурный язык. Из-за этого невозможно создать логику if-then, необходимую скриптам идемпотентной миграции.

Если вы знаете, что последняя миграция применена к базе данных, можно создать скрипт из этой миграции до последней миграции.

dotnet ef migrations script CurrentMigration

В противном случае рекомендуется использовать dotnet ef database update, чтобы применить миграции. При выполнении команды можно указать файл базы данных.

dotnet ef database update --connection "Data Source=My.db"

Защита параллельных миграций

EF9 представил механизм блокировки миграции для защиты от одновременных выполнений миграции. В отличие от SQL Server, которая использует блокировку приложения уровня сеанса (sp_getapplock), которая автоматически освобождается при закрытии подключения, SQLite не имеет встроенных блокировок приложений. ВМЕСТО этого EF Core создает таблицу __EFMigrationsLock и вставляет строку для получения блокировки.

Обработка оставленных блокировок

Если приложение неожиданно завершается (например, процесс завершится принудительно во время миграции), строка блокировки в __EFMigrationsLock таблице может не удалиться. Это предотвращает завершение последующей миграции, так как каждая попытка будет ждать неограниченное время, пока блокировка будет освобождена.

Чтобы устранить заброшенную блокировку, удалите таблицу __EFMigrationsLock из базы данных:

DROP TABLE "__EFMigrationsLock";

Или, кроме того, удалите все строки из таблицы:

DELETE FROM "__EFMigrationsLock";

После очистки блокировки последующие операции миграции выполняются нормально. При необходимости таблица автоматически создается.

См. также