如何在 Eloquent 中查询特定关系

Posted

技术标签:

【中文标题】如何在 Eloquent 中查询特定关系【英文标题】:How to query specific relation(s) in Eloquent 【发布时间】:2020-11-24 10:49:59 【问题描述】:

我有这样结构的数据库表(有点像国际会议论文集):

languages (id, abbr)

papers (id, title, fulltext, language_id)

keywords (id)
keyword_translations (id, label, keyword_id, language_id) // cointains language-specific tranlation of given keyword
paper_keywords (id, paper_id, keyword_id) //M:N relation between papers and keywords

usage (id)
usage_translations (id, label, usage_id, language_id)
paper_usage (id, paper_id, usage_id) //M:N relation between papers and usages

这描述了论文及其元数据。所需的 UI 应该是多种语言的,因此有“翻译表”。

在我的 Eloquent 模型中,我已经建立了所有简单的 M:N belonsToMany 关系,例如“所有使用此设备的论文”。模型如下所示:

class Paper extends Model

    public function keywords()
    
        return $this->belongsToMany('App\Keyword', 'paper_keyword');
    

    public function usages()
    
        return $this->belongsToMany('App\Usage', 'paper_usage');
    

class Keyword extends Model

    public function translations()
    
        return $this->hasMany('App\KeywordTranslation');
    

    public function papers()
    
        return $this->belongsToMany('App\Paper', 'paper_keyword');
    

……用法相同。

现在我需要查询由其 ID 给出的特定论文(或者可能是多篇论文)以及属于它的所有关键字和用法 - 但仅具有给定 language_id 的那些。 (这个language_id只涉及翻译(对于UI),论文可以有不同的language_id。一个典型的例子是我想看一篇斯洛伐克语或波兰语的论文,但是UI是捷克语,所以应该有捷克语关键字和其他元数据的标签)。

我知道我可以做到App\Paper::with(['usages.translations', 'keywords.translations'])->find(1605);,但这会带来所有翻译,而不仅仅是特定于语言的翻译。在纯 SQL 中,我会简单地使用一些别名连接所有表并查询 WHERE keyword_translations.language_id = 1,但在 Eloquent 中?

我想避免需要修改数据库的解决方案。

【问题讨论】:

您是否正在寻找带有orWhere() 子句的where() 【参考方案1】:

我认为您需要以下查询

$languageId = 'language_id';

$papers = App\Paper::with(['usages.translations', 'keywords.translations'])
        ->whereHas('usages.translations', function($query) use ($languageId) 
            $query->where('language_id', $languageId);
        )
        ->whereHas('keywords.translations', function($query) use ($languageId) 
            $query->where('language_id', $languageId);
        )
        ->get();

【讨论】:

不幸的是,这不起作用 - 它会获取所有语言突变。【参考方案2】:

听起来你需要的是一个嵌套查询,如下所示:

App\Paper::with(['usages.translations', 'keywords.translations'])
            ->where('usages.translations.language_id', 'your_id_goes_here')
            ->orWhere('keywords.translations.language_id', 'your_id_goes_here')
            ->get();

【讨论】:

谢谢,我试过了,但是我收到了Illuminate/Database/QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'usages.translation s.language_id' in 'where clause' (SQL: select * from `papers` where `usages`.`translations`.`language_id` = 1 or `keywords` .`translations`.`language_id` = 1)'

以上是关于如何在 Eloquent 中查询特定关系的主要内容,如果未能解决你的问题,请参考以下文章

如何在 laravel eloquent 中查询多个关系

如何在 Laravel Eloquent 中构建具有多级关系的查询

如何在 eloquent ORM 中执行此搜索查询

如何在 Laravel 中使用多表查询而不使用 Eloquent 关系

我将如何在 Laravel Eloquent 中编写这个 MySQL 查询?

如何在 Laravel 中定义 Eloquent 关系