Я был бы признателен за помощь в понимании несоответствия, которое я вижу со следующим в моем проекте laravel 6.8:

У меня модель "UserAlert"

class UserAlert extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'user_id', 'from_id', 'subject', 'message'
    ];

    //Relationships
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    //Only include the name of the sender in this relationship
    public function from()
    {
        return $this->hasOne(User::class, 'id', 'from_id')->select('name');
    }
}

Отношение «пользователь» по умолчанию - «user_id» на «id» и работает, как ожидалось.

Как видите, отношение «from» извлекает имя из модели User, связанной с идентификатором from_id в UserAlert.

Если я получаю коллекцию UserAlerts, а затем перебираю ее, чтобы получить отношение «от» для каждого из них, как показано ниже:

$thisUserAlerts = \App\UserAlert::where('user_id', $thisUser->id)->get();
foreach ($thisUserAlerts as $userAlert) {
    dump($userAlert->from);
}

Тогда я действительно вижу имя из отношения "от кого", как хочу:

...
#original: array:1 [
    "name" => "Administrator"
  ]
...

Однако, если я попытаюсь включить отношение непосредственно в коллекцию UserAlert, используя «with», то «from» всегда будет равно нулю.

$thisUserAlertsWith = \App\UserAlert::where('user_id', $thisUser->id)->with('from')->get();
dump($thisUserAlertsWith);
...
#relations: array:1 [
        "from" => null
      ]
...

Из журнала запросов я вижу, что когда я делаю это выше, нет sql-запроса для извлечения имени из таблицы пользователей, но когда я перебираю коллекцию и вызываю '-> from' напрямую, тогда запрос выполняется.

Я неправильно понял «с»?

[отредактировано, чтобы убрать несоответствие в примерах для ясности]

0
Andrew 14 Апр 2020 в 17:17

1 ответ

Лучший ответ

Благодаря Даниалу Петровалиеву за то, что он указал мне правильное направление, я нашел два ответа на свою проблему.

Оказывается, чтобы отношение было включено, вы должны включить первичный ключ (id) в коллекцию.

Итак, первый ответ - изменить отношение с

return $this->hasOne(User::class, 'id', 'from_id')->select('name');

К

return $this->hasOne(User::class, 'id', 'from_id')->select(['id', 'name']);

Мой первоначальный пример работает так, как я задумал.

Изучение этого также привело меня к другому варианту, который заключался не в ограничении полей в самом отношении, а в ограничении их в вызове «with».

Поэтому полностью удалите выделение из отношения:

return $this->hasOne(User::class, 'id', 'from_id')

И вместо этого отфильтруйте коллекцию следующим образом:

$userAlerts =  UserAlert::where('user_id', $id)->with('from:id,name')->get();

Опять же, вы должны включить первичный ключ (id), чтобы он работал.

0
Andrew 14 Апр 2020 в 15:58