【问题标题】:Constraining eager loaded relationship约束急切加载的关系
【发布时间】:2016-12-17 22:16:03
【问题描述】:

我发现with 函数用于重载关系的一个非常奇怪的行为。我有ProductDeal 关系,例如Product belongsTo() Deal(通过product_iddeals 表中)。现在,当我尝试让所有产品都打折时:

Product::with(['deal' => function($query) {
    $query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
}])->get()

这会返回所有产品的集合,即使deals 表中没有没有记录并且所有产品有deal_id设置为NULL。同时Product::has('deal')->get() 返回一个空集合,正如您所期望的那样。

我最初在尝试获取 5 个随机销售的产品以及 DealImage 关系时发现了这个问题:

Product::with(['deal' => function ($query) {
        $query->whereDate('ends_at', '>', // promo still active
                             Carbon::now()->toDateTimeString());
    },
    'images' => function ($query) {
        $query->where('featured', true);    // image featured on homepage
    }])
->where('status', 'IN_STOCK')   // 'In Stock'
->whereNull('deleted_at')       // wasn't soft-deleted
->orderByRaw('RAND()')
->take(5)->get())

这会产生一个集合,其中包含所有 Products 中的 5 个随机 Products。我尝试了query->whereNotNull('ends_at')->whereDate('ends_at' ..... );,但得到了相同的结果。

我在这里做错了什么?

【问题讨论】:

    标签: laravel eloquent laravel-5.3


    【解决方案1】:

    这里你对概念的理解是完全错误的。

    如果您说的是产品 belongsTo() 交易,那么我们假设交易 hasMany() 产品。

    这是交易表

    deals
    id | name | ends_at | blah | blah
    
    products
    id | deal_id | name | blah | blah
    

    所以基本上,Product::with('deal') 应该返回您所有的产品,并且他们的交易是急切加载的。但是Deal::with('products') 将返回一个空集合,因为其中没有有效的deal_id

    需要注意的是,由于Product只能belongTo一个Deal,所以当你执行@时你总是会得到Deal Model而不是一个集合987654328@查询。但是当你执行Deal::with('products') 时,你一定会得到一个集合。

    所以基本上,当你说

    这将返回所有产品的集合,即使交易表中没有记录并且所有产品的 deal_id 都设置为 NULL。

    很明显....因为这里的查询是针对 Products 而不是 Deal。如果您想找到ends_at > Carbon::now()交易,您必须这样做。

    Deal::with('product')->where('ends_at', '>', Carbon::now()->toDateTimeString())
    

    【讨论】:

      【解决方案2】:

      当您使用with 时,它只会急切加载提供的约束上的关系,但如果您想通过关系过滤父模型,那么whereHas 是您的朋友。所以你的查询应该是:

      Product::whereHas('deal' => function($query) {
                $query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
              })->get();
      

      现在它将只获取那些满足给定约束的Product

      您还可以使用withwhereHas 的组合作为:

      Product::whereHas('deal' => function($query) {
                $query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
              })
              ->with(['deal' => function($query) {
                  $query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
              }])
              ->get();
      

      【讨论】:

        猜你喜欢
        • 2013-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-19
        • 2016-12-28
        • 1970-01-01
        • 2015-05-29
        • 2021-04-28
        相关资源
        最近更新 更多