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

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

请点击确认

马上提升浏览体验

ORMX的表管理功能

编程 数据库 阅读:0
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.DataProviders.SQLite;

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

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

检查表是否存在

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}");

创建表

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("表创建成功");

更新表

using JCode.ORMX.DataProviders.SQLite;

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

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

删除表

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("表删除成功");

表对象(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;
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();

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

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

查看表结构

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

表结构更新

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

// 原始实体类
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));

索引管理

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 在类级别定义复合索引(多列索引)。

####.1 IndexAttribute 属性说明

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

####.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));

####.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; }
}

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

####.6 错误处理

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

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

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

实践示例

数据库连接和表管理

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}");

资源管理

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

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

// 执行操作...
// tableManager 释放时会自动释放内部资源

总结

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

扩展思考

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