轻量级数据库初始化框架

在开发一个风格化的Web应用程序时,Entity Framework (EF) 和 SQL Server 对于某些场景来说可能过于笨重。在这种情况下,需要一个更小、更轻量的进程内数据库,以便与 Microsoft AspNet Identity 框架一起使用。之前在使用 Umbraco 时,曾使用过 PetaPoco 作为轻量级 ORM,随后发现了 NPoco,它增加了一些不错的特性,包括许多方法的异步版本。SQLite 成为了选择,因为它是一个出色的产品,甚至支持全文搜索。

然而,这个解决方案并没有提供任何自动保持数据库与模式更改同步的方法,所以创建了一个简单的初始化框架,本文就是关于这个框架的介绍。

SQLite的限制

SQLite 在某些情况下只支持标准 SQL 命令的子集。例如,ALTER TABLE 不能用来删除列,而且与 CREATE TABLE IF NOT EXISTS 不同,没有类似的 ALTER TABLE ADD COLUMN IF NOT EXISTS。因此,任何初始化器都必须能够处理更复杂的情况,而不仅仅是执行脚本。当然,初始化器还必须有一个有效的版本控制机制,以便知道何时以及在哪里开始应用更改。

初始化框架

创建的初始化器并不完美,相信读者会找到许多改进的方法。但它能够完成工作,它是灵活的、自动的,并且简单易实现。它包括两个接口:

IDbInitialiser 用于管理数据库初始化和升级。通常在应用程序启动时调用一次。

public interface IDbInitialiser : IDisposable { void InitialiseDatabase(); void InitialiseDatabase(IDatabaseConfigurator[] configurators, bool dispose = false); long InitialVersion { get; } long FinalVersion { get; } long ConfiguratorsRun { get; } }

这个接口提供了维护数据库架构所需的主要功能。InitialiseDatabase 方法每次应用程序启动时都会被调用,应该执行所有必要的更新以将数据库升级到当前版本。它提供的特性并非必需,但对于调试或记录数据库更改活动非常有用。

配置器是实际进行数据库更改的组件。要使用自动配置,配置器类必须使用一致的命名约定,以三个数字结尾,例如 Config001, Config002, Config003 等。这三个数字是数据库版本号,并使用 SQLite 的 PRAGMA 存储。

public interface IDatabaseConfigurator : IDisposable { int Version { get; } void PreMigrate(IDatabase db); void Migrate(IDatabase db); void PostMigrate(IDatabase db); void Seed(IDatabase db); }

这个接口提供了对特定数据库版本更改进行操作的核心功能。每次需要对数据库进行更改以发布版本时,都会创建一个新的 IDatabaseConfigurator,它将执行所有必要的更改。

示例实现

SQLite的一个优点是,当第一次以任何方式访问数据库时,如果数据库不存在,SQLite 会创建一个空数据库。使用 SQLite 本身来存储当前数据库版本号,这是通过 PRAGMA user_version 命令完成的。

使用约定更新过程时,每个 IDatabaseConfigurator 必须使用类名的最后三个字符提供其版本号(例如 Config000, Config001 等)。初始化器使用反射定位并实例化配置器,并且在完成后也会处理它们的释放。

MyDbInitialiser 将整个更新序列包装在一个事务中,这样数据库要么完全升级,要么在发生错误时根本不升级。

注意事项

使用 System.Data.SQLite 时,需要在 config 文件中添加所需的 DbProviderFactory 条目。

<system.data> <DbProviderFactories> <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /> </DbProviderFactories> </system.data>

SQLite有时会留下 SQLite.Interop.dll 打开,导致构建失败。这是因为测试运行器在测试之间保持在内存中。通过使用测试设置来停止保持执行引擎在内存中可以解决这个问题。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485