资讯专栏INFORMATION COLUMN

【整理】Laravel中Eloquent ORM 关联关系的操作

bovenson / 3352人阅读

摘要:从属关联关系更新关联使用方法,该方法会在子模型设置外键移除关联的时候,使用方法。使得这项操作变得简单,只需要添加包含关联关系名称的属性到子模型即可触发的所有关联关系关联关系更新时,所属模型将也会更新其值

Laravel中Eloquent ORM 关联关系的操作 关联数据 定义关联关系

一对一

hasOne("AppPhone"); 
        // 外键应该在父级上有一个与之匹配的id(或者自定义 $primaryKey)
        // return $this->hasOne("AppPhone", "foreign_key");
        // 用User的local_key,匹配Phone的foreign_key
       // return $this->hasOne("AppPhone", "foreign_key", "local_key");
    }
}

$phone = User::find(1)->phone; // 获取用户的手机模型

相对的关联

belongsTo("AppUser");
        // return $this->belongsTo("AppUser", "foreign_key");
        // return $this->belongsTo("AppUser", "foreign_key", "other_key");
    }
}

$user = Phone::find(1)->user; // 查询phone的id=1对应的user
$user = Phone::where("number","188**")->first()->user; // 查询电话为188的用户

一对多

class User extends Model{
    // 获取文章
    public function article()
    {
         return $this->hasMany("AppComment");
         // return $this->hasMany("AppComment", "foreign_key");
         // return $this->hasMany("AppComment", "foreign_key", "local_key");
    }
}
$articles = User::find(1)->article; // 返回 userid为1 的所有文章
$article = User::find(1)->article()->where("title", "aa")->first(); // 返回某一篇

一对多(逆向)

class Article extends Model{
    public function user()
    {
        return $this->belongsTo("AppUser");
        // return $this->belongsTo("AppPost", "foreign_key");
        // return $this->belongsTo("AppPost", "foreign_key", "other_key");
    }
}
$user = Article::find($id)->user; // 返回文章的作者

多对多

需要三张数据表:users、roles 和 role_user,
role_user 表为关系表,默认按照关联模型名的字母顺序命名,并且包含 user_id 和 role_id 两个列。
class User extends Model{
    /**
     * 用户角色
     */
    public function roles()
    {
         //默认去role_user查找关系
        // return $this->belongsToMany("AppRole");
        return $this->belongsToMany("AppRole","role_users");
        // 定义键值
        // return $this->belongsToMany("AppRole", "user_roles", "user_id", "role_id");
    }
}

$roles = User::find(1)->roles;
// 返回 [{"id":1,"name":"SuperManager","pivot":{"user_id":1,"role_id":1}},{"id":2,"name":"Manager","pivot":{"user_id":1,"role_id":2}}]

$roles = User::find(1)->roles()->orderBy("name")->get(); // 条件约束
注意我们获取到的每一个 Role 模型都被自动赋上了 pivot 属性。该属性包含一个代表中间表的模型,并且可以像Eloquent 模型一样使用。

如果你的 pivot 表包含额外的属性,必须在定义关联关系时进行指定:

return $this->belongsToMany("AppRole")->withPivot("column1", "column2");

如果你想要你的 pivot 表自动包含created_at 和 updated_at 时间戳,在关联关系定义时使用 withTimestamps 方法:

return $this->belongsToMany("AppRole")->withTimestamps();

过中间表字段过滤关联关系

return $this->belongsToMany("AppRole")->wherePivot("approved", 1);
return $this->belongsToMany("AppRole")->wherePivotIn("priority", [1, 2]);
关联查询

存在的关联查询

// 获取所有至少有一条评论的文章...
$posts = AppPost::has("comments")->get();
你还可以指定操作符和数目来自定义查询:

// 获取所有至少有三条评论的文章...
$posts = Post::has("comments", ">=", 3)->get();
还可以使用”.“来构造嵌套 has 语句,例如,你要获取所有至少有一条评论及投票的文章:

// 获取所有至少有一条评论获得投票的文章...
$posts = Post::has("comments.votes")->get();
如果你需要更强大的功能,可以使用 whereHas 和 orWhereHas 方法将 where 条件放到 has 查询上,这些方法允许你添加自定义条件约束到关联关系条件约束,例如检查一条评论的内容:

// 获取所有至少有一条评论包含foo字样的文章
$posts = Post::whereHas("comments", function ($query) {
    $query->where("content", "like", "foo%");
})->get();

无关联结果查询

// 获取所有没有评论的博客文章
$posts = AppPost::doesntHave("comments")->get();

// 检查评论内容:
$posts = Post::whereDoesntHave("comments", function ($query) {
   $query->where("content", "like", "foo%");
})->get();

统计关联模型

如果你想要在不加载关联关系的情况下统计关联结果数目,可以使用 withCount 方法,该方法会放置一个 {relation}_count 字段到结果模型
$posts = AppPost::withCount("comments")->get();
foreach ($posts as $post) {
    echo $post->comments_count;
}

// 添加约束条件到查询一样来添加多个关联关系的“计数”:
$posts = Post::withCount(["votes", "comments" => function ($query) {
    $query->where("content", "like", "foo%");
}])->get();
echo $posts[0]->votes_count;
echo $posts[0]->comments_count;

// 为关联关系计数结果设置别名,从而允许在一个关联关系上进行多维度计数:

$posts = Post::withCount([
    "comments",
    "comments AS pending_comments" => function ($query) {
        $query->where("approved", false);
    }
])->get();

echo $posts[0]->comments_count;
echo $posts[0]->pending_comments_count;
渴求式加载
当以属性方式访问数据库关联关系的时候,关联关系数据是“懒惰式加载”的,这意味着关联关系数据直到第一次访问的时候才被加载。
$books = AppBook::all();
foreach ($books as $book) {
    echo $book->author->name;
}
// 该循环要执行26次查询:1次是获取书本身,剩下的25次查询是为每一本书获取其作者。
$books = AppBook::with("author")->get();
foreach ($books as $book) {
    echo $book->author->name;
}
// 在该操作中,只执行两次查询即可:
// select * from books
// select * from authors where id in (1, 2, 3, 4, 5, ...)

渴求式加载多个关联关系

$books = AppBook::with("author", "publisher")->get();

嵌套的渴求式加载

// 加载所有书的作者及所有作者的个人联系方式:
$books = AppBook::with("author.contacts")->get();

带条件约束的渴求式加载

//  加载 title 包含 first 的文章
$users = AppUser::with(["posts" => function ($query) {
    $query->where("title", "like", "%first%");
}])->get();

// 加载按created_at倒序的的文章
$users = AppUser::with(["posts" => function ($query) {
    $query->orderBy("created_at", "desc");
}])->get();

懒惰渴求式加载

$books = AppBook::all();
if ($someCondition) {
    $books->load("author", "publisher");
}
// 设置更多的查询条件到渴求式加载查询上,可以传递一个闭包到 load 方法:

$books->load(["author" => function ($query) {
    $query->orderBy("published_date", "asc");
}]);
插入 & 更新关联模型

save 方法

$comment = new AppComment(["message" => "A new comment."]);
$post = AppPost::find(1);
$post->comments()->save($comment);
// save 方法会自动添加 post_id 值到新的Comment 模型。

保存多个关联模型,可以使用 saveMany 方法:

$post = AppPost::find(1);
$post->comments()->saveMany([
    new AppComment(["message" => "A new comment."]),
    new AppComment(["message" => "Another comment."]),
]);

create方法

该方法接收属性数组、创建模型、然后插入数据库。save 和 create 的不同之处在于 save 接收整个 Eloquent 模型实例而 create 接收原生 PHP 数组:

使用 create 方法之前确保先浏览属性批量赋值文档。

$post = AppPost::find(1);
$comment = $post->comments()->create([
    "message" => "A new comment.",
]);

从属关联关系

更新 belongsTo 关联, 使用associate 方法,该方法会在子模型设置外键:

$account = AppAccount::find(10);
$user->account()->associate($account);
$user->save();

移除 belongsTo 关联的时候,使用dissociate 方法。该方法会设置关联关系的外键为 null:

$user->account()->dissociate();
$user->save();
多对多关联 的 附加/分离

假定一个用户可能有多个角色,同时一个角色属于多个用户,要通过在连接模型的中间表中插入记录附加角色到用户上,可以使用 attach 方法:

$user = AppUser::find(1);
$user->roles()->attach($roleId);

// 以数组形式传递额外被插入数据到中间表:
$user->roles()->attach($roleId, ["expires" => $expires]);

移除一个多对多关联记录,使用 detach 方法。detach 方法将会从中间表中移除相应的记录;
但是,两个模型在数据库中都保持不变:

// 从指定用户中移除角色...
$user->roles()->detach($roleId);

// 从指定用户移除所有角色...
$user->roles()->detach();

接收数组形式的 ID 作为输入:

$user = AppUser::find(1);
$user->roles()->detach([1, 2, 3]);
$user->roles()->attach([1 => ["expires" => $expires], 2, 3]);

同步关联

sync 方法接收数组形式的 ID 并将其放置到中间表
// 任何不在该数组中的 ID 对应记录将会从中间表中移除
$user->roles()->sync([1, 2, 3]);

// 还可以和 ID 一起传递额外的中间表值:
$user->roles()->sync([1 => ["expires" => true], 2, 3]);

// 如果不想要脱离存在的ID,可以使用syncWithoutDetaching 方法:
$user->roles()->syncWithoutDetaching([1, 2, 3]);

切换关联

// 如果当前没有附加,则附加:如果给定ID当前被附加,则取消附加
$user->roles()->toggle([1, 2, 3]);

在中间表上保存额外数据

// 接收额外中间表属性数组作为第二个参数:
AppUser::find(1)->roles()->save($role, ["expires" => $expires]);

更新中间表记录 updateExistingPivot

// 更新中间表中已存在的行,接收中间记录外键和属性数组进行更新
$user = AppUser::find(1);
$user->roles()->updateExistingPivot($roleId, $attributes);
触发父级时间戳
当一个模型属于另外一个时,子模型更新时父模型的时间戳也被更新将很有用

例如,当 Comment 模型被更新时,你可能想要”触发“更新其所属模型 Post 的updated_at 时间戳。Eloquent 使得这项操作变得简单,只需要添加包含关联关系名称的 touches 属性到子模型即可:

class Comment extends Model{
    // 触发的所有关联关系
    protected $touches = ["post"];

    // 关联关系
    public function post()
    {
        return $this->belongsTo("AppPost");
    }
}

更新 Comment 时,所属模型 Post 将也会更新其 updated_at 值

$comment = AppComment::find(1);
$comment->text = "Edit to this comment!";
$comment->save();

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30780.html

相关文章

  • 深入理解 Laravel Eloquent(三)——模型间关系关联

    摘要:是什么是一个,全称为,翻译为对象关系映射如果只把它当成数组库抽象层那就太小看它了。所谓对象,就是本文所说的模型对象关系映射,即为模型间关系。至此,深入理解系列文章到此结束。 原文发表在我的个人网站:深入理解 Laravel Eloquent(三)——模型间关系(关联) 在本篇文章中,我将跟大家一起学习 Eloquent 中最复杂也是最难理解的部分——模型间关系。官方英文文档中...

    2501207950 评论0 收藏0
  • Laravel & Lumen之Eloquent ORM使用速查-进阶部分

    摘要:关联关系查询在中,所有的关系都是使用函数定义的,可以在不执行关联查询的情况下获取关联的实例。 关联关系 One To One 假设User模型关联了Phone模型,要定义这样一个关联,需要在User模型中定义一个phone方法,该方法返回一个hasOne方法定义的关联

    Chaz 评论0 收藏0
  • Laravel使用数据库事务以及捕获事务失败后异常

    摘要:在中要想在数据库事务中运行一组操作,则可以在中使用方法。如果在事务的闭包内抛出异常,事务将会被自动还原。 Description 在Laravel中要想在数据库事务中运行一组操作,则可以在 DB facade 中使用 transaction 方法。如果在事务的闭包内抛出异常,事务将会被自动还原。如果闭包运行成功,事务将被自动提交。你不需要担心在使用 transaction 方法时还需要...

    newtrek 评论0 收藏0
  • 整理Laravel Eloquent ORM 相关操作

    摘要:软删除当模型被软删除后,它们并没有真的从数据库删除,而是在模型上设置一个属性并插入数据库,如果模型有一个非空值,那么该模型已经被软删除了。 Laravel 中Eloquent ORM 相关操作 定义 操作 获取(查询) 获取集合,(查询列表) 返回值是 IlluminateDatabaseEloquentCollection 的一个实例 获取所有的数据 use AppUser; $us...

    dongfangyiyu 评论0 收藏0
  • Laravel Eloquent 模型关联速查表

    摘要:模型資料庫遷移儲存紀錄在及之間建立關聯在及之間建立關聯取得紀錄取得取得一对多关联示例细节在此示例中,我们有两个模型小偷和车,和两张表和。业务规则小偷可以偷走多辆车。关系图关联详情关联表应该保存驾驶员和汽车。 showImg(https://segmentfault.com/img/remote/1460000016043938); 一張 Laravel’s Eloquent ORM 5...

    flybywind 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<