ORMX的表管理功能 - 开发日志,表管理, 索引管理, 复合索引, 表结构更新, 索引命名规则 - 学习如何使用ORMX的表管理功能,包括创建、更新、删除表,以及索引管理。

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

请点击确认

马上提升浏览体验

ORMX的表管理功能

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

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

第五章:表管理

5.1 表管理器(ITableManager)

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

5.1.1 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();
}

5.1.2 获取表名

using JCode.ORMX.DataProviders.SQLite;

// 创建数据库提供程序(推荐方式)
using var provider = new SqliteDatabaseProvider("Data Source=:memory:");
var tableManager = provider.GetTableManager();

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

5.1.3 检查表是否存在

using JCode.ORMX.DataProviders.SQLite;

// 创建数据库提供程序(推荐方式)
using var provider = new SqliteDatabaseProvider("Data Source=:memory:");
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}");

5.1.4 创建表

using JCode.ORMX.DataProviders.SQLite;

// 创建数据库提供程序(推荐方式)
using var provider = new SqliteDatabaseProvider("Data Source=:memory:");
var tableManager = provider.GetTableManager();

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

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

5.1.5 更新表

using JCode.ORMX.DataProviders.SQLite;

// 创建数据库提供程序(推荐方式)
using var provider = new SqliteDatabaseProvider("Data Source=:memory:");
var tableManager = provider.GetTableManager();

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

5.1.6 删除表

using JCode.ORMX.DataProviders.SQLite;

// 创建数据库提供程序(推荐方式)
using var provider = new SqliteDatabaseProvider("Data Source=:memory:");
var tableManager = provider.GetTableManager();

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

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

5.2 表对象(ITable

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

5.2.1 获取表对象

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

5.2.2 ITable 接口

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

5.2.3 表对象的常用操作

using 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操作

5.3 手动创建表

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

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

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

var dbProvider = new DbProvider(); // 使用抽象基类或具体实现
var sqlExecutor = new SqlExecutor(connection, dbProvider);

// 创建表
sqlExecutor.ExecuteNonQuery(@"
    CREATE TABLE Users (
        Id INTEGER PRIMARY KEY AUTOINCREMENT,
        Name 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);");

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

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

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

5.4 查看表结构

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

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

var dbProvider = new DbProvider(); // 使用抽象基类或具体实现
var sqlExecutor = new SqlExecutor(connection, dbProvider);

// 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; }
}

5.5 表结构更新

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

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

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

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

var dbProvider = new SqliteDatabaseProvider(connection); // 使用 SQLite 数据库提供程序
var tableManager = dbProvider.GetTableManager();

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

5.6 索引管理

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

5.6.1 索引属性说明

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

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

5.6.2 自动创建索引

在创建表时,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));

5.6.3 索引更新

当实体类的索引配置发生变化时,可以通过 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));

5.6.4 手动管理索引(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");

5.6.5 索引命名规则

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

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

例如:

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

5.6.6 复合索引

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

5.6.6.1 IndexAttribute 属性说明

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

5.6.6.2 定义复合索引

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, Created,普通索引
  • 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));

5.6.6.3 复合索引排序方向

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

// 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; }
}

5.6.6.4 混合索引

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

[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; }
}

5.6.6.5 手动创建复合索引(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

5.6.6.6 错误处理

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

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

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

5.7 实践示例

5.7.1 数据库连接和表管理

using JCode.ORMX.DataProviders.SQLite;

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

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

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

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

5.7.2 资源管理

// 使用 using 语句自动释放资源
using var userTable = tableManager.Table<User>();
using var orderTable = tableManager.Table<Order>();

// 执行操作...
// 自动释放资源

总结

本章介绍了 ORMX 框架的表管理功能,包括表的创建、更新、删除和索引管理。通过 ITableManager 接口,开发者可以方便地管理数据库表的生命周期。ORMX 提供了自动索引管理功能,支持单列索引、复合索引、唯一索引等多种索引类型,并提供了灵活的索引命名规则和排序方向配置。对于 SQLite 数据库,还提供了手动索引管理的扩展方法。合理使用索引可以显著提升查询性能,但需要注意索引的数量和维护成本。

扩展思考

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