Laravel returns 包含第一个模型副本的集合
Laravel returns a Collection with duplicates of the first model
我正在开发一个 Laravel 5.7
(API) 应用程序,其背后有一个 PostgreSQL 数据库。相关模型是:User
(客户和员工)、Car
和 Request
。
员工User
为Car
创建了Request
,属于客户[=113] =] User
.
关系是:
Car
(作为客户) :
User
=
n:m
Car
:
Request
=
1:n
User
:
Request
(作为员工) =
1:n
(数据设计不是最理想的,说得客气一点,但无论如何,这是目前给定的现实。)
现在进入实际问题。我想显示 客户 User
:
的所有 Request
Request::query()
->join('user_car', 'user_car.car_id', '=', 'request.car_id')
->join('user', 'user.id', '=', 'user_car.user_id')
->where('user.id', '=', $customer->id)
->select()
->get();
给定 $customer->id
的 客户 有 n
Request
个。并且上面调用的结果 Collection
的长度是正确的。但是所有这些 n
条目都是第一个条目的副本。意思是:我得到一个包含 n
个 Request#1
实例的列表。
为什么第一个调用 return 对同一 Model
对象的引用列表? 这是一个(已知)错误吗?
附加信息
关系:
class User extends \Illuminate\Foundation\Auth\User
{
// ...
public function cars()
{
return $this->belongsToMany('App\Car', 'user_car')->withTimestamps();
}
public function requests()
{
return $this->hasMany(Request::class, 'user_id');
}
}
class Car extends Model
{
// ...
public function users()
{
return $this->belongsToMany('App\User', 'user_car')->withTimestamps();
}
public function requests()
{
return $this->hasMany(Request::class);
}
}
class Request extends Model
{
// ...
public function car()
{
return $this->belongsTo(Car::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
查询正确
我记录了数据库请求,得到了生成的语句
SELECT *
FROM "request"
INNER JOIN "user_car" ON "user_car"."car_id" = "request"."car_id"
INNER JOIN "user" ON "user"."id" = "user_car"."user_id"
WHERE "user"."id" = 1;
...,手动执行。结果 table 包含预期的 n
不同的 个条目。
不只是参考文献
结果 Collection
的条目实例引用了不同的对象:
$test1 = $resultCollection->first();
$test2 = $resultCollection->last();
$test3 = spl_object_hash($test1);
$test4 = spl_object_hash($test2);
Xdebug 输出:
$test3 = "0000000077505ccd000000007964e0a8" <-- ccd0
$test4 = "0000000077505c33000000007964e0a8" <-- c330
解决方法
我找到了解决方法。这个电话
Request::whereIn('car_id', $customer->cars()->pluck('id')->toArray())->get();
... 检索 correct/expected 模型集。
首先,请注意您的对象哈希值实际上并不相同,您可能正在处理两个不同的实例。
您可能遇到的问题是列名不明确。当您 JOIN
将多个表放在一起时,任何 matching/duplicate 列名称都将包含最后一个匹配列的值。您的 SQL GUI/client 通常将它们分开。不幸的是 Laravel 没有前缀机制,只能使用关联数组。
假设您所有的表都有一个主键列 id
,结果集中的每个 Request
对象都可能具有相同的 ID - 您在 [=13] 中传递的用户 ID =]条件。
您可以通过显式选择需要防止歧义的列来解决现有查询中的这个问题。使用 ->select(['request.*'])
将返回的信息限制为 Request
对象数据。
我正在开发一个 Laravel 5.7
(API) 应用程序,其背后有一个 PostgreSQL 数据库。相关模型是:User
(客户和员工)、Car
和 Request
。
员工User
为Car
创建了Request
,属于客户[=113] =] User
.
关系是:
Car
(作为客户):
User
=
n:m
Car
:
Request
=
1:n
User
:
Request
(作为员工)=
1:n
(数据设计不是最理想的,说得客气一点,但无论如何,这是目前给定的现实。)
现在进入实际问题。我想显示 客户 User
:
Request
Request::query()
->join('user_car', 'user_car.car_id', '=', 'request.car_id')
->join('user', 'user.id', '=', 'user_car.user_id')
->where('user.id', '=', $customer->id)
->select()
->get();
给定 $customer->id
的 客户 有 n
Request
个。并且上面调用的结果 Collection
的长度是正确的。但是所有这些 n
条目都是第一个条目的副本。意思是:我得到一个包含 n
个 Request#1
实例的列表。
为什么第一个调用 return 对同一 Model
对象的引用列表? 这是一个(已知)错误吗?
附加信息
关系:
class User extends \Illuminate\Foundation\Auth\User
{
// ...
public function cars()
{
return $this->belongsToMany('App\Car', 'user_car')->withTimestamps();
}
public function requests()
{
return $this->hasMany(Request::class, 'user_id');
}
}
class Car extends Model
{
// ...
public function users()
{
return $this->belongsToMany('App\User', 'user_car')->withTimestamps();
}
public function requests()
{
return $this->hasMany(Request::class);
}
}
class Request extends Model
{
// ...
public function car()
{
return $this->belongsTo(Car::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
查询正确
我记录了数据库请求,得到了生成的语句
SELECT *
FROM "request"
INNER JOIN "user_car" ON "user_car"."car_id" = "request"."car_id"
INNER JOIN "user" ON "user"."id" = "user_car"."user_id"
WHERE "user"."id" = 1;
...,手动执行。结果 table 包含预期的 n
不同的 个条目。
不只是参考文献
结果 Collection
的条目实例引用了不同的对象:
$test1 = $resultCollection->first();
$test2 = $resultCollection->last();
$test3 = spl_object_hash($test1);
$test4 = spl_object_hash($test2);
Xdebug 输出:
$test3 = "0000000077505ccd000000007964e0a8" <-- ccd0
$test4 = "0000000077505c33000000007964e0a8" <-- c330
解决方法
我找到了解决方法。这个电话
Request::whereIn('car_id', $customer->cars()->pluck('id')->toArray())->get();
... 检索 correct/expected 模型集。
首先,请注意您的对象哈希值实际上并不相同,您可能正在处理两个不同的实例。
您可能遇到的问题是列名不明确。当您 JOIN
将多个表放在一起时,任何 matching/duplicate 列名称都将包含最后一个匹配列的值。您的 SQL GUI/client 通常将它们分开。不幸的是 Laravel 没有前缀机制,只能使用关联数组。
假设您所有的表都有一个主键列 id
,结果集中的每个 Request
对象都可能具有相同的 ID - 您在 [=13] 中传递的用户 ID =]条件。
您可以通过显式选择需要防止歧义的列来解决现有查询中的这个问题。使用 ->select(['request.*'])
将返回的信息限制为 Request
对象数据。