【问题标题】:Laravel - Eloquent "Has", "With", "WhereHas" - What do they mean?Laravel - 雄辩的“Has”、“With”、“WhereHas”——它们是什么意思?
【发布时间】:2015-07-25 17:55:04
【问题描述】:

我发现这些方法背后的概念和含义有点令人困惑,是否有人可以在示例的上下文中向我解释haswith 之间的区别是什么(如果可能)?

【问题讨论】:

    标签: laravel orm eloquent relational-database relationship


    【解决方案1】:

    documentation已经解释了用法,所以我将使用SQL来解释方法。

    示例:

    假设有一个Order (orders) 有很多OrderItem (order_items) 并且你已经建立了它们之间的关系:

    // App\Models\Order:
    public function orderItems() {
        return $this->hasMany('App\Models\OrderItem', 'order_id', 'id');
    }
    

    这三种方法都是基于关系的

    结果:with()返回模型对象及其相关结果。

    优点:eager-loading可以防止N+1问题

    当您使用以下 Eloquent Builder 时:

    Order::with('orderItems')->get();
    

    Laravel 将此代码更改为只有两条 SQL

    // get all orders:
    SELECT * FROM orders; 
     
    // get the order_items based on the orders' id above
    SELECT * FROM order_items WHERE order_items.order_id IN (1,2,3,4...);
    

    然后Laravel通过外键第二条SQL查询结果第一条SQL查询结果合并,最后返回集合结果。

    因此,如果您在闭包中选择了没有 foreign_key 的列,则关系结果将为空:

    Order::with(['orderItems' => function($query) { 
               // $query->sum('quantity');
               $query->select('quantity'); // without `order_id`
           }
    ])->get();
    
    #=> result:
    [{  id: 1,
        code: '00001',
        orderItems: [],    // <== is empty
      },{
        id: 2,
        code: '00002',
        orderItems: [],    // <== is empty
      }...
    }]
    

    Has会在关系不为空时返回模型的对象。

    Order::has('orderItems')->get();
    

    Laravel 将此代码更改为一个 SQL 查询

    select * from `orders` where exists (
        select * from `order_items` where `orders`.`id` = `order_items`.`order_id`
    )
    

    哪里有

    whereHasorWhereHas 方法将 where 条件放在您的 has 查询上。这些方法允许您将自定义约束添加到关系约束

    Order::whereHas('orderItems', function($query) {
       $query->where('status', 1);
    })->get();
    

    Laravel 将此代码更改为一个 SQL 查询

    select * from `orders` where exists (
        select * 
        from `order_items` 
        where `orders`.`id` = `order_items`.`order_id` and `status` = 1
    )
    

    【讨论】:

      【解决方案2】:

      with() 用于渴望加载。这基本上意味着,沿着主模型,Laravel 将预加载您指定的关系。如果您有一组模型并且想要为所有模型加载关系,这将特别有用。因为通过预先加载,您只需运行一个额外的数据库查询,而不是为集合中的每个模型运行一个。

      例子:

      User &gt; hasMany &gt; Post

      $users = User::with('posts')->get();
      foreach($users as $user){
          $users->posts; // posts is already loaded and no additional DB query is run
      }
      

      has()是根据关系过滤选择模型。所以它的行为与正常的 WHERE 条件非常相似。如果您只使用has('relation'),则意味着您只想获取在此关系中至少有一个相关模型的模型。

      例子:

      User &gt; hasMany &gt; Post

      $users = User::has('posts')->get();
      // only users that have at least one post are contained in the collection
      

      哪里有

      whereHas() 的工作原理与has() 基本相同,但允许您为相关模型指定额外的过滤器以进行检查。

      例子:

      User &gt; hasMany &gt; Post

      $users = User::whereHas('posts', function($q){
          $q->where('created_at', '>=', '2015-01-01 00:00:00');
      })->get();
      // only users that have posts from 2015 on forward are returned
      

      【讨论】:

      • +1,非常有帮助的答案!另请注意,虽然with('relation') 将在返回的集合中包含相关表的数据,但has('relation')whereHas('relation') 包含相关表的数据。因此,您可能需要同时致电 with('relation') 以及 has()whereHas()
      • 欢迎回答,如何从关系模型访问父模型,例如这里如何根据用户模型的属性搜索帖子模型
      • @BhojendraNepal 不幸的是,文档中似乎没有太多关于它的内容...This is all I found(下面几段)
      • @hussainfrotan 同理,查询帖子时在用户关系上使用whereHas
      • 很好奇,在 Laravel 文档中:laravel.com/docs/5.8/eloquent-relationships,当使用 whereHas 时,它使用 use Illuminate\Database\Eloquent\Builder;,然后是 function(Builder $query)。我看到的大多数示例,点使用Builder,只需传入$query,这是正确的方式吗?
      猜你喜欢
      • 2019-01-22
      • 2022-01-27
      • 1970-01-01
      • 2017-11-05
      • 2017-03-15
      • 2014-06-02
      • 2021-12-24
      • 2020-02-18
      • 2012-06-07
      相关资源
      最近更新 更多