首页 > 解决方案 > hasOneThrough 与数据透视表 laravel 雄辩

问题描述

我有以下表格

mysql> describe records;
+-----------------+---------------------+------+-----+---------+----------------+
| Field           | Type                | Null | Key | Default | Extra          |
+-----------------+---------------------+------+-----+---------+----------------+
| id              | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| event_school_id | bigint(20) unsigned | NO   | MUL | NULL    |                |
| athlete_id      | bigint(20) unsigned | NO   | MUL | NULL    |                |
| year            | int(10) unsigned    | NO   |     | NULL    |                |
| place           | int(10) unsigned    | NO   |     | NULL    |                |
| created_at      | timestamp           | YES  |     | NULL    |                |
| updated_at      | timestamp           | YES  |     | NULL    |                |
| deleted_at      | timestamp           | YES  |     | NULL    |                |
+-----------------+---------------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)

mysql> describe event_school;
+------------+---------------------+------+-----+---------+----------------+
| Field      | Type                | Null | Key | Default | Extra          |
+------------+---------------------+------+-----+---------+----------------+
| id         | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| event_id   | bigint(20) unsigned | NO   | MUL | NULL    |                |
| school_id  | bigint(20) unsigned | NO   | MUL | NULL    |                |
| notes      | text                | NO   |     | NULL    |                |
| created_at | timestamp           | YES  |     | NULL    |                |
| updated_at | timestamp           | YES  |     | NULL    |                |
| deleted_at | timestamp           | YES  |     | NULL    |                |
+------------+---------------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

mysql> describe events;
+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| id          | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| name        | varchar(191)        | NO   |     | NULL    |                |
| category_id | bigint(20) unsigned | NO   | MUL | NULL    |                |
| created_at  | timestamp           | YES  |     | NULL    |                |
| updated_at  | timestamp           | YES  |     | NULL    |                |
| deleted_at  | timestamp           | YES  |     | NULL    |                |
+-------------+---------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

从我的 Record Eloquent 模型中,我如何从记录中获取事件。它需要通过 event_school 数据透视表;但我没有 EventSchool 的模型。我需要做一个吗?如果没有 EventSchool 模型,有没有办法做到这一点?

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class EventSchool extends Model
{
    use SoftDeletes;
    protected $guarded = ['id'];
    protected $table = 'event_school';

    public function event()
    {
        return $this->belongsTo('App\Event');
    }

    public function school()
    {
        return $this->belongsTo('App\School');
    }

}
namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Record extends Model
{
    use SoftDeletes;
    protected $guarded = ['id'];

    public function athlete()
    {
        return $this->belongsTo('App\Athlete');
    }

    function event_school()
    {
        return $this->belongsTo('App\EventSchool','event_school_id');
    }

    function event()
    {
        //What can I put here to complete method

        //right now have to do \App\Record::find(1)->event_school->event

        //Want to do \App\Record::find(1)->event
    }
}

编辑:

这是答案之一的输出

>>> \App\Record::find(3)->event_school->event
=> App\Event {#3035
     id: 1,
     name: "100 Meter",
     category_id: 1,
     created_at: null,
     updated_at: null,
     deleted_at: null,
   }
>>> \App\Record::find(3)->event
=> null

标签: laraveleloquent

解决方案


每次我遇到这种情况时,我最终都会为数据透视表创建一个模型。这样做的另一个好处是,您可以直接访问该表,而无需带入关系的另一端。

您已经拥有外键 ( notes) 的附加信息。如果您有 aSchool并且需要notesfrom an Event,但不需要Event,则如果数据透视表有模型,则可以这样做。
当然,您可以join在不需要模型的情况下使用 a 来完成。

这里的关键是扩展 fromPivot而不是Model. 它所做的一件事是将表名设为单数。但是你不能使用SoftDeletes(你真的需要它吗?它没有多大意义)

注意:Pivot 模型可能不使用 SoftDeletes 特征。如果您需要软删除数据透视记录,请考虑将数据透视模型转换为实际的 Eloquent 模型。

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class EventSchool extends Pivot
{
    protected $guarded = ['id'];

    public function event()
    {
        return $this->belongsTo(Event::class);
    }

    public function school()
    {
        return $this->belongsTo(School::class);
    }
}

现在,hasOneThrough与您需要的相反。你需要类似的东西belongsToThrough,但它不存在。您可以使用的是访问器

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Record extends Model
{
    use SoftDeletes;

    protected $guarded = ['id'];

    public function athlete()
    {
        return $this->belongsTo(Athlete::class);
    }

    function eventSchool()
    {
        return $this->belongsTo(EventSchool::class);
    }

    function getEventAttribute()
    {
        return $this->eventSchool->event;
    }
}

\App\Record::find(1)->event会做你期望它做的事情。


推荐阅读