SeaORM 2.0.0-rc.31 变更解读:`ne_all` 条件、`model_attrs` 宏定制、`TextUuid` 类型列与 `COUNT(*)` 溢出修复
后端数据库ORM【免费下载链接】sea-orm A powerful relational ORM for Rust项目地址https://gitcode.com/gh_mirrors/se/sea-orm点击查看免费下载SeaORM 2.0.0-rc.31发布于 2.0.0-rc.30 之后是 2.0 系列迈向稳定版过程中的一次功能与稳定性迭代一方面为查询条件、宏派生与类型系统新增能力另一方面修复了 MySQL / SQLite 上COUNT(*)的整数溢出隐患。本文以该变更日志为骨架结合仓库源码逐一拆解这些改动背后的实现细节与使用方式帮助读者在升级到 rc.31 后快速掌握新 API 并规避兼容性陷阱。新特性ne_all条件方法补全 PostgreSQL 数组取反查询rc.31 为ColumnTrait新增了ne_all方法用于对多个值做“不等于任意一个”的取反查询与既有的eq_any形成互补。ne_all的语义与生成 SQL从源码看ne_all是eq_any的“相反操作”等价于is_not_in。其实现位于 src/entity/column.rs#[cfg(feature postgres-array)] fn ne_allV, I(self, v: I) - Expr where V: IntoValue sea_query::postgres_array::NotU8, I: IntoIteratorItem V, { use sea_query::extension::postgres::PgFunc; let values: VecValue v.into_iter().map(|v| v.into()).collect(); if let Some(first) values.first() { Expr::col(self.as_column_ref()).ne(PgFunc::all(Value::Array( first.array_type(), Some(Box::new(values)), ))) } else { Expr::col(self.as_column_ref()).is_not_in(std::iter::empty::V()) } }注意两点关键行为空集合的边界语义当传入的迭代器为空时ne_all退化为is_not_in(空集)生成WHERE 1 1而非恒假条件与eq_any空集生成WHERE 1 2的行为对称保证“全部不匹配空集合”逻辑恒真。这一点在源码的 doctest 中有明确断言src/entity/column.rs。仅限 PostgreSQL该方法是 PostgreSQL 数组扩展的一部分由postgres-arrayfeature 门控。它利用PgFunc::all生成 ALL(ARRAY [...])语法例如cake::Column::Id.ne_all(vec![4, 5])会编译为WHERE cake.id ALL(ARRAY [4,5])。与eq_any的对比使用eq_any同样位于 src/entity/column.rs生成 ANY(ARRAY [...])。两者搭配可在一条查询中表达“匹配任一”与“不匹配任一”两种集合语义// 匹配任意一个 cake::Entity::find() .filter(cake::Column::Id.eq_any(vec![4, 5])); // 不匹配任意一个rc.31 新增 cake::Entity::find() .filter(cake::Column::Id.ne_all(vec![4, 5]));泛型边界放宽eq_any/ne_all兼容性提升变更日志同时提到“放宽了eq_any/ne_all的 trait bounds”并依赖最新版sea-query。结合实现可以看出方法签名中V: IntoValue sea_query::postgres_array::NotU8的组合边界NotU8用于排除歧义的u8数组类型使得更多标量类型可以直接传入集合迭代器而无需手动构造Value。升级提示使用这两个方法前请同步升级sea-query依赖否则可能出现 trait bound 不满足的编译错误。新特性model_attrs/model_ex_attrs自定义派生属性rc.31 为#[sea_orm::model]宏引入了model_attrs与model_ex_attrs两个属性允许把自定义 derive 和 attribute 透传给生成的Model与ModelEx结构体。宏展开原理该功能在 sea-orm-macros/src/derives/model_ex.rs 中实现。宏展开流程如下遍历输入结构体上的所有属性凡是#[sea_orm(...)]之外的属性如#[derive(TS)]会被同时收进model_attrs与inherited_model_ex_attrs第 31-35 行解析#[sea_orm(model_attrs(...))]与#[sea_orm(model_ex_attrs(...))]括号内的嵌套 meta通过parse_quote!(#[#m])逐个转换成真正的Attribute分别存入model_attrs与model_ex_attrs第 40-56 行展开时model_attrs前缀在Model结构体上inherited_model_ex_attrs与model_ex_attrs前缀在ModelEx结构体上第 151-166 行。其中inherited_model_ex_attrs还会经过一轮过滤自动剔除Eq嵌套关系可能包含非Eq字段无法安全转发并把DeriveEntityModel替换为DeriveModelEx/DeriveActiveModelEx第 89-115 行。典型用法定制 TypeScript 接口名变更日志给出了配合ts-rs生成 TypeScript 类型、并重命名接口的示例#[sea_orm::model] #[derive(TS, ...)] #[sea_orm(model_attrs(ts(rename Fruit)))] #[sea_orm(model_ex_attrs(ts(rename FruitEx)))] struct Model { ... }展开后Model获得#[ts(rename Fruit)]、ModelEx获得#[ts(rename FruitEx)]从而在前端类型导出中获得自定义接口名。除此之外它同样可用于注入serde、Clone、Debug等任意 derive 或 attribute为同一实体派生“展示用”与“完整关联用”两套结构体提供了更灵活的定制入口。新特性TextUuid类型列#2717rc.31 为TextUuid增加了类型化列typed column支持。TextUuid是 SeaORM 内置的 UUID 字符串包装类型定义于 src/value/text_uuid.rs内部持有uuid::Uuid以字符串形式与数据库交互并实现了ValueType、TryGetable、TryFromU64用于主键场景等 trait。类型化列位于 src/entity/column/types.rs 的TextUuidColumnE并基于 src/entity/column/types/with_uuid.rs 中的bind_oper!/bind_oper_2!/bind_vec_func!生成全套运算符bind_oper!(pub eq, eq, type TextUuid); bind_oper!(pub ne, ne, type TextUuid); bind_oper!(pub gt, gt, type TextUuid); bind_oper!(pub gte, gte, type TextUuid); bind_oper!(pub lt, lt, type TextUuid); bind_oper!(pub lte, lte, type TextUuid); bind_oper_2!(pub between, between, type TextUuid); bind_oper_2!(pub not_between, not_between, type TextUuid); bind_oper!(pub if_null, if_null, type TextUuid); bind_vec_func!(pub is_in, is_in, type TextUuid); bind_vec_func!(pub is_not_in, is_not_in, type TextUuid);这意味着以TextUuid为主键或普通列的实体现在可以用强类型方式书写过滤条件例如entity::Column::Uuid.eq(some_uuid_text)、is_in(vec![...])等无需手工做字符串/Uuid转换减少类型错误并提升可读性。Bug 修复COUNT(*)在 MySQL / SQLite 上的溢出问题#2944rc.31 修复了一个在大数据集下可能静默出错的隐患COUNT(*)在所有后端统一返回i64。背景是 MySQL 的COUNT(*)返回BIGINT64 位而此前 SeaORM 将其按i32读取当表行数超过 21 亿时会发生溢出。rc.31 起统一按i64解析。仓库中的文档示例已同步更新例如 src/executor/select.rs 中的 doctest 使用Into::Value::into(2i64)构造计数结果并将结果类型声明为Vec(String, i64)配合cake::Column::Id.count()与into_values::_, QueryAs()完成分组计数查询let res: Vec(String, i64) cake::Entity::find() .select_only() .column_as(cake::Column::Name, QueryAs::CakeName) .column_as(cake::Column::Id.count(), QueryAs::NumOfCakes) .group_by(cake::Column::Name) .into_values::_, QueryAs() .all(db) .await?;升级影响如果你此前将计数查询结果绑定到i32变量升级到 rc.31 后需要把目标类型改为i64或让类型推导自动适配否则会出现类型不匹配的编译错误。Bug 修复Proxy 错误处理#2935rc.31 修复了ProxyDatabase的错误处理路径。代理模式允许在 Rust 侧自定义数据库实现例如转发到远程服务其核心 trait 定义于 src/database/proxy.rsquery/execute返回Result_, DbErrping用于探测数据库可用性并应返回错误以标识不可用。本次修复确保了代理层在查询失败、执行失败等场景下能够正确传播DbErr而不是被吞掉或错误转换从而让上层拿到准确的错误信息。如果项目通过ProxyDatabaseTrait实现自定义数据源建议升级后补充针对异常路径的回归测试。改进移除原始字符串哈希#2381变更日志还提到一次内部重构“移除原始字符串哈希以提升可读性”。这类改动通常发生在标识符生成、内部名称编码等环节——将原先基于HashSet/ 哈希去重或哈希键控的不可读字符串替换为更直观的生成逻辑。该改动不改变对外 API但会减少--release下二进制或诊断信息中出现的不可读哈希字符串属于对开发者友好的内部整理。若你的项目依赖 SeaORM 内部行为例如宏生成结构体的Debug输出建议在升级后快速跑一遍测试确认无回归。升级建议与总结综合 rc.31 的变更升级时建议依次确认同步升级sea-queryeq_any/ne_all的 trait bound 放宽依赖最新sea-query检查计数查询的目标类型COUNT(*)结果统一为i64排查原先绑定到i32的代码按需使用新 APIPostgreSQL 用户可引入ne_all简化取反集合过滤使用ts-rs、serde等派生库的实体可通过model_attrs/model_ex_attrs定制派生属性UUID 字符串主键场景可借助TextUuidColumn获得类型化运算符回归代理与计数场景若使用了ProxyDatabase或大表计数优先验证错误传播与数值范围。整体来看rc.31 延续了 SeaORM 2.0 系列“类型安全 后端一致”的路线既在查询层补齐了集合取反能力也在宏层放开了派生定制空间同时修复了影响大数据量场景的计数溢出问题是向 2.0 稳定版推进过程中值得关注的一个版本。赞分享后端数据库ORM【免费下载链接】sea-orm A powerful relational ORM for Rust项目地址https://gitcode.com/gh_mirrors/se/sea-orm点击查看免费下载相关推荐SeaORM 2.0.0-rc.28 版本解读ActiveValue 条件更新、主键 auto_increment 修正与 Postgres 事务配置修复SeaORM 2.0.0 rc.28 版本解读ActiveValue 条件更新、主键 auto_increment 修正与 Postgres 事务配置修复 本后端数据库ORMSeaORM 2.0.0-rc.29 版本解读分布式 Tracing 支持、TextUuid 与 TryInsert 新特性全解析SeaORM 2.0.0 rc.29 版本解读分布式 Tracing 支持、TextUuid 与 TryInsert 新特性全解析 本篇文章以 SeaORM后端数据库ORMmidir Android开发实战API 29平台上的MIDI应用构建指南midir Android开发实战API 29平台上的MIDI应用构建指南 midir是一个基于Rust的跨平台实时MIDI处理库为Android API后端数据库ORM上一篇为什么OpenRadar是毫米波雷达数据处理的最佳Python方案下一篇soci-snapshotter CLI命令详解轻松掌握容器镜像懒加载创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考