Diesel 的 find 或 filter 的一般用法来执行删除
Posted
技术标签:
【中文标题】Diesel 的 find 或 filter 的一般用法来执行删除【英文标题】:Generic usage of Diesel's find or filter to perform deletions 【发布时间】:2019-08-08 08:31:24 【问题描述】:我正在尝试使用通用 Diesel 函数来缩减重复性任务,例如基于主键删除一行。
我获得了相对较快的通用行插入,但删除查询似乎相当困难。我尝试使用find()
和filter()
来解决它。我也咨询过类似的话题1和2,都没有成功。
使用find
use diesel::prelude::*;
use diesel::query_dsl::methods::FindDsl;
use std::error::Error;
pub struct DB
conn: SqliteConnection,
impl DB
pub fn remove_row<'a, T>(&self, table: T, pk: &'a str) -> Result<(), Box<Error>>
where
T: FindDsl<&'a str>,
<T as FindDsl<&'a str>>::Output: diesel::Identifiable,
<T as FindDsl<&'a str>>::Output: diesel::associations::HasTable,
diesel::delete(table.find(pk)).execute(&self.conn)?;
Ok(())
这会导致以下我无法解释的错误:
error[E0275]: overflow evaluating the requirement `_: std::marker::Sized`
--> src/db/mod.rs:103:3
|
103 | diesel::delete (table.find (pk)) .execute (&self.conn) ?;
| ^^^^^^^^^^^^^^
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
= note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<_>` for `<<<T as diesel::query_dsl::filter_dsl::FindDsl<&'a str>>::Output as diesel::associations::HasTable>::Table as diesel::query_builder::AsQuery>::Query`
= note: required because of the requirements on the impl of `diesel::query_builder::IntoUpdateTarget` for `<T as diesel::query_dsl::filter_dsl::FindDsl<&'a str>>::Output`
= note: required by `diesel::delete`
使用filter()
use diesel::prelude::*;
use diesel::query_dsl::methods::FilterDsl;
use std::error::Error;
pub struct DB
conn: SqliteConnection,
impl DB
pub fn remove_row<T>(&self, table: T, pk: &str) -> Result<(), Box<Error>>
where
T: FilterDsl<bool>,
<T as FilterDsl<bool>>::Output: diesel::Identifiable,
<T as FilterDsl<bool>>::Output: diesel::associations::HasTable,
diesel::delete(table.filter(id.eq(pk))).execute(&self.conn)?;
Ok(())
除了前面的错误,这里还有一条关于id
在数据结构中未知的错误信息。我可以考虑一个缺失的特征,它可以保证该行的存在,但我还没有发现任何关于这种行为的信息。
error[E0425]: cannot find value `id` in this scope
--> src/db/mod.rs:117:33
|
117 | diesel::delete (table.filter (id.eq (pk))) .execute (&self.conn) ?;
| ^^ not found in this scope
help: possible candidates are found in other modules, you can import them into scope
|
4 | use crate::db::schema::events::columns::id;
|
4 | use crate::db::schema::ignored_events::columns::id;
|
4 | use crate::db::schema::locations::columns::id;
|
4 | use std::process::id;
error[E0275]: overflow evaluating the requirement `_: std::marker::Sized`
--> src/db/mod.rs:117:3
|
117 | diesel::delete (table.filter (id.eq (pk))) .execute (&self.conn) ?;
| ^^^^^^^^^^^^^^
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
= note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<_>` for `<<<T as diesel::query_dsl::filter_dsl::FilterDsl<bool>>::Output as diesel::associations::HasTable>::Table as diesel::query_builder::AsQuery>::Query`
= note: required because of the requirements on the impl of `diesel::query_builder::IntoUpdateTarget` for `<T as diesel::query_dsl::filter_dsl::FilterDsl<bool>>::Output`
= note: required by `diesel::delete`
【问题讨论】:
【参考方案1】:泛型并不容易。像 Diesel 这样高度通用的系统中的泛型更加困难。
我更喜欢将步骤分解成非常个小部分,并尽可能避免链接。有了这个,您基本上需要为每个步骤添加特征边界。一件好事是为非常复杂的特征界限使用/创建类型别名。 Diesel provides a number of these,您可以制作自己的特殊用途。
在查看生成的错误消息时,我主要查看的是被调用的函数/方法所描述的类型界限。
逐点:
.find
来自FindDsl
。
delete
需要 IntoUpdateTarget
。
调用delete
的结果类型是DeleteStatement
,参数化为T::Table
和T::WhereClause
。这是自定义类型别名 DeleteFindStatement
。
.execute
来自ExecuteDsl
。
use diesel::
associations::HasTable,
helper_types::Find,
query_builder::DeleteStatement, IntoUpdateTarget,
query_dsl::methods::ExecuteDsl,
;
type DeleteFindStatement<F> =
DeleteStatement<<F as HasTable>::Table, <F as IntoUpdateTarget>::WhereClause>;
impl DB
pub fn remove_row<Tbl, Pk>(&self, table: Tbl, pk: Pk) -> Result<(), Box<Error>>
where
Tbl: FindDsl<Pk>,
Find<Tbl, Pk>: IntoUpdateTarget,
DeleteFindStatement<Find<Tbl, Pk>>: ExecuteDsl<SqliteConnection>,
let find = table.find(pk);
let delete = diesel::delete(find);
delete.execute(&self.conn)?;
Ok(())
您需要自己尝试基于filter
的版本,因为您没有提供足够的代码来判断id
应该是什么;如您的错误消息所示。
另见:
How to define a function-local type alias of the function's type parameters (or their associated types)?将主键设为通用是否有好处,即使它在所有情况下都是
&str
?
对我来说,使用泛型类型比插入一堆泛型生命周期参数更容易。
【讨论】:
好的,所以插入货物错误中提到的特征边界在这里并没有真正的帮助。我基本上了解您在这里所做的事情,但遗憾的是,即使在执行小步骤时,我也看不到从这些错误消息到您提出的解决方案的可理解路径。所以猜测一个人只需要更多地了解 Diesel 的工作原理。不过,非常感谢您的帮助!在filter
变体中,所有表都有一个主键“id:String”列。这需要如何指定?即使在所有情况下都是&str
,将主键设为通用是否有好处?以上是关于Diesel 的 find 或 filter 的一般用法来执行删除的主要内容,如果未能解决你的问题,请参考以下文章
IE8 DOM 转换 XML 并从 jQuery find() 或 filter() 不返回任何内容
使用 Diesel 的 `belongs_to` 属性时“使用未声明的类型或模块”
如何从仅返回 1 或 0 条记录的 Diesel 查询中获取 Option<T> 而不是 Option<Vec<T>>?