일대일
사용자모델이 전화 모델과 연관되어 있다고 가정합니다. 이러한 연관을 정의하려면 사용자에서 전화 방법을 정의해야 합니다. 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('App\Phone'); } }
에 의해 정의된 연관을 반환하는 모델 hasOne 메소드의 첫 번째 매개변수는 연관될 모델입니다. 정의된 후 다음 구문을 사용하여 연관 속성을 쿼리할 수 있습니다. >
$phone = User::find(1)->phone;
return $this->hasOne('App\Phone', 'foreign_key');return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Phone extends Model{ /** * Get the user that owns the phone. */ public function user() { return $this->belongsTo('App\User'); // return $this->belongsTo('App\User', 'foreign_key'); // return $this->belongsTo('App\User', 'foreign_key', 'other_key'); } }
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Post extends Model{ /** * Get the comments for the blog post. */ public function comments() { return $this->hasMany('App\Comment'); } }
역방향 연관을 정의하기 위한
$comments = App\Post::find(1)->comments; foreach ($comments as $comment) { //} $comments = App\Post::find(1)->comments()->where('title', 'foo')->first();
쿼리 작업
$comment = App\Comment::find(1); echo $comment->post->title;
다대다
사용자가 여러 역할에 속할 수 있고 역할도 여러 사용자에 속할 수 있는 시나리오를 생각해 보세요. 여기에는 users,roles,role_user라는 세 가지 테이블이 소개됩니다. role_user 테이블은 관련 테이블이며 user_id와 role_id라는 두 개의 필드를 포함합니다.
다대다 연결에는 presentsToMany 메소드가 필요합니다
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{ /** * The roles that belong to the user. */ public function roles() { // 指定关联表 // return $this->belongsToMany('App\Role', 'role_user'); // 指定关联表,关联字段 // return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id'); return $this->belongsToMany('App\Role'); } }
위에서는 사용자가 여러 역할에 속해 있음을 정의합니다. 일단 관계가 설정되면
user = App\User::find(1); foreach ($user->roles as $role) { //}$roles = App\User::find(1)->roles()->orderBy('name')->get();
를 쿼리할 수 있습니다. 역방향 연관 관계
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Role extends Model{ /** * The users that belong to the role. */ public function users() { return $this->belongsToMany('App\User'); } }
중간 테이블의 열 값 검색
$user = App\User::find(1); foreach ($user->roles as $role) { echo $role->pivot->created_at; }
위 코드는 중간 테이블의 Created_at 필드에 액세스합니다.
기본적으로 피벗
객체를 통해 모델의 키에 액세스할 수 있습니다. 중간 테이블에 추가 속성이 포함되어 있으면 연결을 지정할 때 withPivot 메서드를 사용해야 합니다. 열 이름 return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
countries id - integer name - stringusers id - integer country_id - integer name - stringposts id - integer user_id - integer title - string
보시다시피, 게시물 테이블에는 country_id가 직접 포함되어 있지 않지만, users 테이블을 통해 국가 테이블과 관계가 설정됩니다
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('App\Post', 'App\User', 'country_id', 'user_id'); return $this->hasManyThrough('App\Post', 'App\User'); } }
의 첫 번째 매개변수는 hasManyThrough 메소드는 액세스하려는 모델의 이름이고 두 번째 매개변수는 중간 모델 이름입니다.
HasManyThrough hasManyThrough( string $related, string $through, string|null $firstKey = null, string|null $secondKey = null, string|null $localKey = null)
다형성 관계(다형성 연관)
테이블 구조는 다음과 같습니다
posts id - integer title - string body - textcomments id - integer post_id - integer body - textlikes id - integer likeable_id - integer likeable_type - string
보시는 바와 같이 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's likes. */ public function likes() { return $this->morphMany('App\Like', 'likeable'); } }class Comment extends Model{ /** * Get all of the comment's likes. */ public function likes() { return $this->morphMany('App\Like', 'likeable'); } }
기본적으로 likeable_type 유형은 AppPost 및 AppComment와 같은 관련 모델의 전체 이름입니다.
일반적으로 사용자 정의 값을 사용하여 연관된 테이블 이름을 식별할 수 있으므로 이 값을 사용자 정의해야 합니다. 예를 들어 프로젝트 서비스 제공자 객체의 부팅 메소드에 연결을 등록해야 합니다. ,
의 부팅 방법에서use Illuminate\Database\Eloquent\Relations\Relation;Relation::morphMap([ 'posts' => App\Post::class, 'likes' => App\Like::class,]);
AppServiceProvider
는 다형성 관계를 검색합니다. $post = App\Post::find(1); foreach ($post->likes as $like) { //}
는 좋아요를 누른 게시물이나 댓글에 액세스합니다.
$like = App\Like::find(1); $likeable = $like->likeable;
위 예에서 반환된 likeable은 레코드 유형에 따라 게시물이나 댓글을 반환합니다.
다대다 다형성 연관
연관 관계 쿼리
함수를 사용하여 정의됩니다. 블로그 시스템이 있고 User 모델이 많은 Post 모델과 연결되어 있다고 가정합니다. /**
* Get all of the posts for the user.
*/public function posts()
{ return $this->hasMany('App\Post');
}
$user = App\User::find(1);$user->posts()->where('active', 1)->get();
$user = App\User::find(1);foreach ($user->posts as $post) { //}
动态的属性都是延迟加载的,它们只有在被访问的时候才会去查询数据库,与之对应的是预加载,预加载可以使用关联查询出所有数据,减少执行sql的数量。
使用has方法可以基于关系的存在性返回结果
// 检索至少有一个评论的所有帖子...$posts = App\Post::has('comments')->get(); // Retrieve all posts that have three or more comments...$posts = Post::has('comments', '>=', 3)->get(); // Retrieve all posts that have at least one comment with votes...$posts = Post::has('comments.votes')->get();
如果需要更加强大的功能,可以使用whereHas和orWhereHas方法,把where条件放到has语句中。
// 检索所有至少存在一个匹配foo%的评论的帖子$posts = Post::whereHas('comments', function ($query) { $query->where('content', 'like', 'foo%'); })->get();
在访问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('App\Author'); } }
接下来我们检索所有的书和他们的作者
$books = App\Book::all(); foreach ($books as $book) { echo $book->author->name; }
上面的查询将会执行一个查询查询出所有的书,然后在遍历的时候再执行N个查询查询出作者信息,显然这样做是非常低效的,幸好我们还有预加载功能,可以将这N+1个查询减少到2个查询,在查询的时候,可以使用with方法指定哪个关系需要预加载。
$books = App\Book::with('author')->get(); foreach ($books as $book) { echo $book->author->name; }
对于该操作,会执行下列两个sql
select * from books select * from authors where id in (1, 2, 3, 4, 5, ...)
预加载多个关系
$books = App\Book::with('author', 'publisher')->get();
嵌套的预加载
$books = App\Book::with('author.contacts')->get();
$users = App\User::with(['posts' => function ($query) { $query->where('title', 'like', '%first%'); }])->get();$users = App\User::with(['posts' => function ($query) { $query->orderBy('created_at', 'desc'); }])->get();
延迟预加载#
有时候,在上级模型已经检索出来之后,可能会需要预加载关联数据,可以使用load方法
$books = App\Book::all();if ($someCondition) { $books->load('author', 'publisher'); }$books->load(['author' => function ($query) { $query->orderBy('published_date', 'asc'); }]);
保存单个关联模型
$comment = new App\Comment(['message' => 'A new comment.']); $post = App\Post::find(1);$post->comments()->save($comment);
$post = App\Post::find(1); $post->comments()->saveMany([ new App\Comment(['message' => 'A new comment.']), new App\Comment(['message' => 'Another comment.']), ]);
多对多关联可以为save的第二个参数指定关联表中的属性
App\User::find(1)->roles()->save($role, ['expires' => $expires]);
上述代码会更新中间表的expires字段。
使用create方法与save方法的不同在于它是使用数组的形式创建关联模型的
$post = App\Post::find(1);$comment = $post->comments()->create([ 'message' => 'A new comment.',]);
更新belongsTo关系的时候,可以使用associate方法,该方法会设置子模型的外键
$account = App\Account::find(10); $user->account()->associate($account); $user->save();
要移除belongsTo关系的话,使用dissociate方法
$user->account()->dissociate();$user->save();
中间表查询条件#
当查询时需要对使用中间表作为查询条件时,可以使用wherePivot
, wherePivotIn
,orWherePivot
,orWherePivotIn
添加查询条件。
$enterprise->with(['favorites' => function($query) { $query->wherePivot('enterprise_id', '=', 12)->select('id'); }]);
Attaching / Detaching#
$user = App\User::find(1); // 为用户添加角色 $user->roles()->attach($roleId); // 为用户添加角色,更新中间表的expires字段 $user->roles()->attach($roleId, ['expires' => $expires]); // 移除用户的单个角色 $user->roles()->detach($roleId); // 移除用户的所有角色 $user->roles()->detach();
attach和detach方法支持数组参数,同时添加和移除多个
$user = App\User::find(1); $user->roles()->detach([1, 2, 3]); $user->roles()->attach([1 => ['expires' => $expires], 2, 3]);
使用updateExistingPivot方法更新中间表
$user = App\User::find(1);$user->roles()->updateExistingPivot($roleId, $attributes);
同步中间表(同步关联关系)#
使用sync方法,可以指定两个模型之间只存在指定的关联关系
$user->roles()->sync([1, 2, 3]); $user->roles()->sync([1 => ['expires' => true], 2, 3]);
上述两个方法都会让用户只存在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 = ['post']; /** * Get the post that the comment belongs to. */ public function post() { return $this->belongsTo('App\Post'); } }
现在,更新评论的时候,帖子的updated_at字段也会被更新
$comment = App\Comment::find(1);$comment->text = 'Edit to this comment!';$comment->save();
위 내용은 Laravel 프레임워크 - EloquentORM의 고급 부분에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!