【问题标题】:Laravel HasMany reverse relation issueLaravel HasMany 反向关系问题
【发布时间】:2019-01-07 02:39:54
【问题描述】:

让我们举个例子:

我有一个显示所有发票的页面。

网站管理员可以通过搜索他们的姓名或姓氏来过滤客户的结果。

发票模型

    public function clients()
{
    return $this->belongsTo('App\Client');
}

客户端模型

    public function invoices() {

    return $this->hasMany('App\Invoice');
}

假设管理员想要按客户筛选发票,他输入例如“Jhon”

我的控制器:

1- 选择名称 LIKE 'Jhon' 或姓氏 LIKE 'Jhon' 的客户

2- 如果 $query 返回一个包含许多名为 Jhon 的客户端的数组。

我将如何使用关系获取此客户的发票???

【问题讨论】:

  • 不应该 client()client() 吗? IE。发票属于一个客户,而不是许多客户s。除此之外,您还必须使用 ->whereHas() 来过滤您的 client 关系,以查找其中包含 john 的列的任何记录。

标签: laravel eloquent has-many


【解决方案1】:

你可以两种方式都做,这取决于最适合的。

发票(哪里有):

Invoice::whereHas('client', function ($query){
    $query->where('name', 'like', 'Jhon')
        ->orWhere('lastname', 'like', 'Jhon');
})->get();

客户(平面地图+发票关系):

Client::where('name', 'like', 'Jhon')
    ->orWhere('lastname', 'like', 'Jhon')
    ->get()
    ->flatMap->invoices;

请记住,第二个选项会受到 N+1 的影响,除非在执行查询之前调用 with('invoices') (->get());

【讨论】:

  • 谢谢你 Jorge .. 简单干净!!
【解决方案2】:

您应该使用它们所代表的事物的单数或复数形式来命名您的关系,以免在项目开发的后期迷路。在你的情况下,

public function clients() {
    return $this->belongsTo('App\Client', 'client_id');
}

应该是单数,因为一张发票只属于一个客户

public function client() {
    return $this->belongsTo('App\Client', 'client_id');
}

现在,要实际回答您的问题,因为您正在列出 发票,我建议您从您的发票模型开始。像这样的东西可以解决问题:

$invoices = Invoice::with('client')->where(function($q){
    $q->where('firstname', 'LIKE', 'Jhon');
    $q->orWhere('lastname', 'LIKE', 'Jhon');
})->get();

请注意with('client'),它会很有用,因为它会急切地向客户端加载您的所有发票,因此您不会在每次 foreach 迭代时都收到另一个查询。 The documentation about eager loading is available here

您可以做的另一件事是:不要使用“like”,而是使用“REGEXP”。

$invoices = Invoice::with('client')->where(function($q){
    $q->where('firstname', 'REGEXP', '([[:<:]])Jhon');
    $q->orWhere('lastname', 'REGEXP', '([[:<:]])Jhon');
})->get();

它将为您提供每个人的发票,其中他们的名字或姓氏以 Jhno 开头。与“Jhon”一词无用,但在许多情况下非常有用:“J”会找到每个 Jack、Jhon、John、Joe...

最后一件事,我在示例中使用了with('client'),因为我假设您更正了关系的名称。如果没有,您应该使用“clients”,因为它是 Invoice 模型中关系的名称:)

【讨论】:

  • 我收到此错误SQLSTATE[42S22]: Column not found: 1054 Unknown column 'nom' in 'where clause' (SQL: select * from factures` where (nom LIKE %jhon% or prenom LIKE %jhoni%))`
  • 控制器`$invoices = Facture::with('client')->where(function($q){ $key = Input::get('client'); $q->where ('nom', 'LIKE', '%'.$key.'%'); $q->orWhere('prenom', 'LIKE', '%'.$key.'%'); })- >get();`
【解决方案3】:

请记住,Toyi 在我看来是最好的方法,我只是想让这对你来说尽可能简单,但他 100% 赞成 Eager Loading,因为它更有效。

所以您使用一对多关系,您的客户模型是父模型,但现在您制作 Invoice 模型 Inverse,所以第一件事是首先您必须确保每个 Invoice 都有一个整数“client_id”来存储每个每张发票上的客户 ID。我也只是为了安全起见,并确保它寻找正确的 id 设置你的模型。

客户端模型

public function invoices() {
    return $this->hasMany('App\Invoice', 'client_id');
}

发票模型

public function clients() {
    return $this->belongsTo('App\Client', 'client_id');
}

然后在您的控制器中,您将像这样提取该数据。

$client = Client::where('name','like', '%' . Input::get('name') . '%')->orWhere('lastname', 'like', '%' . Input::get('name') . '%')->get();

foreach($client->invoices as $invoice) {
   echo $invoice->title; //Or What ever data you need to pull from your invoice.
}

请注意,我还添加了将输入添加到 orWhere 和 where 语句的方式。请记住,“%”有助于检查用户输入框中的意外 %。

预加载

更新这篇文章我看到你有以下代码:

$invoices = Facture::with('client')->where(function($q) { 
   $key = Input::get('client'); 
   $q->where('nom', 'LIKE', '%'.$key.'%'); 
   $q->orWhere('prenom', 'LIKE', '%'.$key.'%'); 
})->get();

我会做的是像这样传递输入,它可能会修复你的错误。

$key = Input::get('client');
$invoices = Facture::with('client')->where(function($q) or ($key) {  
   $q->where('nom', 'LIKE', '%'.$key.'%'); 
   $q->orWhere('prenom', 'LIKE', '%'.$key.'%'); 
})->get();

这背后的原因是因为急切加载无法从外部放置字符串和变量,所以我通过将变量与函数一起传递并在 $invoices 之前将 $key 输入分配给它.如果这是有道理的。干杯希望这对你有用。

【讨论】:

    猜你喜欢
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-28
    • 1970-01-01
    • 2017-05-18
    • 2019-03-04
    • 1970-01-01
    相关资源
    最近更新 更多