简体   繁体   中英

Issue with Laravel Eloquent Many-to-Many relationship

I have the following setup, three tables, tracks , tags and tag_track

tracks

CREATE TABLE `tracks` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `mdbid` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
  `track_no` int(11) NOT NULL,
  `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `sort_title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `safe_title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `album_mdbid` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `deleted_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `tracks_mdbid_unique` (`mdbid`)
) ENGINE=InnoDB AUTO_INCREMENT=603 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

tags

CREATE TABLE `tags` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `mdbid` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
  `text` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `tags_mdbid_unique` (`mdbid`),
  UNIQUE KEY `tags_text_unique` (`text`)
) ENGINE=InnoDB AUTO_INCREMENT=3376 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

tag_track

CREATE TABLE `tag_track` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `tag_mdbid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `track_mdbid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  KEY `tag_track_tag_mdbid_index` (`tag_mdbid`),
  KEY `tag_track_track_mdbid_index` (`track_mdbid`),
  CONSTRAINT `tag_track_track_mdbid_foreign` FOREIGN KEY (`track_mdbid`) REFERENCES `tracks` (`mdbid`) ON DELETE CASCADE,
  CONSTRAINT `tag_track_tag_mdbid_foreign` FOREIGN KEY (`tag_mdbid`) REFERENCES `tags` (`mdbid`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Track

class Track extends \Eloquent {

  // Add your validation rules here
  public static $rules = [
    // 'title' => 'required'
  ];

  // Don't forget to fill this array
  protected $fillable = [];

    public function album() {
        return $this->belongsTo('Album', 'album_mdbid', 'mdbid');
    }

    public function getTags() {
        return $this->hasMany('Tag', 'tag_track', 'tag_mdbid', 'track_mdbid');
    }

}

Tag

class Tag extends \Eloquent {

  // Add your validation rules here
  public static $rules = [
    // 'title' => 'required'
  ];

  // Don't forget to fill this array
  protected $fillable = [];

    public function getTracks() {
        return $this->hasMany('Track', 'tag_track', 'tag_mdbid', 'track_mdbid');
    }
}

Routes

Route::get('/', function()
{
    // When I uncomment the line below it finds the tag details
    // $tag = Tag::where('mdbid', '=', 'mR3YQxbayRP1RwGzvEJvXe1BcFPukMSP');
    $track = Track::find(1);
    return $track->tags;
});

When I go to the route in the browser, nothing is shown

UPDATE

I have now got it displaying the correct number of results, but only after changing the pivot table to integers, before I was using a 32 length alphanumeric field. How can I get this to work?

Change getTags() to tags() on the Track model, or use $track->getTags like you defined on the model.

And since you have many-to-many relationship between tags and tracks, change the definitions:

// on Tag model
public function getTracks() {
    return $this->belongsToMany('Track', 'tag_track', 'tag_mdbid', 'track_mdbid');
}


// on Track model
public function getTags() {
    return $this->belongsToMany('Tag', 'tag_track', 'track_mdbid', 'tag_mdbid');
}

And why you don't want to setup relation on the primary ids but mdbids?

try renaming the function getTags() to tags() and then use

$track->tags()->getResults();

the tags() function will return a HasMany object this object represent the many to many relation the getResults() function return the results of the relation that means the tags related to the track in your case. I hope this will be helpful

The relationship to use for a many-to-many is belongsToMany() and you've also got some foreign keys out of order.

Change getTracks() to return $this->belongsToMany('Track', 'tag_track', 'track_mdbid', 'tag_mdbid');

Change getTags() to return $this->belongsToMany('Tag', 'tag_track', 'tag_mdbid', 'track_mdbid');

Additionally as others have pointed out, you must change these function names to tags() and tracks() or call them appropriately when trying to use them.

Route::get('/', function()
{
    // When I uncomment the line below it finds the tag details
    // $tag = Tag::where('mdbid', '=', 'mR3YQxbayRP1RwGzvEJvXe1BcFPukMSP');
    $track = Track::find(1);
    return $track->getTags;
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM