hasOneThrough与数据透视表laravel雄辩

时间:2019-09-13 19:01:22

标签: laravel eloquent

我有下表

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

2 个答案:

答案 0 :(得分:1)

我在计算机上全新安装了laravel,并根据您提供的信息建立了模型和关系,而我想到的最简单的解决方案是:

public function event()
{
    return $this->hasOneThrough(Event::class, EventSchool::class,
        'event_id', 'id', 'id', 'event_id'
    );
}

这是我所做的测试:

// Within some controller:
$record = Record::find(2);
dd($record->event);

这是结果,我认为这是您要寻找的结果:

Event {#303 ▼
  #connection: "pgsql"
  #table: "events"
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  #perPage: 15
  +exists: true
  +wasRecentlyCreated: false
  #attributes: array:6 [▼
    "id" => 2
    "name" => "Event 2"
    "category_id" => 2
    "created_at" => "2019-09-16 03:15:07"
    "updated_at" => "2019-09-16 03:15:07"
    "laravel_through_key" => 2
  ]
  #original: array:6 [▶]
  #changes: []
  #casts: []
  #dates: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  +timestamps: true
  #hidden: []
  #visible: []
  #fillable: []
  #guarded: array:1 [▶]
}

希望有帮助。

答案 1 :(得分:1)

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

您已经有了有关外键(notes)的其他信息。如果您有School,并且需要notes中的Event,但是您不需要Event,则只要数据透视表具有模型,就可以这样做。
当然,您可以使用join来完成此操作,而无需模型。

此处的关键是从Pivot而不是Model扩展。它要做的一件事是使表名成为单数。但是您不能使用SoftDeletes(您真的需要吗?这没有多大意义)

  

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

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

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

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

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

现在,hasOneThrough可以满足您的需求。您需要类似belongsToThrough的东西,但是它不存在。您可以使用的是accessor

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会完全按照您的期望去做。