Diesel泛型更新方法编译报错求助:类型不匹配问题
解决Diesel泛型更新方法的类型不匹配问题及抽象实现参考
错误原因分析
编译错误的核心是更新语句的目标表与变更集的目标表类型不匹配:
diesel::update(current_model)接收的是&Model类型,它对应的目标表是<&'m Model as HasTable>::Tablenew_model是Model类型,它的AsChangeset::Target被绑定为Tab参数- 编译器无法确认这两个表类型是同一个,因此抛出类型不匹配错误
修复后的泛型更新实现
下面是简化并修复约束后的代码,去掉了冗余绑定,明确了表类型的一致性:
use diesel::pg::Pg; use diesel::{AsChangeset, HasTable, Identifiable, IntoUpdateTarget, Queryable, Table}; use diesel::pg::PgConnection; use diesel::result::Error; pub fn update<'m, Model, Tab>( conn: &PgConnection, current_model: &'m Model, new_model: Model, ) -> Result<Model, Error> where // 表类型的基础约束 Tab: Table + HasTable<Table = Tab>, // Model的核心约束:能作为Tab的变更集,且能从Tab的查询结果中反序列化 Model: AsChangeset<Target = Tab> + Queryable<<Tab as Table>::AllColumns::SqlType, Pg> + HasTable<Table = Tab>, // 引用类型的约束:能唯一标识记录,能作为更新目标,且对应表为Tab &'m Model: Identifiable + IntoUpdateTarget + HasTable<Table = Tab>, // 必要的查询片段约束(Diesel内部需要) <&'m Model as IntoUpdateTarget>::WhereClause: diesel::QueryFragment<Pg>, <Model as AsChangeset>::Changeset: diesel::QueryFragment<Pg>, { diesel::update(current_model) .set(new_model) .get_result(conn) }
关键修复点
- 新增
&'m Model: HasTable<Table = Tab>约束,强制引用类型对应的表与Model变更集的目标表一致 - 移除了重复的
AsChangeset<Target = Tab>绑定和不必要的Queryable冗余约束 - 删除了无用的
Tab参数(通过trait约束已经完成Model与Tab的关联,无需传入实例) - 去掉了不安全的
unwrap(),直接返回get_result的Result
抽象更新操作的实现参考
基于Diesel实现通用更新操作,核心是利用它提供的trait体系,推荐以下实践:
- 依赖
Identifiabletrait:这是Diesel定位单条记录的标准方式,确保更新操作能生成正确的WHERE子句 - 最小化约束:只保留必要的trait绑定(
AsChangeset、IntoUpdateTarget、Queryable等),避免过度泛化导致的复杂约束 - 封装为trait方法:可以给所有符合条件的
Model实现一个默认的更新方法,比如:pub trait Updateable { type Table: Table; fn update(self, conn: &PgConnection, new_model: Self) -> Result<Self, Error> where Self: AsChangeset<Target = Self::Table> + Queryable<<Self::Table as Table>::AllColumns::SqlType, Pg> + HasTable<Table = Self::Table>, for<'m> &'m Self: Identifiable + IntoUpdateTarget + HasTable<Table = Self::Table>, <&'_ Self as IntoUpdateTarget>::WhereClause: diesel::QueryFragment<Pg>, <Self as AsChangeset>::Changeset: diesel::QueryFragment<Pg>; } impl<T> Updateable for T { type Table = <Self as HasTable>::Table; fn update(self, conn: &PgConnection, new_model: Self) -> Result<Self, Error> { diesel::update(&self) .set(new_model) .get_result(conn) } } - 避免硬编码数据库类型:如果需要支持多数据库,可以将
Pg替换为泛型的DB: Backend,进一步提升通用性
内容的提问来源于stack exchange,提问作者Dmitrii Sergeev
相关产品推荐
相关产品推荐

