我正在尝试使用 Diesel 从数据库加载关联。我定义了以下模型:
#[derive(Identifiable, Queryable, PartialEq, Debug)]
#[table_name = "contacts"]
pub struct Contact {
pub id: i32,
pub firstname: String,
pub lastname: String,
}
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Contact)]
#[table_name = "emails"]
pub struct Email {
pub id: i32,
pub contact_id: i32,
pub label: String,
pub email: String,
}
Run Code Online (Sandbox Code Playgroud)
现在我尝试使用以下代码获取所有联系人及其关联的电子邮件:
let result = match contacts::table
.inner_join(emails::table)
.load::<models::Contact, Vec<models::Email>>(&self.conn)
{
Ok(rows) => rows,
Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "Database error")),
};
Run Code Online (Sandbox Code Playgroud)
但这是行不通的。该错误与不满足的特征界限有关:
error[E0107]: wrong number of type arguments: expected 1, found 2
--> src/db.rs:44:38
|
44 | .load::<models::Contact, Vec<models::Email>>(&self.conn) {
| ^^^^^^^^^^^^^^^^^^ unexpected type argument
error[E0277]: the trait bound `(i32, std::string::String, std::string::String): diesel::Queryable<((diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text), (diesel::sql_types::Integer, diesel::sql_types::Nullable<diesel::sql_types::Integer>, diesel::sql_types::Text, diesel::sql_types::Text)), _>` is not satisfied
--> src/db.rs:44:14
|
44 | .load::<models::Contact, Vec<models::Email>>(&self.conn) {
| ^^^^ the trait `diesel::Queryable<((diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text), (diesel::sql_types::Integer, diesel::sql_types::Nullable<diesel::sql_types::Integer>, diesel::sql_types::Text, diesel::sql_types::Text)), _>` is not implemented for `(i32, std::string::String, std::string::String)`
|
= help: the following implementations were found:
<(A, B, C) as diesel::Queryable<(SA, SB, SC), __DB>>
<(A, B, C) as diesel::Queryable<diesel::sql_types::Record<(SA, SB, SC)>, diesel::pg::Pg>>
= note: required because of the requirements on the impl of `diesel::Queryable<((diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text), (diesel::sql_types::Integer, diesel::sql_types::Nullable<diesel::sql_types::Integer>, diesel::sql_types::Text, diesel::sql_types::Text)), _>` for `models::Contact`
= note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, models::Contact>` for `diesel::query_builder::SelectStatement<diesel::query_source::joins::JoinOn<diesel::query_source::joins::Join<schema::contacts::table, schema::emails::table, diesel::query_source::joins::Inner>, diesel::expression::operators::Eq<diesel::expression::nullable::Nullable<schema::emails::columns::contact_id>, diesel::expression::nullable::Nullable<schema::contacts::columns::id>>>>`
Run Code Online (Sandbox Code Playgroud)
我缺少什么?
正如评论中所解决的,.load()只需要 1 个类型参数。如果您要为每行加载多种类型,则需要将它们组合成一个元组:
let result = match contacts::table
.inner_join(emails::table)
.load::<(models::Contact, models::Email)>(&self.conn)
Run Code Online (Sandbox Code Playgroud)
当查询变得更加复杂时,您最终可能会加载通常(A, B, (C, Option<D>)反映组成查询的 JOIN 和 SELECT 的嵌套性的类型。
您还会注意到,Email记录不是以Vec平连接的形式返回,而是与其关联的Contact记录一起返回。您几乎总是会看到数据以扁平化的行形式生成,而不是反序列化为复杂的结构。从diesel::associations:
在 Diesel 中,数据及其关联被认为是分开的。如果您想传递用户及其所有帖子,则该类型为
(User, Vec<Post>).
所以这甚至没有利用柴油机的“协会”。从以下位置获取所有电子邮件,看起来会像这样contact:
Email::belonging_to(&contact).load::<Email>()
Run Code Online (Sandbox Code Playgroud)