柴油中的显式 JOIN ON

Posted

技术标签:

【中文标题】柴油中的显式 JOIN ON【英文标题】:Explicit JOIN ON in diesel 【发布时间】:2021-07-06 08:43:23 【问题描述】:

我有两个表要加入、过滤并仅选择 Diesel 中的特定列:

contest_users::dsl::contest_users
    .inner_join(
        contests::table.on(contest_users::contest_id.eq(contests::contest_id)),
    )
    .filter(contest_users::user_id.eq(42))
    .select((contests::columns::contest_id,))

这是一个repo with a repro(见代码中的 cmets)。

我找到了一些可以编译的解决方案,但我仍然想知道是否可以在不使用 joinable! 的情况下命名此查询的类型。

下面的东西是可编译的:

pub fn join_and_filter() -> diesel::dsl::Filter<
    diesel::dsl::Select<
        diesel::dsl::InnerJoin<contest_users::table, contests::table>,
        (contests::columns::contest_id,),
    >,
    diesel::expression::operators::Eq<
        contest_users::columns::user_id,
        diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>,
    >,
> 
    joinable!(contest_users -> contests (contest_id));

    contest_users::dsl::contest_users
        .inner_join(
            contests::table.on(contest_users::contest_id.nullable().eq(contests::contest_id.nullable())),
        )
        .filter(contest_users::user_id.eq(42))
        .select((contests::columns::contest_id,))

虽然以下(没有joinable,即使我有明确的.on())会导致编译错误:

pub fn join_and_filter() -> diesel::dsl::Filter<
    diesel::dsl::Select<
        diesel::dsl::InnerJoin<contest_users::table, contests::table>,
        (contests::columns::contest_id,),
    >,
    diesel::expression::operators::Eq<
        contest_users::columns::user_id,
        diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>,
    >,
> 
    contest_users::dsl::contest_users
        .inner_join(
            contests::table.on(contest_users::contest_id.eq(contests::contest_id))
        )
        .filter(contest_users::user_id.eq(42))
        .select((contests::columns::contest_id,))

error[E0277]: the trait bound `contest_users::table: JoinTo<contests::table>` is not satisfied
  --> src/main.rs:69:1
   |
69 | / pub fn join_and_filter() -> diesel::dsl::Filter<
70 | |     diesel::dsl::Select<
71 | |         diesel::dsl::InnerJoin<contest_users::table, contests::table>,
72 | |         (contests::columns::contest_id,),
...  |
84 | |         .select((contests::columns::contest_id,))
85 | | 
   | |_^ the trait `JoinTo<contests::table>` is not implemented for `contest_users::table`
   |
   = help: the following implementations were found:
             <contest_users::table as JoinTo<JoinOn<Join, On>>>
             <contest_users::table as JoinTo<diesel::query_builder::BoxedSelectStatement<'a, QS, ST, DB>>>
             <contest_users::table as JoinTo<diesel::query_builder::SelectStatement<F, S, D, W, O, L, Of, G>>>
             <contest_users::table as JoinTo<diesel::query_source::joins::Join<Left, Right, Kind>>>
   = note: required because of the requirements on the impl of `JoinWithImplicitOnClause<contests::table, Inner>` for `contest_users::table`

【问题讨论】:

【参考方案1】:

我找到了一些可以编译的解决方案,但我仍然想知道是否可以在不使用 joinable 的情况下命名此查询的类型!。

根据文档diesel::dsl::InnerJoin 定义如下:

type InnerJoin<Source, Rhs> = <Source as JoinWithImplicitOnClause<Rhs, Inner>>::Output;

这和声明

表示.inner_join(rhs)的返回类型

表示此类型旨在与不带显式 on 子句的 inner_join 语句一起使用。

现在这引发了如何正确指定返回类型的问题,因为柴油 1.4 不会通过 diesel::dsl 导出相应的类型。柴油机主分支的文档表明那里存在相应的type,但类型定义中的相关类型并未作为公共 API 的一部分在 1.4 版本中公开。这表明目前无法使用现有的柴油版本命名此类型。

【讨论】:

以上是关于柴油中的显式 JOIN ON的主要内容,如果未能解决你的问题,请参考以下文章

运算符重载中的显式构造?

Scala 中的显式类型转换

C++17 中的显式默认构造函数

Swift 2 中的显式老式错误处理

使用 DataContractSerializer 的接口中的显式类型

仅当使用列列表并且 IDENTITY_INSERT 为 ON [重复] 时,才能指定表“客户”中标识列的显式值