Eloquent与条件有很多关系

Posted

技术标签:

【中文标题】Eloquent与条件有很多关系【英文标题】:Eloquent hasMany relationship with condition 【发布时间】:2018-08-20 17:32:17 【问题描述】:

我有一个具有属性“id”、“orderer_user_id”和“contractor_user_id”的模型合同。 我有一个具有“contract_id”、“user_id”和“已签名”属性的模型签名。 我在合同上有一个 hasMany 关系来检索属于合同的签名。 每个合同都有两个签名,一个属于订购者,另一个属于承包商。

我需要获取尚未签署其订购者签名的所有合同(因此,'contract_id' 必须是其父级的 id,'user_id' 必须是其父级的 'orderer_user_id',而 'signed' 必须是假的)

Laravel/Eloquent 的实现方式是什么? 我知道我可以编写一个 foreach 循环并迭代所有合同,检查其签名,然后使用未签名的订购者签名构建一组合同,但感觉很笨拙。 我一直在玩弄关系/有/没有等,但我似乎无法得到正确的结果。

【问题讨论】:

添加一个您到目前为止所做的工作示例会很有帮助 【参考方案1】:

你应该在合约模型上实现关系

// Contract.php

public function signatures() 
    // add proper parameters 2nd: foreign key and 3rd: local key if 
    // your Database design is not respecting laravel/eloquent naming guidelines
    return $this->hasMany(Signature::class); 

为了检索 未签署的合同,这应该可以工作:

$unsignedContracts = Contract::whereHas("signatures", '<', 2)->get();    

我认为这也应该完全不包括条目,但如果没有,你也可以试试这个

$unsignedContracts = Contract::whereDoesntHave("signatures")
                             ->orWhereHas("signatures", '<', 2)->get();

如果您想查询所有带有附加条件的签名,这也是可能的:

$unsignedContracts = Contract::whereHas("signatures", function($q) 
                         $q->where("signed","=",false);
                     )->get()

您还可以在 Signature 模型中引入承包商和订购者的具体关系:

// Signature.php

public function contractor() 
    return $this->belongsTo(User::class, "contractor_user_id", "id"); 


public function orderer() 
    return $this->belongsTo(User::class, "orderer_user_id", "id"); 

有了这些你应该可以做到:

// this should return all contracts where one of the 
// required users has not signed yet
$unsignedContracts = Contract::where(function($q) 
    $q->whereDoesntHave("contractor")
      ->orWhereDoesntHave("orderer");
)->get();

Laravel 文档非常好,恕我直言,请查看https://laravel.com/docs/5.6/eloquent-relationships#querying-relations 以获取更多信息。

【讨论】:

感谢您的反应。我有你提到的确切关系。关键是所有合同在数据库中都有两个签名子节点,但我需要找出哪些合同有一个签名,其中字段“已签名”= false。我现在这样做的方式可行,但感觉有点笨拙: $cons = Contract::get(); foreach ($cons as $con) if ($con->ordererSigned() == true && $con->contractorSigned() == false) $result[] = $con; 您还可以通过whereHas 方法为您添加附加条件,我已经更新了我的答案。这能满足您的需求吗?【参考方案2】:

您可以创建一个应对或定义您的多重关系,无论何时调用它(添加 ->where()->select()...)。

就我个人而言,我会创建一个作用域,这样您就可以随时调用关系,并在需要时应用作用域,从而使两个函数(最终就是函数)独立。

https://laravel.com/docs/5.6/eloquent#local-scopes

【讨论】:

以上是关于Eloquent与条件有很多关系的主要内容,如果未能解决你的问题,请参考以下文章

与where子句查询的Eloquent嵌套关系在false条件下返回集合

关系方法必须在 laravel eloquent 中返回一个对象

Laravel Eloquent 根据数据透视表字段条件获取多对多关系

Laravel Eloquent 关系有很多错误:在 where 上使用时调用未定义的方法

laravel Eloquent 中的条件关系

Laravel Eloquent 关系 - 不根据条件获取