学习如何使用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 后进一步思考。