Jadual Kandungan
关联关系
定义反向关系
One To Many
定义反向关联
Many To Many
反向关联关系
检索中间表的列值
Has Many Through
Polymorphic Relations (多态关联)
检索多态关系
多对多的多态关联
关联关系查询
查询关系存在性
预加载
带约束的预加载
关联模型插入" >关联模型插入
save方法
保存多个关联模型
save方法和多对多关联
create方法
更新 “Belongs To” 关系
Many to Many 关系
更新中间表(关联表)字段
Rumah pembangunan bahagian belakang tutorial php Laravel框架-EloquentORM进阶部分的详细介绍

Laravel框架-EloquentORM进阶部分的详细介绍

Mar 21, 2017 am 09:18 AM

关联关系

One To One
假设User模型关联了Phone模型,要定义这样一个关联,需要在User模型中定义一个phone方法,该方法返回一个hasOne方法定义的关联

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{
    /**
     * Get the phone record associated with the user.
     */
    public function phone()
    {
        return $this->hasOne(&#39;App\Phone&#39;);
    }
}
Salin selepas log masuk

hasOne方法的第一个参数为要关联的模型,定义好之后,可以使用下列语法查询到关联属性了

$phone = User::find(1)->phone;
Salin selepas log masuk

Eloquent会假定关联的外键是基于模型名称的,因此Phone模型会自动使用user_id字段作为外键,可以使用第二个参数和第三个参数覆盖

return $this->hasOne(&#39;App\Phone&#39;, &#39;foreign_key&#39;);return $this->hasOne(&#39;App\Phone&#39;, &#39;foreign_key&#39;, &#39;local_key&#39;);
Salin selepas log masuk

定义反向关系

定义上述的模型之后,就可以使用User模型获取Phone模型了,当然也可以通过Phone模型获取所属的User了,这就用到了belongsTo方法了

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Phone extends Model{
    /**
     * Get the user that owns the phone.
     */
    public function user()
    {
        return $this->belongsTo(&#39;App\User&#39;);        // return $this->belongsTo(&#39;App\User&#39;, &#39;foreign_key&#39;);
        // return $this->belongsTo(&#39;App\User&#39;, &#39;foreign_key&#39;, &#39;other_key&#39;);

    }
}
Salin selepas log masuk

One To Many

假设有一个帖子,它有很多关联的评论信息,这种情况下应该使用一对多的关联,使用hasMany方法

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Post extends Model{
    /**
     * Get the comments for the blog post.
     */
    public function comments()
    {
        return $this->hasMany(&#39;App\Comment&#39;);
    }
}
Salin selepas log masuk

查询操作

$comments = App\Post::find(1)->comments;
foreach ($comments as $comment) {    //}

$comments = App\Post::find(1)->comments()->where(&#39;title&#39;, &#39;foo&#39;)->first();
Salin selepas log masuk

定义反向关联

反向关联也是使用belongsTo方法,参考One To One部分。

$comment = App\Comment::find(1);
echo $comment->post->title;
Salin selepas log masuk

Many To Many

多对多关联因为多了一个中间表,实现起来比hasOne和hasMany复杂一些。

考虑这样一个场景,用户可以属于多个角色,一个角色也可以属于多个用户。这就引入了三个表: users, roles, role_user。其中role_user表为关联表,包含两个字段user_id和role_id。

多对多关联需要使用belongsToMany方法

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{
    /**
     * The roles that belong to the user.
     */
    public function roles()
    {
        // 指定关联表
        // return $this->belongsToMany(&#39;App\Role&#39;, &#39;role_user&#39;);
        // 指定关联表,关联字段
        // return $this->belongsToMany(&#39;App\Role&#39;, &#39;role_user&#39;, &#39;user_id&#39;, &#39;role_id&#39;);

        return $this->belongsToMany(&#39;App\Role&#39;);
    }
}
Salin selepas log masuk

上述定义了一个用户属于多个角色,一旦该关系确立,就可以查询了

user = App\User::find(1);
foreach ($user->roles as $role) {    //}$roles = App\User::find(1)->roles()->orderBy(&#39;name&#39;)->get();
Salin selepas log masuk

反向关联关系

反向关系与正向关系实现一样

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Role extends Model{
    /**
     * The users that belong to the role.
     */
    public function users()
    {
        return $this->belongsToMany(&#39;App\User&#39;);
    }
}
Salin selepas log masuk

检索中间表的列值

对多对多关系来说,引入了一个中间表,因此需要有方法能够查询到中间表的列值,比如关系确立的时间等,使用pivot属性查询中间表

$user = App\User::find(1);

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}
Salin selepas log masuk

上述代码访问了中间表的created_at字段。

注意的是,默认情况下之后模型的键可以通过pivot对象进行访问,如果中间表包含了额外的属性,在指定关联关系的时候,需要使用withPivot方法明确的指定列名

return $this->belongsToMany(&#39;App\Role&#39;)->withPivot(&#39;column1&#39;, &#39;column2&#39;);
Salin selepas log masuk

Has Many Through

这种关系比较强大,假设这样一个场景:Country模型下包含了多个User模型,而每个User模型又包含了多个Post模型,也就是说一个国家有很多用户,而这些用户都有很多帖子,我们希望查询某个国家的所有帖子,怎么实现呢,这就用到了Has Many Through关系

countries    id - integer
    name - stringusers    id - integer
    country_id - integer
    name - stringposts    id - integer
    user_id - integer
    title - string
Salin selepas log masuk

可以看到,posts表中并不直接包含country_id,但是它通过users表与countries表建立了关系

使用Has Many Through关系

namespace App;

use Illuminate\Database\Eloquent\Model;class Country extends Model{    /**
     * Get all of the posts for the country.
     */
    public function posts()
    {        // return $this->hasManyThrough(&#39;App\Post&#39;, &#39;App\User&#39;, &#39;country_id&#39;, &#39;user_id&#39;);

        return $this->hasManyThrough(&#39;App\Post&#39;, &#39;App\User&#39;);
    }
}
Salin selepas log masuk

方法hasManyThrough的第一个参数是我们希望访问的模型名称,第二个参数是中间模型名称。

HasManyThrough hasManyThrough( 
    string $related, 
    string $through, 
    string|null $firstKey = null, 
    string|null $secondKey = null, 
    string|null $localKey = null)
Salin selepas log masuk

Polymorphic Relations (多态关联)

多态关联使得同一个模型使用一个关联就可以属于多个不同的模型,假设这样一个场景,我们有一个帖子表和一个评论表,用户既可以对帖子执行喜欢操作,也可以对评论执行喜欢操作,这样的情况下该怎么处理呢?

表结构如下

posts    id - integer
    title - string
    body - textcomments    id - integer
    post_id - integer
    body - textlikes    id - integer
    likeable_id - integer
    likeable_type - string
Salin selepas log masuk

可以看到,我们使用likes表中的likeable_type字段判断该记录喜欢的是帖子还是评论,表结构有了,接下来就该定义模型了

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;class Like extends Model{    /**
     * Get all of the owning likeable models.
     */
    public function likeable()
    {        return $this->morphTo();
    }
}class Post extends Model{    /**
     * Get all of the product&#39;s likes.
     */
    public function likes()
    {        return $this->morphMany(&#39;App\Like&#39;, &#39;likeable&#39;);
    }
}class Comment extends Model{    /**
     * Get all of the comment&#39;s likes.
     */
    public function likes()
    {        return $this->morphMany(&#39;App\Like&#39;, &#39;likeable&#39;);
    }
}
Salin selepas log masuk

默认情况下,likeable_type的类型是关联的模型的完整名称,比如这里就是App\Post和App\Comment。

通常情况下我们可能会使用自定义的值标识关联的表名,因此,这就需要自定义这个值了,我们需要在项目的服务提供者对象的boot方法中注册关联关系,比如AppServiceProvider的boot方法中

use Illuminate\Database\Eloquent\Relations\Relation;Relation::morphMap([    &#39;posts&#39; => App\Post::class,
    &#39;likes&#39; => App\Like::class,]);
Salin selepas log masuk

检索多态关系

访问一个帖子所有的喜欢

$post = App\Post::find(1);  
foreach ($post->likes as $like) {    //}
Salin selepas log masuk

访问一个喜欢的帖子或者评论

$like = App\Like::find(1);   
$likeable = $like->likeable;
Salin selepas log masuk

上面的例子中,返回的likeable会根据该记录的类型返回帖子或者评论。

多对多的多态关联

多对多的关联使用方法morphToMany和morphedByMany,这里就不多废话了

关联关系查询

在Eloquent中,所有的关系都是使用函数定义的,可以在不执行关联查询的情况下获取关联的实例。假设我们有一个博客系统,User模型关联了很多Post模型:

/**
 * Get all of the posts for the user.
 */public function posts()
{   return $this->hasMany(&#39;App\Post&#39;);
}
Salin selepas log masuk

你可以像下面这样查询关联并且添加额外的约束

$user = App\User::find(1);$user->posts()->where(&#39;active&#39;, 1)->get();
Salin selepas log masuk

如果不需要对关联的属性添加约束,可以直接作为模型的属性访问,例如上面的例子,我们可以使用下面的方式访问User的Post

$user = App\User::find(1);foreach ($user->posts as $post) {    //}
Salin selepas log masuk

动态的属性都是延迟加载的,它们只有在被访问的时候才会去查询数据库,与之对应的是预加载,预加载可以使用关联查询出所有数据,减少执行sql的数量。

查询关系存在性

使用has方法可以基于关系的存在性返回结果

// 检索至少有一个评论的所有帖子...$posts = App\Post::has(&#39;comments&#39;)->get();
// Retrieve all posts that have three or more comments...$posts = Post::has(&#39;comments&#39;, &#39;>=&#39;, 3)->get();
// Retrieve all posts that have at least one comment with votes...$posts = Post::has(&#39;comments.votes&#39;)->get();
Salin selepas log masuk

如果需要更加强大的功能,可以使用whereHas和orWhereHas方法,把where条件放到has语句中。

// 检索所有至少存在一个匹配foo%的评论的帖子$posts = Post::whereHas(&#39;comments&#39;, function ($query) {    
$query->where(&#39;content&#39;, &#39;like&#39;, &#39;foo%&#39;);
})->get();
Salin selepas log masuk

预加载

在访问Eloquent模型的时候,默认情况下所有的关联关系都是延迟加载的,在使用的时候才会开始加载,这就造成了需要执行大量的sql的问题,使用预加载功能可以使用关联查询出所有结果

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Book extends Model{
    /**
     * Get the author that wrote the book.
     */
    public function author()
    {
        return $this->belongsTo(&#39;App\Author&#39;);
    }
}
Salin selepas log masuk

接下来我们检索所有的书和他们的作者

$books = App\Book::all();
foreach ($books as $book) {    
echo $book->author->name;
}
Salin selepas log masuk

上面的查询将会执行一个查询查询出所有的书,然后在遍历的时候再执行N个查询查询出作者信息,显然这样做是非常低效的,幸好我们还有预加载功能,可以将这N+1个查询减少到2个查询,在查询的时候,可以使用with方法指定哪个关系需要预加载。

$books = App\Book::with(&#39;author&#39;)->get();
foreach ($books as $book) {
    echo $book->author->name;
}
Salin selepas log masuk

对于该操作,会执行下列两个sql

select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)
Salin selepas log masuk

预加载多个关系

$books = App\Book::with(&#39;author&#39;, &#39;publisher&#39;)->get();
Salin selepas log masuk

嵌套的预加载

$books = App\Book::with(&#39;author.contacts&#39;)->get();
Salin selepas log masuk

带约束的预加载

$users = App\User::with([&#39;posts&#39; => function ($query) {
    $query->where(&#39;title&#39;, &#39;like&#39;, &#39;%first%&#39;);
}])->get();$users = App\User::with([&#39;posts&#39; => function ($query) {
    $query->orderBy(&#39;created_at&#39;, &#39;desc&#39;);
}])->get();
Salin selepas log masuk

延迟预加载#

有时候,在上级模型已经检索出来之后,可能会需要预加载关联数据,可以使用load方法

$books = App\Book::all();if ($someCondition) {    $books->load(&#39;author&#39;, &#39;publisher&#39;);
}$books->load([&#39;author&#39; => function ($query) {
    $query->orderBy(&#39;published_date&#39;, &#39;asc&#39;);
}]);
Salin selepas log masuk

关联模型插入

save方法

保存单个关联模型

$comment = new App\Comment([&#39;message&#39; => &#39;A new comment.&#39;]);
$post = App\Post::find(1);$post->comments()->save($comment);
Salin selepas log masuk

保存多个关联模型

$post = App\Post::find(1); 
$post->comments()->saveMany([    
new App\Comment([&#39;message&#39; => &#39;A new comment.&#39;]),    
new App\Comment([&#39;message&#39; => &#39;Another comment.&#39;]),
]);
Salin selepas log masuk

save方法和多对多关联

多对多关联可以为save的第二个参数指定关联表中的属性

App\User::find(1)->roles()->save($role, [&#39;expires&#39; => $expires]);
Salin selepas log masuk

上述代码会更新中间表的expires字段。

create方法

使用create方法与save方法的不同在于它是使用数组的形式创建关联模型的

$post = App\Post::find(1);$comment = $post->comments()->create([
    &#39;message&#39; => &#39;A new comment.&#39;,]);
Salin selepas log masuk

更新 “Belongs To” 关系

更新belongsTo关系的时候,可以使用associate方法,该方法会设置子模型的外键

$account = App\Account::find(10);
$user->account()->associate($account);
$user->save();
Salin selepas log masuk

要移除belongsTo关系的话,使用dissociate方法

$user->account()->dissociate();$user->save();
Salin selepas log masuk

Many to Many 关系

中间表查询条件#

当查询时需要对使用中间表作为查询条件时,可以使用wherePivotwherePivotInorWherePivotorWherePivotIn添加查询条件。

$enterprise->with([&#39;favorites&#39; => function($query) {    
$query->wherePivot(&#39;enterprise_id&#39;, &#39;=&#39;, 12)->select(&#39;id&#39;);
}]);
Salin selepas log masuk

Attaching / Detaching#

$user = App\User::find(1);
// 为用户添加角色
$user->roles()->attach($roleId);
// 为用户添加角色,更新中间表的expires字段
$user->roles()->attach($roleId, [&#39;expires&#39; => $expires]);
// 移除用户的单个角色
$user->roles()->detach($roleId);
// 移除用户的所有角色
$user->roles()->detach();
Salin selepas log masuk

attach和detach方法支持数组参数,同时添加和移除多个

$user = App\User::find(1);
$user->roles()->detach([1, 2, 3]);
$user->roles()->attach([1 => [&#39;expires&#39; => $expires], 2, 3]);
Salin selepas log masuk

更新中间表(关联表)字段

使用updateExistingPivot方法更新中间表

$user = App\User::find(1);$user->roles()->updateExistingPivot($roleId, $attributes);
Salin selepas log masuk

同步中间表(同步关联关系)#

使用sync方法,可以指定两个模型之间只存在指定的关联关系

$user->roles()->sync([1, 2, 3]);
$user->roles()->sync([1 => [&#39;expires&#39; => true], 2, 3]);
Salin selepas log masuk

上述两个方法都会让用户只存在1,2,3三个角色,如果用户之前存在其他角色,则会被删除。

更新父模型的时间戳#

假设场景如下,我们为一个帖子增加了一个新的评论,我们希望这个时候帖子的更新时间会相应的改变,这种行为在Eloquent中是非常容易实现的。

在子模型中使用$touches属性实现该功能

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;class Comment extends Model{    /**
     * All of the relationships to be touched.
     *
     * @var array
     */
    protected $touches = [&#39;post&#39;];    /**
     * Get the post that the comment belongs to.
     */
    public function post()
    {        return $this->belongsTo(&#39;App\Post&#39;);
    }
}
Salin selepas log masuk

现在,更新评论的时候,帖子的updated_at字段也会被更新

$comment = App\Comment::find(1);$comment->text = &#39;Edit to this comment!&#39;;$comment->save();
Salin selepas log masuk

Atas ialah kandungan terperinci Laravel框架-EloquentORM进阶部分的详细介绍. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bagaimana untuk mendapatkan kod pengembalian semasa menghantar e -mel gagal di Laravel? Bagaimana untuk mendapatkan kod pengembalian semasa menghantar e -mel gagal di Laravel? Apr 01, 2025 pm 02:45 PM

Kaedah untuk mendapatkan kod kembali apabila menghantar e -mel Laravel gagal. Apabila menggunakan Laravel untuk membangunkan aplikasi, anda sering menghadapi situasi di mana anda perlu menghantar kod pengesahan. Dan pada hakikatnya ...

Tugas Jadual Laravel tidak dilaksanakan: Apa yang harus saya lakukan jika tugas itu tidak berjalan selepas Jadual: Jalankan Perintah? Tugas Jadual Laravel tidak dilaksanakan: Apa yang harus saya lakukan jika tugas itu tidak berjalan selepas Jadual: Jalankan Perintah? Mar 31, 2025 pm 11:24 PM

Tugas Jadual Laravel menjalankan penyelesaian masalah yang tidak responsif semasa menggunakan penjadualan tugas jadual Laravel, banyak pemaju akan menghadapi masalah ini: Jadual: Jalankan ...

Di Laravel, bagaimana menangani situasi di mana kod pengesahan gagal dihantar melalui e -mel? Di Laravel, bagaimana menangani situasi di mana kod pengesahan gagal dihantar melalui e -mel? Mar 31, 2025 pm 11:48 PM

Kaedah mengendalikan kegagalan e -mel Laravel untuk menghantar kod pengesahan adalah menggunakan Laravel ...

Bagaimana untuk melaksanakan fungsi jadual tersuai untuk mengklik untuk menambah data dalam admin dcat? Bagaimana untuk melaksanakan fungsi jadual tersuai untuk mengklik untuk menambah data dalam admin dcat? Apr 01, 2025 am 07:09 AM

Cara melaksanakan fungsi jadual klik tersuai untuk menambah data dalam dcatadmin (laravel-admin) semasa menggunakan dcat ...

Laravel - Pelayan Buang Laravel - Pelayan Buang Aug 27, 2024 am 10:51 AM

Laravel - Dump Server - Laravel dump server datang dengan versi Laravel 5.7. Versi sebelumnya tidak termasuk pelayan dump. Pelayan dump akan menjadi kebergantungan pembangunan dalam fail komposer laravel/laravel.

Perkongsian Sambungan Laravel Redis: Mengapa kaedah pilih mempengaruhi sambungan lain? Perkongsian Sambungan Laravel Redis: Mengapa kaedah pilih mempengaruhi sambungan lain? Apr 01, 2025 am 07:45 AM

Kesan perkongsian sambungan Redis dalam rangka kerja Laravel dan pilih kaedah apabila menggunakan Rangka Kerja Laravel dan Redis, pemaju mungkin menghadapi masalah: melalui konfigurasi ...

Laravel Multi-Tenant Extension Stancl/Tenancy: Bagaimana Menyesuaikan Alamat Hos Sambungan Pangkalan Data Penyewa? Laravel Multi-Tenant Extension Stancl/Tenancy: Bagaimana Menyesuaikan Alamat Hos Sambungan Pangkalan Data Penyewa? Apr 01, 2025 am 09:09 AM

Sambungan pangkalan data penyewa tersuai dalam pakej lanjutan multi-penyewa Larave Stancl/penyewaan ketika membina aplikasi multi-penyewa menggunakan pakej lanjutan multi-penyewa Larave Stancl/penyewaan, ...

Laravel - URL Tindakan Laravel - URL Tindakan Aug 27, 2024 am 10:51 AM

Laravel - URL Tindakan - Laravel 5.7 memperkenalkan ciri baharu yang dipanggil &quot;URL tindakan boleh panggil&quot;. Ciri ini serupa dengan yang terdapat dalam Laravel 5.6 yang menerima kaedah rentetan dalam tindakan. Tujuan utama sintaks baharu memperkenalkan Laravel 5.7 adalah untuk mengarahkanl

See all articles