Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
292 views
in Technique[技术] by (71.8m points)

php - Laravel hasManyThrough

I'm struggling to get my head around a hasManyThrough concept with laravel. I have three tables:

Bookings
    -id (int)
    -some other fields

Meta
    -id (int)
    -booking_id (int)
    -metatype_id (int)
    -some other fields

MetaType
    -id (int)
    -name (string)
    -some other fields

What I am trying to get is an Eloquent model that allows me to have a single booking record with multiple Meta records of type MetaType. I thought that hasManyThrough might have solved this, but now I am thinking that perhaps this is not the best way.

In my booking model I have

public function bookingmeta() {
    return $this->hasMany('bookingmeta','booking_id');
}

public function bookingmetatype() {
    return $this->hasManyThrough('bookingmetatype','bookingmeta','booking_id','bookingmetatype_id');
}

But this fails to generate the correct SQL and fails. I get

select `new_bookingmetatype`.*, `new_bookingmeta`.`booking_id` 
from `new_bookingmetatype` 
inner join `new_bookingmeta` 
on `new_bookingmeta`.`bookingmetatype_id` = `new_bookingmetatype`.`id` 
where `new_bookingmeta`.`booking_id` in (57103)

Whereas what I am really trying to achieve is

select `new_bookingmetatype`.*, `new_bookingmeta`.`booking_id` 
from `new_bookingmetatype` 
inner join `new_bookingmeta` 
on `new_bookingmeta`.`id` = `new_bookingmetatype`.`bookingmetatype_id`  
where `new_bookingmeta`.`booking_id` in (57103)

If anyone can point me in the right direction I'd really appreciate it. Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

hasManyThrough is not the way at all. It works only for relations like this:

A hasMany/hasOne B, B hasMany/hasOne C, then A hasManyThrough C (through B)

What you have here is a many to many (belongsToMany), with meta being the pivot table.

So you can do this (assuming meta is table name, Booking and MetaType are models):

// Booking model
public function meta()
{
  return $this->belongsToMany('MetaType', 'meta', 'booking_id', 'metatype_id')
        ->withPivot([ ARRAY OF FIELDS YOU NEED FROM meta TABLE ]);
}

Then you can access all associated MetaType:

$booking->meta; // collection of MetaType models

query it like this (eager loading):

$booking = Booking::with(['meta' => function ($q) {

  // query related table
  $q->where('someFieldOnMetaTypeTable', 'someValue')

    // and / or pivot table
    ->wherePivot('someFieldOnMetaTable', 'anotherValue');

}])->first();

or set constraints on the related table to filter the Booking:

$booking = Booking::whereHas('meta', function ($q) {

  // query related table
  $q->where('someFieldOnMetaTypeTable', 'someValue')

    // and / or pivot table
    ->where('meta.someFieldOnMetaTable', 'anotherValue');

})->first();

Note: wherePivot works only when you eager load the relationship, so you can't use it in whereHas closure.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...