2016-03-07 4 views
3

В Laravel, возможно ли Eager Загрузить «первый» элемент из отношения BelongsToMany? Как и в, верните Item из этой связи, а не Collection?Laravel - Eager Load Single Item in ManyToMany Realtionship

Из того, что я попытался (и читать) применение first() или limit('1') или любое другое ограничение не будет возвращать отдельный элемент

+0

Можете ли вы разместить свой код, пожалуйста? –

ответ

4

Используйте accessor.

Я думаю, что вам нужно что-то вроде latest, first, или такого рода один элемент из коллекции, так что вы можете сделать это:

public function items() 
{ 
    return $this->belongsToMany(Item::class); 
} 

public function getLatestItemAttribute() 
{ 
    return $this->items->sortByDesc('created_at')->first(); 
} 

, то вы можете просто использовать:

$yourModel->latestItem; // single related model OR null 

Редактировать: как упоминалось в комментарии в комментарии @Hkan, приведенный выше код приведет к сбору всей коллекции и работе над ней. Тем не менее, вы можете использовать в качестве альтернативы отношение объекта и непосредственно запрос к таблице:

public function getLatestItemAttribute() 
{ 
    return $this->items()->latest()->first(); 
} 

однако, таким образом, вы запустите запрос каждый раз, когда вы называете $model->latestItem. В результате вы получаете новую копию модели, а не тот же экземпляр, и, очевидно, вы можете запросить свою базу данных произвольное количество раз, в зависимости от вашего прецедента.

жесткий, но лучше способом было бы имитировать отношения:

public function getLatestItemAttribute() 
{ 
    if (!$this->relationLoaded('latestItem')) { 
    $this->setRelation('latestItem', $this->items()->latest()->first()); 
    } 

    return $this->getRelation('latestItem'); 
} 

в этом случае $model->latestItem рассматривается как любые другие одного отношений, когда загружен. То есть, это будет единственный экземпляр, когда вы вызываете аксессуар и будете сохраняться при использовании метода push.

+0

Это позволит получить все связанные элементы. Вместо этого следует: return $ this-> items() -> orderBy ('created_at', 'desc') -> first() '. – Hkan

+0

да, было. Однако, независимо от того, будет ли это ** ** быть или нет, зависит от требований. Редактировать для получения дополнительной информации. –

+1

эй! Не знал об этом методе 'setRelation()'. Выглядит довольно круто. – Hkan

0

@djt Я искал также для решения, где я могу eager load relationship with only one item, и попробовал все , и, кажется, нет такого решения, кроме joins

Collection::select('items.item_name as name', 'items_sub.sub_name as subname') 
->leftJoin('items_sub', function ($join) { 
    $join->on('items.id', '=', 'items_sub.item_id')->where('items_sub.type', '=', 0); 
})->get(); 

Таким образом, вы получите все Collection function helpers а также уменьшить количество запросов вы делаете в БД, Потому что когда вы eager load with Eloquent, он делает как минимум 2 запросов к DB Я добавил where jsut в качестве примера.