【问题标题】:Laravel returns a Collection with duplicates of the first modelLaravel 返回一个包含第一个模型重复的集合
【发布时间】:2019-05-08 16:43:30
【问题描述】:

我正在开发一个 Laravel 5.7 (API) 应用程序,它背后有一个 PostgreSQL 数据库。相关模型为:User(客户和员工)、CarRequest

员工UserCar 创建一个Request,该Car 属于客户 User

关系是:

  • Car (作为客户: User = n:m
  • Car:Request=1:n
  • User : Request (作为员工= 1:n

(委婉地说,数据设计不是最理想的,但无论如何,这是目前的既定现实。)

现在到实际问题。我想显示一个客户 User的所有Requests:

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 Requests。并且上面调用的结果Collection 的长度是正确的。但是所有这些n 条目都是第一个条目的重复项。意思是:我得到了一个包含nRequest#1 实例的列表。

为什么第一次调用会返回对同一个 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;

...,并手动执行。结果表包含预期的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();

...检索正确/预期的模型集。

【问题讨论】:

  • 在您的查询中,您为什么不只是引用关系?你能展示你在你的用户、汽车和请求模型中的关系吗?此外,您不需要在查询中包含 ->select() 行,只需 get()。
  • @eResourcesInc 感谢您的评论。 1。 “引用关系”——你是什么意思? $customer-&gt;cars-&gt; ... 然后呢? 2“显示关系”刚刚更新了问题(参见附加信息)。 3。 "->select() 行" -- 正确,谢谢!
  • 在您的解决方法中,为什么不直接设置 $requests = $customer->cars()->requests()?如果这给了你正确的结果,你为什么要把它写成一个完整的查询,而不是仅仅利用这些关系查询的简单性?
  • @eResourcesInc 1. "$customer->cars()->requests()" -- 这不起作用。 Customer#cars() 返回一个 BelongsToMany 对象。所以我得到一个异常“调用未定义的方法...... BelongsToMany::requests()”。 $customer-&gt;cars-&gt;requests() 也不起作用,因为 $customer-&gt;carsCollection,它不知道 request() 方法。 2.“为什么...完整查询”——是的,我找到了一个可行的解决方案。但我想知道,为什么通过Builder 的替代方式不起作用。要么我理解错了(然后我想知道,我的错误是什么),要么这是一个错误(然后我想报告它)。
  • 当然它会返回一个关系,但我没有用 ->get() 写出整个查询,因为这取决于你。对汽车的调用会返回一组模型,然后您可以利用它们之间的关系。因此,对于汽车模型的请求关系,您绝对应该能够遵循两个级别的关系路径并获得所需的内容。我想我没有遵循帖子的要点,看到您正在尝试查看它是否是一个错误,但这可能是一些编码错误,因为这是基本功能,如果它有错误,那么几乎没有 laravel 应用程序可以正常工作。

标签: laravel laravel-5 laravel-5.7 data-retrieval


【解决方案1】:

首先,请注意您的对象哈希实际上并不相同,您可能要处理两个单独的实例。

您可能遇到的问题是列名不明确。当您JOIN 将多个表放在一起时,任何匹配/重复的列名都将包含最后一个匹配列的值。您的 SQL GUI/客户端通常将它们分开。不幸的是,Laravel 没有前缀机制,只是使用关联数组。

假设您所有的表都有一个主键列 id,那么结果集中的每个 Request 对象都可能具有相同的 ID - 您在 WHERE 条件中传递的用户 ID。

您可以在现有查询中通过明确选择需要防止歧义的列来解决此问题。使用-&gt;select(['request.*']) 将返回的信息限制为Request 对象数据。

【讨论】:

  • 非常感谢您的回答! 1 “对象哈希实际上并不相同”——是的,你是对的。我已经相应地更新了这个问题。 2 谢谢你的解释!我永远不会想到,Eloquent 不会为列添加前缀……在我看来,这是 ORM 的一个非常基本的功能。最重要的是:如果我对具体的Model 类执行查询,我假设只获取它的对象——无需明确指定。无论如何,感谢您的解释和修复!
猜你喜欢
  • 2012-07-25
  • 1970-01-01
  • 2017-11-15
  • 1970-01-01
  • 2013-12-01
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多