zoukankan      html  css  js  c++  java
  • 深入理解 Laravel Eloquent(三)——模型间关系(关联)

    Eloquent是什么

    Eloquent 是一个 ORM,全称为 Object Relational Mapping,翻译为 “对象关系映射”(如果只把它当成 Database Abstraction Layer 数组库抽象层那就太小看它了)。所谓 “对象”,就是本文所说的 “模型(Model)”;对象关系映射,即为模型间关系。中文文档: http://laravel-china.org/docs/eloquent#relationships

    下面我们开始一个一个地学习。

    一对一关系

    顾名思义,这描述的是两个模型之间一对一的关系。这种关系是不需要中间表的。

    假如我们有两个模型:User 和 Account,分别对应注册用户和消费者,他们是一对一的关系,那么如果我们要使用 Eloquent 提供的一对一关系方法,表结构应该是这样的:

    user: id ... ... account_id
    
    account: id ... ... user_id
    

    假设我们需要在 User 模型中查询对应的 Account 表的信息,那么代码应该是这样的。 `/app/models/User.php`:

    <?php
    
    class User extends Eloquent {
    
      
    
      protected $table = 'users';
    
      public function hasOneAccount()
    
      {
    
          return $this->hasOne('Account', 'user_id', 'id');
    
      }
    
    }
    

    然后,当我们需要用到这种关系的时候,该如何使用呢?如下:

    $account = User::find(10)->hasOneAccount;
    

    此时得到的 `$account` 即为 `Account` 类的一个实例。


    这里最难的地方在于后面的两个 foreign_key 和 local_key 的设置,大家可以就此记住:在 User 类中,无论 hasOne 谁,第二个参数都是 `user_id`,第三个参数一般都是 `id`。由于前面的 `find(10)` 已经锁定了 id = 10,所以这段函数对应的 SQL 为: `select * from account where user_id=10`。


    这段代码除了展示了一对一关系该如何使用之外,还传达了三点信息,也是我对于大家使用 Eloquent 时候的建议:

    1. 每一个 Model 中都指定表名

    2. has one account 这样的关系写成 `hasOneAccount()` 而不是简单的 `account()`

    3. 每次使用模型间关系的时候都写全参数,不要省略

    相应的,如果使用 belongsTo() 关系,应该这么写:

    <?php
    
    class Account extends Eloquent {
    
      protected $table = 'accounts';
    
      
    
      public function belongsToUser()
    
      {
    
        return $this->belongsTo('User', 'user_id', 'id');
    
      }
    
    }
    

    一对多关系

    学会了前面使用一对一关系的基础方法,后面的几种关系就简单多了。

    我们引入一个新的Model:Pay,付款记录。表结构应该是这样的:

    user: id ... ...
    
    pay: id ... ... user_id
    

    User 和 Pay 具有一对多关系,换句话说就是一个 User 可以有多个 Pay,这样的话,只在 Pay 表中存在一个 `user_id` 字段即可。 `/app/models/User.php`:

    <?php
    
    class User extends Eloquent {
    
      
    
      protected $table = 'users';
    
      public function hasManyPays()
    
      {
    
        return $this->hasMany('Pay', 'user_id', 'id');
    
      }
    
    }
    

    然后,当我们需要用到这种关系的时候,该如何使用呢?如下:

    $accounts = User::find(10)->hasManyPays()->get();
    

    此时得到的 `$accounts` 即为 `IlluminateDatabaseEloquentCollection` 类的一个实例。大家应该也已经注意到了,这里不是简单的 `-> hasOneAccount` 而是 `->hasManyPays()->get()`,为什么呢?因为这里是 `hasMany`,操作的是一个对象集合。

    相应的 belongsTo() 的用法跟上面一对一关系一样:

    <?php
    
    class Pay extends Eloquent {
    
      protected $table = 'pays';
    
      
    
      public function belongsToUser()
    
      {
    
        return $this->belongsTo('User', 'user_id', 'id');
    
      }
    
    }
    

    多对多关系

    多对多关系和之前的关系完全不一样,因为多对多关系可能出现很多冗余数据,用之前自带的表存不下了。

    我们定义两个模型:Article 和 Tag,分别表示文章和标签,他们是多对多的关系。表结构应该是这样的:

    article: id ... ...
    
    tag: id ... ...
    
    article_tag: article_id tag_id
    

    在 Model 中使用:

    <?php
    
    class Tag extends Eloquent {
    
      protected $table = 'tags';
    
      
    
      public function belongsToManyArticle()
    
      {
    
        return $this->belongsToMany('Article', 'article_tag', 'tag_id', 'article_id');
    
      }
    
    }
    

    需要注意的是,第三个参数是本类的 id,第四个参数是第一个参数那个类的 id。

    使用跟 hasMany 一样:

    $tagsWithArticles = Tag::take(10)->get()->belongsToManyArticle()->get();
    

    这里会得到一个非常复杂的对象,可以自行 `var_dump()`。跟大家说一个诀窍,`var_dump()` 以后,用 Chrome 右键 “查看源代码”,就可以看到非常整齐的对象/数组展开了。

    在这里给大家展示一个少见用法(奇技淫巧):

    public function parent_video()
    
    {
    
        return $this->belongsToMany($this, 'video_hierarchy', 'video_id', 'video_parent_id');
    
    }
    
    public function children_video()
    
    {
    
        return $this->belongsToMany($this, 'video_hierarchy', 'video_parent_id', 'video_id');
    
    }
    

    对,你没有看错,可以 belongsToMany 自己。

    其他关系

    Eloquent 还提供 “远层一对多关联”、“多态关联” 和 “多态的多对多关联” 这另外三种用法,经过上面的学习,我们已经掌握了 Eloquent 模型间关系的基本概念和使用方法,剩下的几种不常用的方法就留到我们用到的时候再自己探索吧。

    重要技巧:关系预载入

    你也许已经发现了,在一对一关系中,如果我们需要一次性查询出10个 User 并带上对应的 Account 的话,那么就需要给数据库打 1 + 10 条 SQL,这样性能是很差的。我们可以使用一个重要的特性,关系预载入:http://laravel-china.org/docs/eloquent#eager-loading

    直接上代码:

    $users = User::with('hasOneAccount')->take(10)->get()
    

    这样生成的 SQL 就是这个样子的:

    select * from account where id in (1, 2, 3, ... ...)
    

    这样 1 + 10 条 SQL 就变成了 1 + 1 条,性能大增。


    至此,深入理解 Laravel Eloquent 系列文章到此结束。推荐继续了解 软删除转换成数组/JSON

    END

  • 相关阅读:
    浅谈python web三大框架
    Mysql异常
    格式化时间转换
    MySql存储日期为long型,判断时间大小
    Linux下部署项目
    excel
    Tomcate的启动问题
    计算时间差
    地图系的转换
    关于获取本机真实IP
  • 原文地址:https://www.cnblogs.com/caicaizi/p/6137005.html
Copyright © 2011-2022 走看看