Laravel HasMany反向关系问题

时间:2018-07-30 19:17:06

标签: laravel eloquent has-many

让我们举个例子:

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

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

发票模型

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

客户模型

    public function invoices() {

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

让管理员说要按客户过滤发票,他输入例如“ Jhon”

我的控制器:

1-选择名称为“ Jhon”的客户或姓氏为“ Jhon”的客户

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

如何使用关系???

为该客户获取发票

3 个答案:

答案 0 :(得分:0)

请记住,在我看来,Toyi是做到这一点的最佳方法,我只是想让它对您来说尽可能简单,但他对急切装载的态度是100%,因为它效率更高。

因此,您使用一对多关系,其中客户模型为父模型,但现在使发票模型为逆模型,因此首先要确保每个发票都有一个整数“ 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 。如果这样的话。干杯希望这对您有用。

答案 1 :(得分:0)

您可以同时选择两种方法,具体取决于哪种方法最合适。

发票(有):

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

客户(flatMap +发票关系):

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

请记住,除非在执行查询(-> get())之前调用with('invoices'),否则第二个选项将遭受N + 1的破坏。

答案 2 :(得分:0)

您应该用单数或复数形式表示它们之间的关系,以免在以后的项目开发中迷失方向。就您而言,

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();

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

最后,我在示例中使用了with('client'),因为我假设您已更正关系的名称。如果不是,则应使用“客户”,因为它是发票模型中关系的名称:)