# 数据模型文档 ## 概述 数据模型层是 UdminAI 的数据持久化核心,基于 SeaORM 框架实现,提供类型安全的数据库操作接口。包含用户管理、权限控制、流程管理、定时任务、系统日志等核心业务实体。 ## 架构设计 ### 模型模块结构 ``` models/ ├── mod.rs # 模型模块导出 ├── user.rs # 用户模型 ├── role.rs # 角色模型 ├── permission.rs # 权限模型 ├── user_role.rs # 用户角色关联模型 ├── role_permission.rs # 角色权限关联模型 ├── flow.rs # 流程模型 ├── flow_version.rs # 流程版本模型 ├── flow_execution.rs # 流程执行记录模型 ├── schedule_job.rs # 定时任务模型 ├── job_execution.rs # 任务执行记录模型 ├── system_config.rs # 系统配置模型 ├── operation_log.rs # 操作日志模型 ├── system_log.rs # 系统日志模型 ├── notification.rs # 通知模型 └── notification_template.rs # 通知模板模型 ``` ### 设计原则 - **实体完整性**: 每个实体都有完整的字段定义 - **关系映射**: 正确定义实体间的关联关系 - **类型安全**: 使用强类型定义所有字段 - **索引优化**: 为查询字段添加合适的索引 - **软删除**: 重要数据支持软删除机制 - **审计字段**: 包含创建时间、更新时间等审计字段 ## 用户模型 (user.rs) ### 实体定义 ```rust use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "users")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(unique)] pub username: String, pub password_hash: String, #[sea_orm(unique)] pub email: Option, pub display_name: Option, pub avatar: Option, pub status: UserStatus, pub last_login_at: Option, pub login_count: i32, pub is_deleted: bool, pub created_at: DateTimeWithTimeZone, pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm(has_many = "super::user_role::Entity")] UserRoles, #[sea_orm(has_many = "super::flow::Entity")] Flows, #[sea_orm(has_many = "super::schedule_job::Entity")] ScheduleJobs, #[sea_orm(has_many = "super::operation_log::Entity")] OperationLogs, } impl Related for Entity { fn to() -> RelationDef { super::user_role::Relation::Role.def() } fn via() -> Option { Some(super::user_role::Relation::User.def().rev()) } } impl ActiveModelBehavior for ActiveModel {} ``` ### 用户状态枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "user_status")] pub enum UserStatus { #[sea_orm(string_value = "active")] Active, #[sea_orm(string_value = "inactive")] Inactive, #[sea_orm(string_value = "suspended")] Suspended, #[sea_orm(string_value = "deleted")] Deleted, } ``` ### 数据库迁移 ```rust use sea_orm_migration::prelude::*; #[derive(DeriveMigrationName)] pub struct Migration; #[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { manager .create_table( Table::create() .table(User::Table) .if_not_exists() .col( ColumnDef::new(User::Id) .string_len(32) .not_null() .primary_key(), ) .col( ColumnDef::new(User::Username) .string_len(50) .not_null() .unique_key(), ) .col( ColumnDef::new(User::PasswordHash) .string_len(255) .not_null(), ) .col( ColumnDef::new(User::Email) .string_len(100) .unique_key(), ) .col( ColumnDef::new(User::DisplayName) .string_len(100), ) .col( ColumnDef::new(User::Avatar) .string_len(255), ) .col( ColumnDef::new(User::Status) .enumeration( Alias::new("user_status"), ["active", "inactive", "suspended", "deleted"], ) .not_null() .default("active"), ) .col( ColumnDef::new(User::LastLoginAt) .timestamp_with_time_zone(), ) .col( ColumnDef::new(User::LoginCount) .integer() .not_null() .default(0), ) .col( ColumnDef::new(User::IsDeleted) .boolean() .not_null() .default(false), ) .col( ColumnDef::new(User::CreatedAt) .timestamp_with_time_zone() .not_null() .default(Expr::current_timestamp()), ) .col( ColumnDef::new(User::UpdatedAt) .timestamp_with_time_zone() .not_null() .default(Expr::current_timestamp()), ) .to_owned(), ) .await?; // 创建索引 manager .create_index( Index::create() .if_not_exists() .name("idx_users_email") .table(User::Table) .col(User::Email) .to_owned(), ) .await?; manager .create_index( Index::create() .if_not_exists() .name("idx_users_status") .table(User::Table) .col(User::Status) .to_owned(), ) .await?; Ok(()) } async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { manager .drop_table(Table::drop().table(User::Table).to_owned()) .await } } ``` ## 角色模型 (role.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "roles")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(unique)] pub name: String, pub description: Option, pub is_system: bool, pub sort_order: i32, pub is_deleted: bool, pub created_at: DateTimeWithTimeZone, pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm(has_many = "super::user_role::Entity")] UserRoles, #[sea_orm(has_many = "super::role_permission::Entity")] RolePermissions, } impl Related for Entity { fn to() -> RelationDef { super::user_role::Relation::User.def() } fn via() -> Option { Some(super::user_role::Relation::Role.def().rev()) } } impl Related for Entity { fn to() -> RelationDef { super::role_permission::Relation::Permission.def() } fn via() -> Option { Some(super::role_permission::Relation::Role.def().rev()) } } impl ActiveModelBehavior for ActiveModel {} ``` ## 权限模型 (permission.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "permissions")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub name: String, pub resource: String, pub action: String, pub description: Option, pub parent_id: Option, pub sort_order: i32, pub is_system: bool, pub created_at: DateTimeWithTimeZone, pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm(has_many = "super::role_permission::Entity")] RolePermissions, #[sea_orm( belongs_to = "Entity", from = "Column::ParentId", to = "Column::Id" )] Parent, #[sea_orm(has_many = "Entity")] Children, } impl Related for Entity { fn to() -> RelationDef { super::role_permission::Relation::Role.def() } fn via() -> Option { Some(super::role_permission::Relation::Permission.def().rev()) } } impl ActiveModelBehavior for ActiveModel {} ``` ## 流程模型 (flow.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "flows")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub name: String, pub description: Option, pub category: String, pub status: FlowStatus, pub version: String, pub design: Json, pub input_schema: Option, pub output_schema: Option, pub tags: Option, pub created_by: String, pub updated_by: Option, pub published_at: Option, pub is_deleted: bool, pub created_at: DateTimeWithTimeZone, pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::user::Entity", from = "Column::CreatedBy", to = "super::user::Column::Id" )] Creator, #[sea_orm( belongs_to = "super::user::Entity", from = "Column::UpdatedBy", to = "super::user::Column::Id" )] Updater, #[sea_orm(has_many = "super::flow_version::Entity")] FlowVersions, #[sea_orm(has_many = "super::flow_execution::Entity")] FlowExecutions, #[sea_orm(has_many = "super::schedule_job::Entity")] ScheduleJobs, } impl ActiveModelBehavior for ActiveModel {} ``` ### 流程状态枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "flow_status")] pub enum FlowStatus { #[sea_orm(string_value = "draft")] Draft, #[sea_orm(string_value = "published")] Published, #[sea_orm(string_value = "archived")] Archived, #[sea_orm(string_value = "deleted")] Deleted, } ``` ## 流程执行记录模型 (flow_execution.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "flow_executions")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub flow_id: String, pub flow_version: String, pub status: ExecutionStatus, pub input: Option, pub output: Option, pub error: Option, pub context: Option, pub execution_log: Option, pub started_by: Option, pub trigger_type: TriggerType, pub trigger_source: Option, pub start_time: DateTimeWithTimeZone, pub end_time: Option, pub duration_ms: Option, pub created_at: DateTimeWithTimeZone, pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::flow::Entity", from = "Column::FlowId", to = "super::flow::Column::Id" )] Flow, #[sea_orm( belongs_to = "super::user::Entity", from = "Column::StartedBy", to = "super::user::Column::Id" )] User, } impl ActiveModelBehavior for ActiveModel {} ``` ### 执行状态枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "execution_status")] pub enum ExecutionStatus { #[sea_orm(string_value = "pending")] Pending, #[sea_orm(string_value = "running")] Running, #[sea_orm(string_value = "completed")] Completed, #[sea_orm(string_value = "failed")] Failed, #[sea_orm(string_value = "cancelled")] Cancelled, #[sea_orm(string_value = "timeout")] Timeout, } #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "trigger_type")] pub enum TriggerType { #[sea_orm(string_value = "manual")] Manual, #[sea_orm(string_value = "schedule")] Schedule, #[sea_orm(string_value = "webhook")] Webhook, #[sea_orm(string_value = "api")] Api, #[sea_orm(string_value = "event")] Event, } ``` ## 定时任务模型 (schedule_job.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "schedule_jobs")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub name: String, pub description: Option, pub cron_expression: String, pub timezone: String, pub job_type: JobType, pub target_id: String, pub target_config: Option, pub enabled: bool, pub max_retries: i32, pub retry_interval: i32, pub timeout_seconds: Option, pub last_run_at: Option, pub next_run_at: Option, pub run_count: i64, pub success_count: i64, pub failure_count: i64, pub created_by: String, pub updated_by: Option, pub is_deleted: bool, pub created_at: DateTimeWithTimeZone, pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::user::Entity", from = "Column::CreatedBy", to = "super::user::Column::Id" )] Creator, #[sea_orm( belongs_to = "super::flow::Entity", from = "Column::TargetId", to = "super::flow::Column::Id" )] Flow, #[sea_orm(has_many = "super::job_execution::Entity")] JobExecutions, } impl ActiveModelBehavior for ActiveModel {} ``` ### 任务类型枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "job_type")] pub enum JobType { #[sea_orm(string_value = "flow")] Flow, #[sea_orm(string_value = "script")] Script, #[sea_orm(string_value = "http")] Http, #[sea_orm(string_value = "command")] Command, } ``` ## 任务执行记录模型 (job_execution.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "job_executions")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub job_id: String, pub status: JobExecutionStatus, pub trigger_type: JobTriggerType, pub start_time: DateTimeWithTimeZone, pub end_time: Option, pub duration_ms: Option, pub output: Option, pub error: Option, pub retry_count: i32, pub created_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::schedule_job::Entity", from = "Column::JobId", to = "super::schedule_job::Column::Id" )] ScheduleJob, } impl ActiveModelBehavior for ActiveModel {} ``` ### 执行状态枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "job_execution_status")] pub enum JobExecutionStatus { #[sea_orm(string_value = "running")] Running, #[sea_orm(string_value = "completed")] Completed, #[sea_orm(string_value = "failed")] Failed, #[sea_orm(string_value = "timeout")] Timeout, #[sea_orm(string_value = "cancelled")] Cancelled, } #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "job_trigger_type")] pub enum JobTriggerType { #[sea_orm(string_value = "schedule")] Schedule, #[sea_orm(string_value = "manual")] Manual, #[sea_orm(string_value = "retry")] Retry, } ``` ## 操作日志模型 (operation_log.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "operation_logs")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub user_id: String, pub operation: String, pub resource: String, pub resource_id: Option, pub details: Option, pub ip_address: Option, pub user_agent: Option, pub status: OperationStatus, pub error: Option, pub duration_ms: Option, pub created_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::user::Entity", from = "Column::UserId", to = "super::user::Column::Id" )] User, } impl ActiveModelBehavior for ActiveModel {} ``` ### 操作状态枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "operation_status")] pub enum OperationStatus { #[sea_orm(string_value = "success")] Success, #[sea_orm(string_value = "failed")] Failed, #[sea_orm(string_value = "partial")] Partial, } ``` ## 系统日志模型 (system_log.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "system_logs")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub level: LogLevel, pub source: String, pub event_type: String, pub message: String, pub details: Option, pub trace_id: Option, pub span_id: Option, pub created_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} impl ActiveModelBehavior for ActiveModel {} ``` ### 日志级别枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "log_level")] pub enum LogLevel { #[sea_orm(string_value = "trace")] Trace, #[sea_orm(string_value = "debug")] Debug, #[sea_orm(string_value = "info")] Info, #[sea_orm(string_value = "warn")] Warn, #[sea_orm(string_value = "error")] Error, } ``` ## 通知模型 (notification.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "notifications")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub title: String, pub content: String, pub notification_type: NotificationType, pub channel: NotificationChannel, pub recipient_id: String, pub recipient_type: RecipientType, pub status: NotificationStatus, pub priority: NotificationPriority, pub template_id: Option, pub template_data: Option, pub scheduled_at: Option, pub sent_at: Option, pub read_at: Option, pub error: Option, pub retry_count: i32, pub created_at: DateTimeWithTimeZone, pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::notification_template::Entity", from = "Column::TemplateId", to = "super::notification_template::Column::Id" )] Template, } impl ActiveModelBehavior for ActiveModel {} ``` ### 通知相关枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "notification_type")] pub enum NotificationType { #[sea_orm(string_value = "system")] System, #[sea_orm(string_value = "flow_execution")] FlowExecution, #[sea_orm(string_value = "job_execution")] JobExecution, #[sea_orm(string_value = "user_action")] UserAction, #[sea_orm(string_value = "alert")] Alert, } #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "notification_channel")] pub enum NotificationChannel { #[sea_orm(string_value = "system")] System, #[sea_orm(string_value = "email")] Email, #[sea_orm(string_value = "sms")] Sms, #[sea_orm(string_value = "webhook")] Webhook, #[sea_orm(string_value = "push")] Push, } #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "notification_status")] pub enum NotificationStatus { #[sea_orm(string_value = "pending")] Pending, #[sea_orm(string_value = "sent")] Sent, #[sea_orm(string_value = "failed")] Failed, #[sea_orm(string_value = "cancelled")] Cancelled, } #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "notification_priority")] pub enum NotificationPriority { #[sea_orm(string_value = "low")] Low, #[sea_orm(string_value = "normal")] Normal, #[sea_orm(string_value = "high")] High, #[sea_orm(string_value = "urgent")] Urgent, } #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "recipient_type")] pub enum RecipientType { #[sea_orm(string_value = "user")] User, #[sea_orm(string_value = "role")] Role, #[sea_orm(string_value = "group")] Group, #[sea_orm(string_value = "external")] External, } ``` ## 系统配置模型 (system_config.rs) ### 实体定义 ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "system_configs")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, #[sea_orm(unique)] pub key: String, pub value: Json, pub description: Option, pub config_type: ConfigType, pub is_encrypted: bool, pub is_system: bool, pub created_at: DateTimeWithTimeZone, pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} impl ActiveModelBehavior for ActiveModel {} ``` ### 配置类型枚举 ```rust #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "config_type")] pub enum ConfigType { #[sea_orm(string_value = "string")] String, #[sea_orm(string_value = "number")] Number, #[sea_orm(string_value = "boolean")] Boolean, #[sea_orm(string_value = "json")] Json, #[sea_orm(string_value = "array")] Array, } ``` ## 关联表模型 ### 用户角色关联 (user_role.rs) ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "user_roles")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub user_id: String, pub role_id: String, pub assigned_by: String, pub assigned_at: DateTimeWithTimeZone, pub expires_at: Option, pub created_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::user::Entity", from = "Column::UserId", to = "super::user::Column::Id" )] User, #[sea_orm( belongs_to = "super::role::Entity", from = "Column::RoleId", to = "super::role::Column::Id" )] Role, } impl ActiveModelBehavior for ActiveModel {} ``` ### 角色权限关联 (role_permission.rs) ```rust #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "role_permissions")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: String, pub role_id: String, pub permission_id: String, pub granted_by: String, pub granted_at: DateTimeWithTimeZone, pub created_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::role::Entity", from = "Column::RoleId", to = "super::role::Column::Id" )] Role, #[sea_orm( belongs_to = "super::permission::Entity", from = "Column::PermissionId", to = "super::permission::Column::Id" )] Permission, } impl ActiveModelBehavior for ActiveModel {} ``` ## 数据库连接和配置 ### 数据库连接 ```rust use sea_orm::*; pub async fn establish_connection(database_url: &str) -> Result { let mut opt = ConnectOptions::new(database_url.to_owned()); opt.max_connections(100) .min_connections(5) .connect_timeout(Duration::from_secs(8)) .acquire_timeout(Duration::from_secs(8)) .idle_timeout(Duration::from_secs(8)) .max_lifetime(Duration::from_secs(8)) .sqlx_logging(true) .sqlx_logging_level(log::LevelFilter::Info); Database::connect(opt).await } ``` ### 迁移管理 ```rust use sea_orm_migration::prelude::*; pub struct Migrator; #[async_trait::async_trait] impl MigratorTrait for Migrator { fn migrations() -> Vec> { vec![ Box::new(m20220101_000001_create_users_table::Migration), Box::new(m20220101_000002_create_roles_table::Migration), Box::new(m20220101_000003_create_permissions_table::Migration), Box::new(m20220101_000004_create_user_roles_table::Migration), Box::new(m20220101_000005_create_role_permissions_table::Migration), Box::new(m20220101_000006_create_flows_table::Migration), Box::new(m20220101_000007_create_flow_versions_table::Migration), Box::new(m20220101_000008_create_flow_executions_table::Migration), Box::new(m20220101_000009_create_schedule_jobs_table::Migration), Box::new(m20220101_000010_create_job_executions_table::Migration), Box::new(m20220101_000011_create_operation_logs_table::Migration), Box::new(m20220101_000012_create_system_logs_table::Migration), Box::new(m20220101_000013_create_notifications_table::Migration), Box::new(m20220101_000014_create_notification_templates_table::Migration), Box::new(m20220101_000015_create_system_configs_table::Migration), ] } } ``` ## 查询构建器 ### 用户查询示例 ```rust use sea_orm::*; /// 查询活跃用户列表 pub async fn find_active_users( db: &DatabaseConnection, page: u64, page_size: u64, ) -> Result<(Vec, u64), DbErr> { let paginator = user::Entity::find() .filter(user::Column::Status.eq(UserStatus::Active)) .filter(user::Column::IsDeleted.eq(false)) .order_by_desc(user::Column::CreatedAt) .paginate(db, page_size); let total = paginator.num_items().await?; let users = paginator.fetch_page(page - 1).await?; Ok((users, total)) } /// 根据用户名查询用户 pub async fn find_user_by_username( db: &DatabaseConnection, username: &str, ) -> Result, DbErr> { user::Entity::find() .filter(user::Column::Username.eq(username)) .filter(user::Column::IsDeleted.eq(false)) .one(db) .await } /// 查询用户及其角色 pub async fn find_user_with_roles( db: &DatabaseConnection, user_id: &str, ) -> Result)>, DbErr> { user::Entity::find_by_id(user_id) .find_with_related(role::Entity) .all(db) .await .map(|results| { results.into_iter().next().map(|(user, roles)| (user, roles)) }) } ``` ### 流程查询示例 ```rust /// 查询已发布的流程 pub async fn find_published_flows( db: &DatabaseConnection, category: Option<&str>, ) -> Result, DbErr> { let mut query = flow::Entity::find() .filter(flow::Column::Status.eq(FlowStatus::Published)) .filter(flow::Column::IsDeleted.eq(false)); if let Some(cat) = category { query = query.filter(flow::Column::Category.eq(cat)); } query.order_by_desc(flow::Column::UpdatedAt).all(db).await } /// 查询流程执行历史 pub async fn find_flow_executions( db: &DatabaseConnection, flow_id: &str, status: Option, page: u64, page_size: u64, ) -> Result<(Vec, u64), DbErr> { let mut query = flow_execution::Entity::find() .filter(flow_execution::Column::FlowId.eq(flow_id)); if let Some(s) = status { query = query.filter(flow_execution::Column::Status.eq(s)); } let paginator = query .order_by_desc(flow_execution::Column::StartTime) .paginate(db, page_size); let total = paginator.num_items().await?; let executions = paginator.fetch_page(page - 1).await?; Ok((executions, total)) } ``` ## 事务处理 ### 事务示例 ```rust use sea_orm::*; /// 创建用户并分配角色(事务) pub async fn create_user_with_roles_tx( db: &DatabaseConnection, user_data: user::ActiveModel, role_ids: Vec, ) -> Result { let txn = db.begin().await?; // 创建用户 let user = user_data.insert(&txn).await?; // 分配角色 for role_id in role_ids { let user_role = user_role::ActiveModel { id: Set(crate::utils::generate_id()), user_id: Set(user.id.clone()), role_id: Set(role_id), assigned_by: Set("system".to_string()), assigned_at: Set(crate::utils::now_fixed_offset()), expires_at: NotSet, created_at: Set(crate::utils::now_fixed_offset()), }; user_role.insert(&txn).await?; } txn.commit().await?; Ok(user) } /// 更新流程状态(事务) pub async fn publish_flow_tx( db: &DatabaseConnection, flow_id: &str, user_id: &str, ) -> Result { let txn = db.begin().await?; // 更新流程状态 let flow = flow::Entity::find_by_id(flow_id) .one(&txn) .await? .ok_or(DbErr::RecordNotFound("流程不存在".to_string()))?; let mut flow: flow::ActiveModel = flow.into(); flow.status = Set(FlowStatus::Published); flow.published_at = Set(Some(crate::utils::now_fixed_offset())); flow.updated_by = Set(Some(user_id.to_string())); flow.updated_at = Set(crate::utils::now_fixed_offset()); let updated_flow = flow.update(&txn).await?; // 记录操作日志 let log = operation_log::ActiveModel { id: Set(crate::utils::generate_id()), user_id: Set(user_id.to_string()), operation: Set("publish_flow".to_string()), resource: Set("flow".to_string()), resource_id: Set(Some(flow_id.to_string())), details: Set(Some(serde_json::json!({ "flow_name": updated_flow.name, "version": updated_flow.version }))), ip_address: NotSet, user_agent: NotSet, status: Set(OperationStatus::Success), error: NotSet, duration_ms: NotSet, created_at: Set(crate::utils::now_fixed_offset()), }; log.insert(&txn).await?; txn.commit().await?; Ok(updated_flow) } ``` ## 性能优化 ### 索引策略 ```sql -- 用户表索引 CREATE INDEX idx_users_username ON users(username); CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_status ON users(status); CREATE INDEX idx_users_created_at ON users(created_at); -- 流程表索引 CREATE INDEX idx_flows_status ON flows(status); CREATE INDEX idx_flows_category ON flows(category); CREATE INDEX idx_flows_created_by ON flows(created_by); CREATE INDEX idx_flows_updated_at ON flows(updated_at); -- 流程执行表索引 CREATE INDEX idx_flow_executions_flow_id ON flow_executions(flow_id); CREATE INDEX idx_flow_executions_status ON flow_executions(status); CREATE INDEX idx_flow_executions_start_time ON flow_executions(start_time); -- 定时任务表索引 CREATE INDEX idx_schedule_jobs_enabled ON schedule_jobs(enabled); CREATE INDEX idx_schedule_jobs_next_run_at ON schedule_jobs(next_run_at); CREATE INDEX idx_schedule_jobs_created_by ON schedule_jobs(created_by); -- 操作日志表索引 CREATE INDEX idx_operation_logs_user_id ON operation_logs(user_id); CREATE INDEX idx_operation_logs_resource ON operation_logs(resource); CREATE INDEX idx_operation_logs_created_at ON operation_logs(created_at); -- 系统日志表索引 CREATE INDEX idx_system_logs_level ON system_logs(level); CREATE INDEX idx_system_logs_source ON system_logs(source); CREATE INDEX idx_system_logs_created_at ON system_logs(created_at); ``` ### 查询优化 ```rust /// 使用预加载优化查询 pub async fn find_users_with_roles_optimized( db: &DatabaseConnection, page: u64, page_size: u64, ) -> Result)>, DbErr> { user::Entity::find() .filter(user::Column::Status.eq(UserStatus::Active)) .filter(user::Column::IsDeleted.eq(false)) .find_with_related(role::Entity) .paginate(db, page_size) .fetch_page(page - 1) .await } /// 使用原生 SQL 优化复杂查询 pub async fn get_user_statistics( db: &DatabaseConnection, ) -> Result { let result = db .query_one(Statement::from_sql_and_values( DbBackend::Postgres, r#" SELECT COUNT(*) as total_users, COUNT(CASE WHEN status = 'active' THEN 1 END) as active_users, COUNT(CASE WHEN status = 'inactive' THEN 1 END) as inactive_users, COUNT(CASE WHEN last_login_at > NOW() - INTERVAL '30 days' THEN 1 END) as recent_active_users FROM users WHERE is_deleted = false "#, vec![], )) .await? .ok_or(DbErr::RecordNotFound("统计数据不存在".to_string()))?; Ok(UserStatistics { total_users: result.try_get("", "total_users")?, active_users: result.try_get("", "active_users")?, inactive_users: result.try_get("", "inactive_users")?, recent_active_users: result.try_get("", "recent_active_users")?, }) } ``` ## 数据验证 ### 模型验证 ```rust use validator::{Validate, ValidationError}; #[derive(Debug, Validate)] pub struct CreateUserRequest { #[validate(length(min = 3, max = 50, message = "用户名长度必须在3-50个字符之间"))] pub username: String, #[validate(length(min = 6, message = "密码长度至少6个字符"))] pub password: String, #[validate(email(message = "邮箱格式不正确"))] pub email: Option, #[validate(length(max = 100, message = "显示名称不能超过100个字符"))] pub display_name: Option, } /// 自定义验证函数 fn validate_cron_expression(cron: &str) -> Result<(), ValidationError> { cron::Schedule::from_str(cron) .map_err(|_| ValidationError::new("invalid_cron_expression"))?; Ok(()) } #[derive(Debug, Validate)] pub struct CreateScheduleJobRequest { #[validate(length(min = 1, max = 100))] pub name: String, #[validate(custom = "validate_cron_expression")] pub cron_expression: String, #[validate(range(min = 0, max = 10))] pub max_retries: i32, } ``` ## 测试支持 ### 测试数据库设置 ```rust #[cfg(test)] mod tests { use super::*; use sea_orm::*; async fn setup_test_db() -> DatabaseConnection { let db = Database::connect("sqlite::memory:").await.unwrap(); // 运行迁移 Migrator::up(&db, None).await.unwrap(); db } async fn create_test_user(db: &DatabaseConnection) -> user::Model { let user = user::ActiveModel { id: Set(crate::utils::generate_id()), username: Set("test_user".to_string()), password_hash: Set("hashed_password".to_string()), email: Set(Some("test@example.com".to_string())), display_name: Set(Some("Test User".to_string())), avatar: NotSet, status: Set(UserStatus::Active), last_login_at: NotSet, login_count: Set(0), is_deleted: Set(false), created_at: Set(crate::utils::now_fixed_offset()), updated_at: Set(crate::utils::now_fixed_offset()), }; user.insert(db).await.unwrap() } #[tokio::test] async fn test_create_user() { let db = setup_test_db().await; let user = create_test_user(&db).await; assert_eq!(user.username, "test_user"); assert_eq!(user.status, UserStatus::Active); assert!(!user.is_deleted); } #[tokio::test] async fn test_user_role_relationship() { let db = setup_test_db().await; // 创建用户和角色 let user = create_test_user(&db).await; let role = create_test_role(&db).await; // 创建用户角色关联 let user_role = user_role::ActiveModel { id: Set(crate::utils::generate_id()), user_id: Set(user.id.clone()), role_id: Set(role.id.clone()), assigned_by: Set("system".to_string()), assigned_at: Set(crate::utils::now_fixed_offset()), expires_at: NotSet, created_at: Set(crate::utils::now_fixed_offset()), }; user_role.insert(&db).await.unwrap(); // 验证关联关系 let user_with_roles = user::Entity::find_by_id(&user.id) .find_with_related(role::Entity) .all(&db) .await .unwrap(); assert_eq!(user_with_roles.len(), 1); assert_eq!(user_with_roles[0].1.len(), 1); assert_eq!(user_with_roles[0].1[0].id, role.id); } } ``` ## 最佳实践 ### 模型设计 - **主键设计**: 使用字符串类型的 UUID 作为主键 - **外键约束**: 正确定义外键关系和级联操作 - **索引优化**: 为查询字段添加合适的索引 - **软删除**: 重要数据使用软删除而非物理删除 - **审计字段**: 包含创建时间、更新时间等审计信息 ### 查询优化 - **预加载**: 使用 `find_with_related` 避免 N+1 查询问题 - **分页查询**: 使用 `paginate` 进行分页查询 - **索引使用**: 确保查询条件使用了合适的索引 - **原生 SQL**: 复杂查询使用原生 SQL 优化性能 ### 事务管理 - **原子性**: 确保相关操作在同一事务中执行 - **一致性**: 维护数据的完整性约束 - **隔离性**: 避免并发事务的相互干扰 - **持久性**: 确保提交的事务持久保存 ### 错误处理 - **类型安全**: 使用 `Result` 处理数据库错误 - **错误分类**: 区分不同类型的数据库错误 - **错误恢复**: 提供合适的错误恢复机制 - **日志记录**: 记录详细的错误信息用于调试 ### 缓存策略 - **查询缓存**: 缓存频繁查询的结果 - **实体缓存**: 缓存常用的实体对象 - **失效策略**: 合理的缓存失效机制 - **一致性**: 保证缓存与数据库的一致性 ## 总结 数据模型层是 UdminAI 系统的数据基础,通过 SeaORM 提供了类型安全、高性能的数据访问接口。模型设计遵循了关系型数据库的最佳实践,包括合理的索引设计、事务管理、数据验证和性能优化。 主要特点: - **类型安全**: 使用 Rust 的类型系统确保数据安全 - **关系映射**: 正确定义实体间的关联关系 - **性能优化**: 通过索引和查询优化提升性能 - **事务支持**: 提供完整的事务管理机制 - **测试友好**: 支持单元测试和集成测试 - **扩展性**: 易于扩展和维护的模型设计 通过这套完整的数据模型设计,UdminAI 能够高效、安全地管理用户数据、流程数据、任务数据和系统数据,为上层业务逻辑提供可靠的数据支撑。