问题 Laravel 5.1将关系数据加载到选定的行中


我有一个 timesheet 桌子和一个 user 我的数据库中的表。以下关系设置在 timesheet 模型。

/**
 * The user that owns the timesheet.
 *
 * @return Object
 */
public function user()
{
    return $this->belongsTo('App\Models\User\User');
}

以上意味着我可以通过以下方式从数据库中选择时间表来获取用户数据:

$this->timesheet->whereStatus('Approved')->with('user');

这将在结果中加载用户对象,如果转换为数组将如此;

0 => array:13 [▼
    "id" => 1
    "user_id" => 2
    "week" => 1
    "year" => 2016
    "week_ending" => "Sunday 10th January 2016"
    "total_hours" => "45.00"
    "token" => "0e6796a2dc68066c8d36ff828c519af00657db02b733309b8a4ac0f7b5d6a385"
    "status" => "Approved"
    "supervisor_id" => 1
    "approved_by" => 1
    "created_at" => "2016-01-13 15:42:49"
    "updated_at" => "2016-01-14 14:52:07"
    "user" => array:7 [▼
      "id" => 2
      "first_name" => "Bill"
      "last_name" => "Andrews"
      "email" => "Bill.andrews@domain.com"
      "status" => 1
      "created_at" => "2016-01-13 15:38:18"
      "updated_at" => "2016-01-14 14:50:03"
    ]
  ]

但是,我只需要 first_name 和 last_name 来自用户表。有没有办法合并/压平 user 数组与 timesheet 所以它看起来像这样;

0 => array:14 [▼
    "id" => 1
    "user_id" => 2
    "week" => 1
    "year" => 2016
    "week_ending" => "Sunday 10th January 2016"
    "total_hours" => "45.00"
    "token" => "0e6796a2dc68066c8d36ff828c519af00657db02b733309b8a4ac0f7b5d6a385"
    "status" => "Approved"
    "supervisor_id" => 1
    "approved_by" => 1
    "created_at" => "2016-01-13 15:42:49"
    "updated_at" => "2016-01-14 14:52:07"
    "first_name" => "Bill"
    "last_name" => "Andrews"
  ]

我试图像这样使用急切的装载;

$this->timesheet->with(['user' => function ($query) {
    $query->select('first_name', 'last_name');
}])->get()->toArray();

但是,它会产生以下输出;

array:126 [▼
  0 => array:13 [▼
    "id" => 1
    "user_id" => 2
    "week" => 1
    "year" => 2016
    "week_ending" => "Sunday 10th January 2016"
    "total_hours" => "45.00"
    "token" => "0e6796a2dc68066c8d36ff828c519af00657db02b733309b8a4ac0f7b5d6a385"
    "status" => "Approved"
    "supervisor_id" => 1
    "approved_by" => 1
    "created_at" => "2016-01-13 15:42:49"
    "updated_at" => "2016-01-14 14:52:07"
    "user" => null
  ]

12556
2018-02-08 14:21


起源



答案:


在第二个示例中,用户关系为空的原因是因为为了使Eloquent关系起作用,它需要绑定关系的键。换一种说法...

  1. 得到 timesheet
  2. 得到 user 只有 first_name 和 last_name
  3. 建立关系。
  4. 既然你没有获取用户的id,那么 user's id 和 timesheet's user_id 不匹配所以无法建立关系。

为了使您的查询有效,您需要像下面这样调整它:

$this->timesheet->with(['user' => function ($query) {
    $query->select('id', 'first_name', 'last_name');
}])->get()->toArray();

如果你想要一个平坦的结果,我认为最好使用 joins 因为渴望加载的性质而不是急切的加载。

$this->timesheet
     ->join('users', 'timesheets.user_id', '=', 'users.id')
     ->select('timesheets.*', 'users.first_name', 'users.last_name')
     ->get()->toArray();

这假定您的表名是 users 和 timesheets


7
2018-02-10 19:18



感谢您的帮助,这是我所追求的信息。我将在9个小时内奖励赏金(它告诉我直到那时才能奖励)。 - V4n1ll4


答案:


在第二个示例中,用户关系为空的原因是因为为了使Eloquent关系起作用,它需要绑定关系的键。换一种说法...

  1. 得到 timesheet
  2. 得到 user 只有 first_name 和 last_name
  3. 建立关系。
  4. 既然你没有获取用户的id,那么 user's id 和 timesheet's user_id 不匹配所以无法建立关系。

为了使您的查询有效,您需要像下面这样调整它:

$this->timesheet->with(['user' => function ($query) {
    $query->select('id', 'first_name', 'last_name');
}])->get()->toArray();

如果你想要一个平坦的结果,我认为最好使用 joins 因为渴望加载的性质而不是急切的加载。

$this->timesheet
     ->join('users', 'timesheets.user_id', '=', 'users.id')
     ->select('timesheets.*', 'users.first_name', 'users.last_name')
     ->get()->toArray();

这假定您的表名是 users 和 timesheets


7
2018-02-10 19:18



感谢您的帮助,这是我所追求的信息。我将在9个小时内奖励赏金(它告诉我直到那时才能奖励)。 - V4n1ll4


你有没有试过一个清单

->lists('first_name', 'last_name');

或者如果你想进行选择

->select('first_name', 'last_name')->get()

更新 您还可以对急切的加载相关对象执行预先加载。这是一个例子

$users = App\User::with(['posts' => function ($query) {
    $query->select('first_name', 'last_name');

}])->get();

如果有帮助,请告诉我。


2
2018-02-08 14:42



如果您认为我已经正确回答了您的问题,请将此标记为下一个人的正确答案。谢谢 ! - Gagan
我努力了 $rows->lists('week_ending', 'user.first_name', 'user.last_name', 'created_at', 'total_hours', 'status');这是我需要的列的列表,但它只是返回 "Bill" => "Sunday 10th January 2016" - V4n1ll4
渴望加载后请看上面的输出(我已经更新了我的原始帖子)。 - V4n1ll4
在您在问题中粘贴的急切加载代码中,我没有看到任何满足此要求的内容 - > whereStatus('Approved')语句,您在原文中。这是预期的吗? - Gagan
该 ->whereStatus('Approved') 不需要。每个时间表都属于一个用户,因此应显示用户信息。 - V4n1ll4


Laravel模型有一种在获取/设置属性之前修改数据的方法。实际上,您可以通过定义getter函数将属性添加到模型中。这将允许您以与您相同的方式引用用户名 user_id 要么 status。这些功能也非常适合更改视图或清理表单输入的日期格式。

/**
 * Get the first name of the user.
 *
 * @return string
 */
public function getFirstNameAttribute()
{
    return $this->user->first_name;
}

/**
 * Get the last name of the user.
 *
 * @return string
 */
public function getLastNameAttribute()
{
    return $this->user->last_name;
}

2
2018-02-10 20:53





这正是一个 join 做。

从文档中

查询构建器还可用于编写连接语句。至   执行一个基本的SQL“内连接”,你可以使用一个连接方法   查询构建器实例。第一个参数传递给join方法   是您需要加入的表的名称,而其余的   arguments指定连接的列约束。

$this->timesheet
      ->leftjoin('user', 'user.id', '=','timesheet.user_id')
      ->get()
      ->toArray();

如果你想对你的领域更有选择性,你可以选择你的 select;

$this->timesheet
      ->leftjoin('user', 'user.id', '=','timesheet.user_id')
      ->select('timesheet.*', 'user.first_name', 'user.last_name')
      ->get()
      ->toArray();

正如其他人所建议的那样,使用数据库查询构建器可能更好

this->timesheet = DB::table('timesheet')
                 ->where('timesheet.status', 'Approved')
                 ->leftjoin('user', 'user.id', '=','timesheet.user_id')
                 ->select('timesheet.*', 'user.first_name', 'user.last_name')
                 ->get()
                 ->toArray();

1
2018-02-10 19:22





在这种情况下,最好使用Raw SQL或Query构建器。 因为关系使用数据库数据作为关系对象。


-1
2018-02-08 14:53