如何在 parent 和 child 上应用 Laravel Eloquent where() 条件(hasMany() 关系)
How to apply a Laravel Eloquent where() condition on both parent and child (hasMany() relationship)
我有一个名为 Laravel Eloquent 的模型 EmailList
和一个名为 Subscriber
的模型。
我在 EmailList 上定义了以下 hasMany 关系。
public function subscribers() {
return $this->hasMany(Subscriber::class);
}
这种关系很好。
我现在想在 parent 上应用 where()
条件,在 child 上应用 where()
条件。
例如,我有两个 EmailList
,一个 属性 id
和一个 属性 称为 listname
(“列表 A”和“清单 B”)。我的 Subscriber
模型有四个相关属性:id
、name
、email
和 email_list_id
.
问题:我想从某个列表中获取所有订阅者,例如'List A',并使用 $query
(使用 Livewire 的搜索功能).
过滤订阅者
为了实现这一点,我想出了以下代码:
EmailList::where('listname', $listname)->first()
->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->paginate(50) //or get(), if you like
此代码部分起作用,因为确实过滤了订阅者,但没有过滤 EmailList。换句话说,我只是搜索了所有订阅者,而不是特定列表中的订阅者。
经过大量搜索后,我发现我或许应该使用 whereHas()
,但是当我尝试这样做时,它只给了我电子邮件列表而不是订阅者。
如果有人能帮我过滤一下就好了。对于有经验的开发人员来说,这可能是花生,但它对我有很大帮助!
更新:
看到 EricLandheer 的回答后,我意识到(当然)我也有 EmailList id。也许这会使它更简单一些,这样您就可以使用 find() 而不是 where()->first() 子句。 (我使用 first() 是因为‘listname’是唯一的,我只想要一个实例。对吗?)
目前,您的代码只有 returns 第一个 EmailList
。你是故意的,还是只想要第一个 EmailList
有 $listname
?
这是一个使用 Eager loading with constraints 的解决方案,它用回调覆盖了 subscribers
关系。结果应该是所有 EmailLists
与 $listname
和匹配的订阅者与搜索。
EmailList::where('listname', $listname)
->with('subscribers', function($query) {
return $query->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
})->get();
关于问题更新
确实,用Listname就可以了。如果它是唯一的,那没问题。您可以将 find()
与 ID 一起使用,如果您考虑在稍后阶段更改 EmailList
的名称,这是更可取的。
也许更优雅/可读的解决方案是:
$emailList = EmailList::firstWhere('listname', $listname);
$emailList->subscribers = $emailList->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->get();
如果您在更多地方使用它,您可以将搜索重构为模型/服务:
// EmailList model
public function subscribers()
{
return $this->hasMany(Subscriber::class);
}
public function searchSubscribers(string $search): Collection
{
return $this->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->get();
}
最终代码
$emailList = EmailList::firstWhere('listname', $listname);
$emailList->subscribers = $emailList->searchSubscribers($this->search);
我有一个名为 Laravel Eloquent 的模型 EmailList
和一个名为 Subscriber
的模型。
我在 EmailList 上定义了以下 hasMany 关系。
public function subscribers() {
return $this->hasMany(Subscriber::class);
}
这种关系很好。
我现在想在 parent 上应用 where()
条件,在 child 上应用 where()
条件。
例如,我有两个 EmailList
,一个 属性 id
和一个 属性 称为 listname
(“列表 A”和“清单 B”)。我的 Subscriber
模型有四个相关属性:id
、name
、email
和 email_list_id
.
问题:我想从某个列表中获取所有订阅者,例如'List A',并使用 $query
(使用 Livewire 的搜索功能).
为了实现这一点,我想出了以下代码:
EmailList::where('listname', $listname)->first()
->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->paginate(50) //or get(), if you like
此代码部分起作用,因为确实过滤了订阅者,但没有过滤 EmailList。换句话说,我只是搜索了所有订阅者,而不是特定列表中的订阅者。
经过大量搜索后,我发现我或许应该使用 whereHas()
,但是当我尝试这样做时,它只给了我电子邮件列表而不是订阅者。
如果有人能帮我过滤一下就好了。对于有经验的开发人员来说,这可能是花生,但它对我有很大帮助!
更新: 看到 EricLandheer 的回答后,我意识到(当然)我也有 EmailList id。也许这会使它更简单一些,这样您就可以使用 find() 而不是 where()->first() 子句。 (我使用 first() 是因为‘listname’是唯一的,我只想要一个实例。对吗?)
目前,您的代码只有 returns 第一个 EmailList
。你是故意的,还是只想要第一个 EmailList
有 $listname
?
这是一个使用 Eager loading with constraints 的解决方案,它用回调覆盖了 subscribers
关系。结果应该是所有 EmailLists
与 $listname
和匹配的订阅者与搜索。
EmailList::where('listname', $listname)
->with('subscribers', function($query) {
return $query->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
})->get();
关于问题更新
确实,用Listname就可以了。如果它是唯一的,那没问题。您可以将 find()
与 ID 一起使用,如果您考虑在稍后阶段更改 EmailList
的名称,这是更可取的。
也许更优雅/可读的解决方案是:
$emailList = EmailList::firstWhere('listname', $listname);
$emailList->subscribers = $emailList->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->get();
如果您在更多地方使用它,您可以将搜索重构为模型/服务:
// EmailList model
public function subscribers()
{
return $this->hasMany(Subscriber::class);
}
public function searchSubscribers(string $search): Collection
{
return $this->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->get();
}
最终代码
$emailList = EmailList::firstWhere('listname', $listname);
$emailList->subscribers = $emailList->searchSubscribers($this->search);