ORMX的表管理功能 - 学习教程,:表管理,索引管理,复合索引,表结构更新,索引命名规则,自动架构更新 - 学习如何使用 ORMX 的表管理功能,包括创建、更新、删除表,以及索引管理。

您当前正在浏览的是本站SEO版网页

请点击确认

马上提升浏览体验

ORMX的表管理功能

编程 数据库 阅读:2
2/8/2026 9:11:46 PM

学习如何使用 ORMX 的表管理功能,包括创建、更新、删除表,以及索引管理。 关键字:表管理,索引管理,复合索引,表结构更新,索引命名规则,自动架构更新

表管理器(ITableManager)

表管理器负责管理数据库表的创建、删除和更新。使用表管理器可以手动创建、删除和更新表。

ITableManager 接口

public interface ITableManager
{
    // 获取表名
    string GetName(Type entityType);

    // 检查表是否存在
    bool Exists(Type entityType);
    bool Exists(string tableName);

    // 创建表
    void Create(Type entityType);
    void Create(Type entityType, string tableName);

    // 更新表结构
    void Update(Type entityType);

    // 删除表
    void Drop(Type entityType);
    void Drop(string tableName);

    // 获取表对象
    ITable<T> Table<T>() where T : class, new();
}

获取表名

using JCode.ORMX.DbProvider.SQLite;

// 创建数据库提供程序
using var provider = new SQLiteProvider("Data Source=test.db");
using var tableManager = provider.GetTableManager();

var tableName = tableManager.GetName(typeof(User));
Console.WriteLine(tableName); // 输出:User

检查表是否存在

using JCode.ORMX.DbProvider.SQLite;

// 创建数据库提供程序
using var provider = new SQLiteProvider("Data Source=test.db");
using var tableManager = provider.GetTableManager();

// 检查实体类型对应的表是否存在
var exists = tableManager.Exists(typeof(User));
Console.WriteLine(<div class="latex">$"User 表存在:{exists}");

// 检查表名是否存在
var exists = tableManager.Exists("Users");
Console.WriteLine($</div>"Users 表存在:{exists}");

创建表

using JCode.ORMX.DbProvider.SQLite;

// 创建数据库提供程序
using var provider = new SQLiteProvider("Data Source=test.db");
using var tableManager = provider.GetTableManager();

// 创建表(使用实体类型的默认表名)
tableManager.Create(typeof(User));

// 创建表(指定表名)
tableManager.Create(typeof(User), "AppUsers");
Console.WriteLine("表创建成功");

创建表并自动更新架构

ORMX 支持在创建表时自动检测并更新表结构。当模型结构发生变化时(如添加新字段、修改字段类型等),可以通过传递 autoUpdate 参数来自动同步数据库结构:

using JCode.ORMX.DbProvider.SQLite;

// 创建数据库提供程序
using var provider = new SQLiteProvider("Data Source=test.db");
using var tableManager = provider.GetTableManager();

// 第一次调用:创建表
tableManager.Create(typeof(User));

// 模型结构发生变化后,再次调用并传入 true:自动更新表结构
tableManager.Create(typeof(User), true);
Console.WriteLine("表创建或更新成功");

自动更新功能说明:

  1. 工作原理

    • 系统会将表的元数据(字段信息、索引配置等)保存在 __ormx_schema_metadata 表中
    • 当调用 Create(type, true) 时,会比较当前模型结构与存储的元数据
    • 如果检测到差异,会自动执行数据库结构变更(添加列、修改列类型、更新索引等)
    • 更新完成后,会自动更新元数据表
  2. 支持的变更类型

    • ✅ 添加新列
    • ✅ 删除列(部分数据库支持)
    • ✅ 修改列类型
    • ✅ 添加/删除索引
    • ✅ 修改索引配置
  3. 数据库兼容性

    • ✅ SQLite:完全支持(通过表重建机制)
    • ✅ MySQL:完全支持
    • ✅ PostgreSQL:完全支持
    • ✅ SQL Server:完全支持
  4. 注意事项

    • 自动更新功能会导致元数据表 __ormx_schema_metadata 的创建
    • 对于 SQLite,修改列类型需要重建表,系统会自动处理数据迁移
    • 建议在生产环境中谨慎使用自动更新,最好在开发阶段使用

更新表

using JCode.ORMX.DbProvider.SQLite;

// 创建数据库提供程序
using var provider = new SQLiteProvider("Data Source=test.db");
using var tableManager = provider.GetTableManager();

// 更新表结构(添加新列、修改列类型等)
tableManager.Update(typeof(User));
Console.WriteLine("表更新成功");

删除表

using JCode.ORMX.DbProvider.SQLite;

// 创建数据库提供程序
using var provider = new SQLiteProvider("Data Source=test.db");
using var tableManager = provider.GetTableManager();

// 删除实体类型对应的表
tableManager.Drop(typeof(User));

// 删除指定表名的表
tableManager.Drop("User");
Console.WriteLine("表删除成功");

表对象(ITable

表对象是进行数据库操作的主要接口,通过表管理器获取。

获取表对象

var userTable = tableManager.Table<User>();

ITable 接口

public interface ITable<T> : IBaseBuilder<T>, IInsertClause<T>, IDebugClause<T> where T : class, new()
{
    bool Drop();
    bool Truncate();
}

表对象的常用操作

var userTable = tableManager.Table<User>();

// 插入数据
var user = userTable.Insert(new User { Name = "张三", Email = "zhangsan@example.com" });

// 查询数据
var users = userTable.Where(u => u.Age > 25).GetList();

// 更新数据
user.Age = 26;
userTable.Update(user);

// 删除数据
userTable.Delete(user.Id);

// 清空表
userTable.Truncate();

// 删除表
userTable.Drop();

关于 CRUD 操作的详细用法,请查阅 CRUD 操作

手动创建表

如果需要完全控制表结构,可以使用 SQL 命令手动创建:

using JCode.ORMX.DbProvider.SQLite;
using JCode.ORMX.Core;
using Microsoft.Data.Sqlite;

// 创建数据库连接
using var connection = new SqliteConnection("Data Source=test.db");
connection.Open();

var dbProvider = new SQLiteProvider(connection);
var sqlExecutor = dbProvider.SqlExecutor;

// 创建表
sqlExecutor.ExecuteNonQuery(@"
    CREATE TABLE Users (
        Id INTEGER PRIMARY KEY AUTOINCREMENT,
        Username TEXT NOT NULL,
        Email TEXT NOT NULL UNIQUE,
        Age INTEGER DEFAULT 0,
        CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP
    );
");

// 创建索引
sqlExecutor.ExecuteNonQuery("CREATE INDEX idx_users_email ON Users(Email);");

// 创建表管理器
using var tableManager = dbProvider.GetTableManager();

// 获取表对象
var userTable = tableManager.Table<User>();

// 执行操作
userTable.Insert(new User { Username = "张三", Email = "zhangsan@example.com" });

查看表结构

using JCode.ORMX.DbProvider.SQLite;
using JCode.ORMX.Core;
using Microsoft.Data.Sqlite;

// 创建数据库连接
using var connection = new SqliteConnection("Data Source=test.db");
connection.Open();

var dbProvider = new SQLiteProvider(connection);
var sqlExecutor = dbProvider.SqlExecutor;

// SQLite 查看表结构
var tableInfo = sqlExecutor.ExecuteReader<TableInfo>("PRAGMA table_info(Users);");

foreach (var column in tableInfo)
{
    Console.WriteLine(<div class="latex">$"列名:{column.Name}, 类型:{column.Type}");
}

// 辅助类
private class TableInfo
{
    public string Name { get; set; }
    public string Type { get; set; }
}

表结构更新

当实体类添加新属性时,可以更新表结构:

// 原始实体类
public class User
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    [Column(Name = "Username")]
    public string? Username { get; set; }
    
    [Column(Name = "Email")]
    public string? Email { get; set; }
}

// 添加新属性
public class User
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    [Column(Name = "Username")]
    public string? Username { get; set; }
    
    [Column(Name = "Email")]
    public string? Email { get; set; }
    
    // 新增属性
    [Column(Name = "Phone")]
    public string? Phone { get; set; }
    
    [Column(Name = "LastLoginAt")]
    public DateTime? LastLoginAt { get; set; }
}

// 更新表结构
using var connection = new SqliteConnection("Data Source=test.db");
connection.Open();

var dbProvider = new SQLiteProvider(connection);
using var tableManager = dbProvider.GetTableManager();

// 添加新列
tableManager.Update(typeof(User));

索引管理

ORMX 支持通过 ColumnAttribute 属性自动创建和管理索引。

索引属性说明

ColumnAttribute 中,以下属性用于配置索引:

属性 类型 说明
Indexed bool 是否创建普通索引
IndexName string 自定义索引名(可选)
IndexDescending bool 是否降序索引(默认 false)
IsUnique bool 是否创建唯一索引
UniqueIndexName string 自定义唯一索引名(可选)

自动创建索引

在创建表时,ORMX 会根据 ColumnAttribute 的配置自动创建索引:

public class User
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    // 普通索引 - 默认索引名:idx_User_Name
    [Column(Indexed = true)]
    public string? Name { get; set; }
    
    // 普通索引 - 自定义索引名
    [Column(Indexed = true, IndexName = "idx_custom_code")]
    public string? Code { get; set; }
    
    // 降序索引
    [Column(Indexed = true, IndexDescending = true)]
    public int SortOrder { get; set; }
    
    // 唯一索引 - 默认索引名:uk_User_Email
    [Column(IsUnique = true)]
    public string? Email { get; set; }
    
    // 唯一索引 - 自定义索引名
    [Column(IsUnique = true, UniqueIndexName = "uk_custom_phone")]
    public string? Phone { get; set; }
    
    // 同时创建普通索引和唯一索引
    [Column(Indexed = true, IsUnique = true)]
    public string? Identifier { get; set; }
}

// 创建表时自动创建所有索引
tableManager.Create(typeof(User));

索引更新

当实体类的索引配置发生变化时,可以通过 Update 方法更新索引:

// 修改索引配置
public class User
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    // 移除索引
    public string? Name { get; set; }
    
    // 修改为唯一索引
    [Column(IsUnique = true, UniqueIndexName = "uk_updated_code")]
    public string? Code { get; set; }
    
    // 新增索引
    [Column(Indexed = true)]
    public DateTime CreatedAt { get; set; }
}

// 更新表结构和索引
tableManager.Update(typeof(User));

手动管理索引(SQLite)

对于 SQLite 数据库,SQLiteTableManager 提供了以下手动索引管理方法:

var sqliteTableManager = (SQLiteTableManager)tableManager;

// 创建普通索引
sqliteTableManager.CreateIndex("User", "Name", "idx_custom_name");

// 创建唯一索引
sqliteTableManager.CreateIndex("User", "Email", "uk_custom_email", isUnique: true);

// 创建降序索引
sqliteTableManager.CreateIndex("User", "SortOrder", isDescending: true);

// 检查索引是否存在
var exists = sqliteTableManager.IndexExists("idx_custom_name");

// 获取表的所有索引
var indexes = sqliteTableManager.GetIndexes("User");

// 删除索引
sqliteTableManager.DropIndex("idx_custom_name");

// 重建表的所有索引
sqliteTableManager.RebuildIndexes("User");

索引命名规则

当未指定自定义索引名时,ORMX 会使用以下命名规则:

  • 普通索引:idx_<表名>_<列名>
  • 唯一索引:uk_<表名>_<列名>

例如:

  • idx_User_Name(User 表 Name 列的普通索引)
  • uk_User_Email(User 表 Email 列的唯一索引)

复合索引

ORMX 支持通过 IndexAttribute 在类级别定义复合索引(多列索引)。

IndexAttribute 属性说明

属性 类型 说明
Name string 索引名(必填)
Columns string 索引列(逗号分隔的属性名,必填)
IsUnique bool 是否唯一索引(可选,默认 false)
SortOrders string 排序方向(逗号分隔,与 Columns 对应,可选)

定义复合索引

ORMX 支持两种方式定义复合索引:

方式一:自动解析(推荐)

只需指定索引名,ORMX 会自动解析列名和是否唯一:

// 自动解析:Status, CreatedAt
[Index("idx_user_status_created")]

// 自动解析:Name, Email,且 IsUnique = true
[Index("uk_user_name_email")]

// 自动解析:Age
[Index("idx_user_age")]
public class User
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    public string? Name { get; set; }
    public string? Email { get; set; }
    public int Age { get; set; }
    public int Status { get; set; }
    public DateTime CreatedAt { get; set; }
}

自动解析规则

索引名格式 前缀 列名解析 IsUnique
idx_[表名]_[列 1] idx_ 列 1 false
idx_[表名]_[列 1]_[列 2] idx_ 列 1, 列 2 false
uk_[表名]_[列 1] uk_ 列 1 true
uk_[表名]_[列 1]_[列 2] uk_ 列 1, 列 2 true

示例

  • idx_user_status_created → 列:Status, CreatedAt,普通索引
  • uk_user_name_email → 列:Name, Email,唯一索引
  • idx_order_customer_product_date → 列:Customer, Product, Date,普通索引
方式二:显式指定
// 显式指定列名
[Index("idx_user_status_created", "Status, CreatedAt")]
[Index("idx_user_name_email", "Name, Email", IsUnique = true)]
[Index("idx_user_age_desc", "Age", SortOrders = "DESC")]
public class User
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    public string? Name { get; set; }
    public string? Email { get; set; }
    public int Age { get; set; }
    public int Status { get; set; }
    public DateTime CreatedAt { get; set; }
}

// 创建表时自动创建所有复合索引
tableManager.Create(typeof(User));

复合索引排序方向

可以为复合索引的每一列指定不同的排序方向:

// CustomerId 升序,OrderDate 降序
[Index("idx_order_customer_date", "CustomerId, OrderDate", SortOrders = "ASC, DESC")]
[Index("idx_order_unique", "CustomerId, ProductId", IsUnique = true)]
public class Order
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    public int CustomerId { get; set; }
    public int ProductId { get; set; }
    public decimal Amount { get; set; }
    public DateTime OrderDate { get; set; }
}

混合索引

可以同时使用单列索引和复合索引:

[Index("idx_mixed_type_status", "Type, Status")]
public class MixedIndexEntity
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    // 单列索引
    [Column(Indexed = true)]
    public string? Name { get; set; }
    
    // 唯一索引
    [Column(IsUnique = true)]
    public string? Code { get; set; }
    
    // 复合索引的一部分
    public int Type { get; set; }
    public int Status { get; set; }
}

手动创建复合索引(SQLite)

对于 SQLite 数据库,SQLiteTableManager 提供了手动创建复合索引的方法:

var sqliteTableManager = (SQLiteTableManager)tableManager;

// 创建复合索引
sqliteTableManager.CreateCompositeIndex("User", "idx_manual_composite", new[] { "Name", "Age" });

// 创建唯一复合索引
sqliteTableManager.CreateCompositeIndex("User", "idx_manual_unique", new[] { "Name", "Email" }, isUnique: true);

// 创建带排序方向的复合索引(CustomerId 升序,Amount 降序)
sqliteTableManager.CreateCompositeIndex(
    "Order", 
    "idx_manual_sort", 
    new[] { "CustomerId", "Amount" }, 
    sortOrders: new[] { false, true }); // false=ASC, true=DESC

错误处理

如果在 IndexAttribute 中指定了不存在的属性名,ORMX 会在运行时抛出详细的错误提示:

// 错误的索引定义
[Index("idx_invalid", "NonExistentColumn")]
public class User { ... }

// 创建表时会抛出:
// InvalidOperationException: 在实体类型 'User' 中定义的索引 'idx_invalid' 包含不存在的属性:NonExistentColumn
// 请检查 IndexAttribute 的 Columns 参数,确保所有列名都是有效的属性名。

实践示例

数据库连接和表管理

using JCode.ORMX.DbProvider.SQLite;

// 创建数据库提供程序(推荐方式:传入连接字符串)
using var provider = new SQLiteProvider("Data Source=test.db");

// 获取表管理器(无需额外参数)
using var tableManager = provider.GetTableManager();

// 获取表对象
var userTable = tableManager.Table<User>();
var orderTable = tableManager.Table<Order>();

Console.WriteLine($</div>"用户表名:{userTable.TableName}");
Console.WriteLine(<div class="latex">$"订单表名:{orderTable.TableName}");

资源管理

// tableManager 实现了 IDisposable,需要使用 using 语句
using var tableManager = provider.GetTableManager();

// 获取表对象(Table<T> 不需要使用 using,因为它没有实现 IDisposable)
var userTable = tableManager.Table<User>();
var orderTable = tableManager.Table<Order>();

// 执行操作...
// tableManager 释放时会自动释放内部的 SqlExecutor 资源
// provider 释放时也会释放内部管理的 SqlExecutor 资源

说明:

  • tableManagerprovider 都实现了 IDisposable 接口,建议使用 using 语句
  • tableManager.Dispose() 会释放其内部创建的 SqlExecutorBase 实例
  • provider.Dispose() 会释放其内部管理的 SqlExecutor 实例
  • Table<T> 对象不需要手动释放

初始化表创建的最佳实践:

在创建初始化表(如系统表、配置表等)时,如果需要批量创建多个表,建议使用同一个 tableManager 实例,而不是为每个表创建新的 tableManager。这样可以避免创建大量的数据库连接,提高性能并减少资源消耗。

// 推荐:使用同一个 tableManager 创建多个表
using var tableManager = provider.GetTableManager();
foreach (var tableType in _tableTypes)
{
    try
    {
        tableManager.Create(tableType, true);
        Logger?.Debug($</div>"数据表创建成功 {tableType.Name}");
    }
    catch (Exception ex)
    {
        Logger?.Error($"创建数据表失败 {tableType.Name}: {ex.Message}", ex);
    }
}

// 不推荐:为每个表创建新的 tableManager(会创建大量数据库连接)
foreach (var tableType in _tableTypes)
{
    using (var tm = provider.GetTableManager())
    {
        tm.Create(tableType, true);
    }
}

性能对比:

  • 推荐方式:只创建 1 个数据库连接和 1 个 SqlExecutorBase 实例
  • 不推荐方式:如果有 10 个表,会创建 10 个数据库连接和 10 个 SqlExecutorBase 实例

虽然数据库连接池可以复用连接,但频繁创建和释放连接仍然会带来性能开销。在初始化场景下,使用同一个 tableManager 是更高效的选择。

自动架构更新示例

using JCode.ORMX.DbProvider.SQLite;

// 创建数据库提供程序
using var provider = new SQLiteProvider("Data Source=test.db");
using var tableManager = provider.GetTableManager();

// 第一次运行:创建表
tableManager.Create(typeof(User));

// 开发过程中,User 类添加了新属性 Phone
// 再次运行:自动检测并添加 Phone 字段
tableManager.Create(typeof(User), true);

// 或者使用 Update 方法手动更新
tableManager.Update(typeof(User));

总结

本章介绍了 ORMX 框架的表管理功能,包括表的创建、更新、删除和索引管理。通过 ITableManager 接口,开发者可以方便地管理数据库表的生命周期。ORMX 提供了自动索引管理功能,支持单列索引、复合索引、唯一索引等多种索引类型,并提供了灵活的索引命名规则和排序方向配置。

自动架构更新功能是 ORMX 的核心特性之一,它允许开发者在模型结构发生变化时自动同步数据库结构,无需手动编写迁移脚本。系统会将表结构元数据保存在 __ormx_schema_metadata 表中,并在每次调用 Create(type, true) 时自动检测和更新差异。

对于 SQLite 数据库,还提供了手动索引管理的扩展方法。合理使用索引可以显著提升查询性能,但需要注意索引的数量和维护成本。

扩展思考

在大数据量场景下,如何设计最优的索引策略?是否需要引入数据库分区、分表等高级技术来应对数据增长?在分布式系统中,如何处理跨节点的索引同步和一致性问题?对于 MongoDB 这样的文档数据库,索引策略与传统关系型数据库有何不同?这些问题值得在深入使用 ORMX 后进一步思考。