探讨SQLite使用EF的CodeFirst模式时数据库迁移的限制

发表时间: 2022-04-12 19:26

问题说明

最近在研究EF的CodeFirst模式下使用SQLite进行数据库开发,需要简单的使用数据库的增删查改。因为不是专业的数据库专家,因此使用过程出现了很多问题。其中一个就是数据库迁移的问题。

网络上看到的代码示例,很多是基于SqlServer和MySql的,测试过程中发现很多函数多不能使用,造成了很多困惑。最后发现了SQLite的局限性。

SQLite 提供程序有一些迁移限制,其中大部分是底层 SQLite 数据库引擎的限制造成的,并不是 EF 特定的。

参考的链接:SQLite - SQLite 局限性 - 《微软 EntityFrameworkCore 中文文档》 - 书栈网 · BookStack

迁移的局限性

SQLite 数据库引擎不支持一些其他主要的关系数据库支持的模式操作。如果尝试将不被支持的操作应用到 SQLite 数据库,将会抛出 NotSupportedException 异常。

操作

支持状态

AddColumn(添加数据列)

AddForeignKey(添加外键)

AddPrimaryKey(添加主键)

AddUniqueConstraint(添加唯一约束)

AlterColumn(修改数据列)

CreateIndex(创建索引)

CreateTable(创建数据表)

DropColumn(删除数据列)

DropForeignKey(删除外键)

DropIndex(删除索引)

DropPrimaryKey(删除主键)

DropTable(删除数据表)

DropUniqueConstraint(删除唯一约束)

RenameColumn(重命名数据列)

RenameIndex(重命名索引)

RenameTable(重命名表名)

迁移局限性解决方案

可以在迁移中手动编写代码来执行数据表重建,这样可以解决一些局限性问题。一个数据表的重建包括重命名已有的数据表、创建新表、复制数据到新表以及删除旧的数据表。这将需要使用 Sql(string) 方法来执行其中一些步骤。

参考示例:

public partial class UpdateBusTable : DbMigration{    public override void Up()    {        Sql(@"PRAGMA foreign_keys = 0;        CREATE TABLE sqlitestudio_temp_table AS SELECT *                FROM Bus;        DROP TABLE Bus;        CREATE TABLE Bus (        Id         NVARCHAR (128)        NOT NULL,        Name       NVARCHAR (2147483647),        RunCount   INT                   DEFAULT (0),        CreateTime DATETIME              NOT NULL,        PRIMARY KEY (Id)        );        INSERT INTO Bus (            Id,            Name,            RunCount        )        SELECT Id,               Name,               RunCount          FROM sqlitestudio_temp_table;        DROP TABLE sqlitestudio_temp_table;        PRAGMA foreign_keys = 1;");    }    public override void Down()    {        DropColumn("dbo.Bus", "CreateTime");    }}

自动生成sql语句

平时很少写sql语句,可能在手动写sql语句时出现问题,找到一个工具,可以在修改数据库表的时候,生成迁移语句,操作流程如下:

  • 下载sqlite工具:SALiteStudio

  • 生成数据库迁移sql语句

以添加一个字段为例,生成sql语句步骤如下:

  • 步骤一:打开数据库,找到要修改的表,在“结构”页面,选择“Add Column”

  • 步骤二:填写字段信息,点击OK

  • 步骤三:点击Commit structure changes,自动弹出将要执行的sql语句

  • 步骤四:拷贝sql语句到迁移类
public partial class UpdateBusTable : DbMigration{    public override void Up()    {        Sql(@"PRAGMA foreign_keys = 0;        CREATE TABLE sqlitestudio_temp_table AS SELECT *                FROM Bus;        DROP TABLE Bus;        CREATE TABLE Bus (        Id         NVARCHAR (128)        NOT NULL,        Name       NVARCHAR (2147483647),        RunCount   INT                   DEFAULT (0),        CreateTime DATETIME              NOT NULL,        PRIMARY KEY (Id)        );        INSERT INTO Bus (            Id,            Name,            RunCount        )        SELECT Id,               Name,               RunCount          FROM sqlitestudio_temp_table;        DROP TABLE sqlitestudio_temp_table;        PRAGMA foreign_keys = 1;");    }    public override void Down()    {        DropColumn("dbo.Bus", "CreateTime");    }}