Laravel HasMany反向关系问题
Laravel HasMany reverse relation issue
让我们举个例子:
我有一个显示所有发票的页面。
网站管理员可以通过搜索他们的名字或姓氏来过滤客户端的结果。
发票模型
public function clients()
{
return $this->belongsTo('App\Client');
}
客户端模型
public function invoices() {
return $this->hasMany('App\Invoice');
}
假设管理员想按客户过滤发票,他键入 'Jhon'
我的控制器:
1- 选择名称 LIKE 'Jhon' 或姓氏 LIKE 'Jhon'
的客户
2- if $query return 一个包含很多客户端的数组名为 Jhon 。
我将如何使用关系为该客户获取发票???
请记住,在我看来,Toyi 是实现此目的的最佳方式,我只是想让它对您来说尽可能简单,但他 100% 支持 Eager Loading,因为它效率更高。
因此,您使用的是一对多关系,其中您的客户模型是父模型,但现在您将发票模型设为逆向,因此第一件事是您必须确保每个发票都有一个整数 "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 语句的方式。请记住,“%”有助于检查用户输入框中的意外百分比。
预加载
对此进行更新Post我看到你有以下代码:
$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();
这背后的原因是因为无论出于何种原因,急切加载都无法从外部放置字符串和变量,因此我通过将变量与函数一起传递并在 $key 输入之前将变量分配给它$发票。如果这是有道理的。干杯希望这对你有用。
两种方式都可以,具体取决于哪种方式最适合。
发票(whereHas):
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());
你应该用它们所代表的事物的单数或复数形式来命名你的关系,以免在以后的项目开发中迷失方向。在你的情况下,
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 模型中关系的名称 :)
让我们举个例子:
我有一个显示所有发票的页面。
网站管理员可以通过搜索他们的名字或姓氏来过滤客户端的结果。
发票模型
public function clients()
{
return $this->belongsTo('App\Client');
}
客户端模型
public function invoices() {
return $this->hasMany('App\Invoice');
}
假设管理员想按客户过滤发票,他键入 'Jhon'
我的控制器:
1- 选择名称 LIKE 'Jhon' 或姓氏 LIKE 'Jhon'
的客户2- if $query return 一个包含很多客户端的数组名为 Jhon 。
我将如何使用关系为该客户获取发票???
请记住,在我看来,Toyi 是实现此目的的最佳方式,我只是想让它对您来说尽可能简单,但他 100% 支持 Eager Loading,因为它效率更高。
因此,您使用的是一对多关系,其中您的客户模型是父模型,但现在您将发票模型设为逆向,因此第一件事是您必须确保每个发票都有一个整数 "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 语句的方式。请记住,“%”有助于检查用户输入框中的意外百分比。
预加载
对此进行更新Post我看到你有以下代码:
$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();
这背后的原因是因为无论出于何种原因,急切加载都无法从外部放置字符串和变量,因此我通过将变量与函数一起传递并在 $key 输入之前将变量分配给它$发票。如果这是有道理的。干杯希望这对你有用。
两种方式都可以,具体取决于哪种方式最适合。
发票(whereHas):
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());
你应该用它们所代表的事物的单数或复数形式来命名你的关系,以免在以后的项目开发中迷失方向。在你的情况下,
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 模型中关系的名称 :)