约束急切加载关系
Constraining eager loaded relationship
我发现 with
函数在重载关系时有一个非常奇怪的行为。我有 Product
和 Deal
关系,这样 Product
belongsTo()
Deal
(通过 product_id
in deals
table ).现在,当我尝试让所有产品都打折时:
Product::with(['deal' => function($query) {
$query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
}])->get()
此 returns 所有 产品的集合,即使 没有 条记录 deals
table 和 所有 产品的 deal_id
设置为 NULL
。同时 Product::has('deal')->get()
returns 一个空集合,如你所料。
我最初是在尝试获取五个随机促销产品以及 Deal
和 Image
关系时发现此问题的:
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())
这会生成一个集合,其中包含所有 Product
中的 5 个随机 Product
。我尝试了 query->whereNotNull('ends_at')->whereDate('ends_at' ..... );
但得到了相同的结果。
我做错了什么?
这里你对概念的理解是完全错误的。
如果您说的是 Product belongsTo()
Deal,那么让我们假设 Deal hasMany()
产品.
这是特价商品table
deals
id | name | ends_at | blah | blah
products
id | deal_id | name | blah | blah
所以基本上,Product::with('deal')
应该 return 您所有产品的交易都被 Eager 加载。但是 Deal::with('products')
会 return 你一个空的集合,因为没有产品有一个有效的 deal_id
。
请务必注意,由于 Product 只能 belongTo
一个 Deal,您将始终获得当您执行 Product::with('deal')
查询时,交易模型而不是集合。但是当你执行Deal::with('products')
你一定会得到一个集合
所以基本上,当你说
这 return 是所有产品的集合,即使交易 table 中没有记录并且所有产品都 deal_id 设置为 NULL。
很明显...因为这里的查询是针对产品而不是交易进行的。如果您想在 ends_at > Carbon::now()
处找到 Deal,则必须这样做。
Deal::with('product')->where('ends_at', '>', Carbon::now()->toDateTimeString())
当你使用 with
时,它只会根据提供的约束预先加载关系,但如果你想通过它们的关系过滤父模型,那么 whereHas
是你的朋友。所以你的查询应该是:
Product::whereHas('deal' => function($query) {
$query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
})->get();
现在它将只获取满足给定约束的 Product
。
您还可以使用 with
和 whereHas
的组合作为:
Product::whereHas('deal' => function($query) {
$query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
})
->with(['deal' => function($query) {
$query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
}])
->get();
我发现 with
函数在重载关系时有一个非常奇怪的行为。我有 Product
和 Deal
关系,这样 Product
belongsTo()
Deal
(通过 product_id
in deals
table ).现在,当我尝试让所有产品都打折时:
Product::with(['deal' => function($query) {
$query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
}])->get()
此 returns 所有 产品的集合,即使 没有 条记录 deals
table 和 所有 产品的 deal_id
设置为 NULL
。同时 Product::has('deal')->get()
returns 一个空集合,如你所料。
我最初是在尝试获取五个随机促销产品以及 Deal
和 Image
关系时发现此问题的:
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())
这会生成一个集合,其中包含所有 Product
中的 5 个随机 Product
。我尝试了 query->whereNotNull('ends_at')->whereDate('ends_at' ..... );
但得到了相同的结果。
我做错了什么?
这里你对概念的理解是完全错误的。
如果您说的是 Product belongsTo()
Deal,那么让我们假设 Deal hasMany()
产品.
这是特价商品table
deals
id | name | ends_at | blah | blah
products
id | deal_id | name | blah | blah
所以基本上,Product::with('deal')
应该 return 您所有产品的交易都被 Eager 加载。但是 Deal::with('products')
会 return 你一个空的集合,因为没有产品有一个有效的 deal_id
。
请务必注意,由于 Product 只能 belongTo
一个 Deal,您将始终获得当您执行 Product::with('deal')
查询时,交易模型而不是集合。但是当你执行Deal::with('products')
你一定会得到一个集合
所以基本上,当你说
这 return 是所有产品的集合,即使交易 table 中没有记录并且所有产品都 deal_id 设置为 NULL。
很明显...因为这里的查询是针对产品而不是交易进行的。如果您想在 ends_at > Carbon::now()
处找到 Deal,则必须这样做。
Deal::with('product')->where('ends_at', '>', Carbon::now()->toDateTimeString())
当你使用 with
时,它只会根据提供的约束预先加载关系,但如果你想通过它们的关系过滤父模型,那么 whereHas
是你的朋友。所以你的查询应该是:
Product::whereHas('deal' => function($query) {
$query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
})->get();
现在它将只获取满足给定约束的 Product
。
您还可以使用 with
和 whereHas
的组合作为:
Product::whereHas('deal' => function($query) {
$query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
})
->with(['deal' => function($query) {
$query->whereDate('ends_at', '>', Carbon::now()->toDateTimeString());
}])
->get();