作用域(Scope)
大约 2 分钟
作用域(Scope)
Scope 是对常见查询条件的可复用封装。Sea-ORM 没有全局 Scope 的语法糖,但可通过扩展 Trait/函数实现“本地/全局”作用域。
本地作用域(函数返回 Condition/Select)
use sea_orm::{Condition, QueryFilter, ColumnTrait};
fn not_deleted() -> Condition {
Condition::all().add(entity::sys_user::Column::DeletedAt.is_null())
}
fn keyword_like(kw: &str) -> Condition {
use sea_orm::sea_query::Expr;
Condition::any()
.add(Expr::col(entity::sys_user::Column::Username).like(format!("%{kw}%")))
.add(Expr::col(entity::sys_user::Column::RealName).like(format!("%{kw}%")))
}
// 使用
let list = entity::sys_user::Entity::find()
.filter(not_deleted())
.filter(keyword_like("alice"))
.all(&db).await?;
扩展 Trait(链式调用)
use sea_orm::{Select, QueryFilter, ColumnTrait};
pub trait UserScopes: Sized {
fn not_deleted(self) -> Self;
fn in_dept(self, dept_id: i64) -> Self;
}
impl UserScopes for Select<entity::sys_user::Entity> {
fn not_deleted(self) -> Self {
self.filter(entity::sys_user::Column::DeletedAt.is_null())
}
fn in_dept(self, dept_id: i64) -> Self {
self.filter(entity::sys_user::Column::DeptId.eq(dept_id))
}
}
// 用法
let users = entity::sys_user::Entity::find().not_deleted().in_dept(1001).all(&db).await?;
数据权限 Scope
fn data_scope_cond(c: &Claims) -> Condition {
match c.data_scope.as_deref() {
Some("ALL") => Condition::all(),
Some("DEPT") => Condition::all().add(entity::sys_user::Column::DeptId.eq(c.dept_id)),
Some("SELF") => Condition::all().add(entity::sys_user::Column::Id.eq(c.sub)),
_ => Condition::all(),
}
}
let users = entity::sys_user::Entity::find().filter(data_scope_cond(&claims)).all(&db).await?;
多租户 Scope
fn tenant_scope(tid: i64) -> Condition {
Condition::all().add(entity::any_table::Column::TenantId.eq(tid))
}
动态排序与安全
- 传入“排序字段/方向”时,使用白名单映射到 Column,避免 SQL 注入
enum UserOrderBy { Id, Username, CreatedAt }
小结
- 将重复条件封装成函数/扩展 Trait
- 数据权限/租户隔离写成 Scope 并在服务层统一应用
- 排序/分页等共性逻辑也可放入作用域或统一工具