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


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

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

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

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

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

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

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

  • DateTimeOffset
  • Десятичное число
  • TimeSpan
  • UInt64

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

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

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

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

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

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

Операция Поддерживается?
AddCheckConstraint ✔ (перестроение)
AddColumn
AddForeignKey ✔ (перестроение)
AddPrimaryKey ✔ (перестроение)
AddUniqueConstraint ✔ (перестроение)
AlterColumn ✔ (перестроение)
CreateIndex
CreateTable
DropCheckConstraint ✔ (перестроение)
DropColumn ✔ (перестроение)
DropForeignKey ✔ (перестроение)
DropIndex
DropPrimaryKey ✔ (перестроение)
DropTable
DropUniqueConstraint ✔ (перестроение)
RenameColumn
ПереименоватьIndex ✔ (перестроение)
Переименование
ОбеспечениеSchema ✔ (no-op)
DropSchema ✔ (no-op)
Insert
Обновить
Удаление

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

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

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

Ограничения сценариев idempotent

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

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

dotnet ef migrations script CurrentMigration

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

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

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

EF9 представил механизм блокировки при выполнении миграций. Он направлен на защиту от нескольких выполнений миграции, происходящих одновременно, так как это может оставить базу данных в поврежденном состоянии. Это одна из потенциальных проблем, связанных с применением миграций во время выполнения с помощью DbContext.Database.Migrate() метода (дополнительные сведения см. в разделе "Применение миграций "). Чтобы устранить эту проблему, EF создает монопольную блокировку базы данных перед применением любых операций миграции.

К сожалению, SQLite не имеет встроенного механизма блокировки, поэтому EF создает отдельную таблицу (__EFMigrationsLock) и использует ее для блокировки. Блокировка освобождается после завершения миграции, а начальный код завершает выполнение. Однако если по какой-то причине миграция завершается ошибкой в невосстановимом способе, блокировка может быть освобождена неправильно. В этом случае последовательные миграции будут заблокированы при выполнении SQL и поэтому никогда не завершатся. Их можно разблокировать вручную, удалив таблицу __EFMigrationsLock в базе данных.

См. также