一、一对一关联

一对一关联是很基本的关联。假设一个 User 对应到一个 Phone,phones 表结构如下(通过 user_id 关联 user 表的主键):

1,定义一对一关联

(1)User 模型中按下面这样定义关联,传到 hasOne 方法里的第一个参数是关联模型的类名称。

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model {

// 获取用户对应的电话

public function phone()

{

return $this->hasOne('App\Models\Phone');

}

}

(2)定义好关联之后,就可以使用 Eloquent 的动态属性取得关联对象:

$phone = User::find(1)->phone;

(3)上面操作实际上执行了如下 sql:

select * from users where id = 1

select * from phones where user_id = 1

2,指定一对一关联的外键

(1)默认情况下,外键名称是基于模型名称来的。比如上面样例,Phone 模型则自动以 user_id 作为外键。如果想要更改这个默认值,可以传入第二个参数到 hasOne 方法里。

return $this->hasOne('App\Models\Phone', 'my_user_id');

(2)我们还可以传入第三个参数,指定关联的外键要对应到本身的哪个字段:

return $this->hasOne('App\Models\Phone', 'my_user_id', 'uid');

3,定义相对的关联

(1)前面我们是在 phones 表中有个 user_id 用来关联 user 表数据,如果想在 Phone 模型中获取 User 模型对象,可以使用 belongsTo 定义相对的关联。

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model {

// 获取电话对应的用户

public function user()

{

return $this->belongsTo('App\Models\User');

}

}

(2)定义好关联之后,就可以使用 Eloquent 的动态属性取得关联对象:

$user = Phone::find(1)->user;

4,指定关联的外键

(1)默认情况下,外键名称是基于模型名称来的。比如上面样例,Phone 模型则自动以 user_id 作为外键。我们也可以在 belongsTo 方法里传入第二个参数,来指定外键字段。

return $this->belongsTo('App\Models\User', 'local_key');

(2)除此之外,也可以传入第三个参数指定要参照上层数据库表的哪个字段。

return $this->belongsTo('App\Models\User', 'local_key', 'parent_key');

二、一对多关联

同样以用户、电话表为例。假设一个 User 可以拥有多个 Phone,phones 表结构如下(通过 user_id 关联 user 表的主键):

1,定义一对多关联

(1)User 模型中按下面这样定义关联,传到 hasMany 方法里的第一个参数是关联模型的类名称。

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model {

// 获取用户对应的所有电话

public function phones()

{

return $this->hasMany('App\Models\Phone');

}

}

(2)定义好关联之后,就可以使用 Eloquent 的动态属性取得所有关联对象:

// 获取id为1的用户所有电话

$phones = User::find(1)->phones;

// 返回的结果同样支持链式调用

$phone = User::find(1)->phones->first();

2,指定一对多关联的外键

(1)默认情况下,外键名称是基于模型名称来的。比如上面样例,Phone 模型则自动以 user_id 作为外键。如果想要更改这个默认值,可以传入第二个参数到 hasMany 方法里。

return $this->hasMany('App\Models\Phone', 'my_user_id');

(2)我们还可以传入第三个参数,指定关联的外键要对应到本身的哪个字段:

return $this->hasMany('App\Models\Phone', 'my_user_id', 'uid');

3,定义相对的关联

如果想要在 Phone 模型中获取 User 模型对象,那么使用 belongsTo 定义相对的关联。具体用法详见上方一对一关联部分。

三、远层一对多关联(Has Many Through)

“远层一对多关联”提供了方便简短的方法,可以经由多层间的关联取得远层的关联。例如,一个 Country 模型可能通过 Users 关联到很多 Posts 模型,这些数据库表间的关系如下:

countries

id - integer

name - string

users

id - integer

country_id - integer

name - string

posts

id - integer

user_id - integer

title - string

(1)虽然 posts 数据库表本身没有 country_id 字段,但 hasManyThrough 方法让我们可以使用 $country->posts 取得 country 的 posts。我们可以定义以下关联:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Country extends Model {

public function posts()

{

return $this->hasManyThrough('App\Models\Post', 'App\Models\User');

}

}

(2)如果想要手动指定关联的字段名称,可以传入第三和第四个参数到方法里:

return $this->hasManyThrough('App\Models\Post', 'App\Models\User', 'country_id', 'user_id');

四、多对多关联

多对多关联常见有用户、角色之间的相互关联:一个用户( user )可能用有很多角色( role ),而一种角色可能很多用户都有。

所以数据库会存在如下三个表:用户表(users)、角色表(roles)、用户角色关联表(role_user)。其中关联表以关联的两个模型命名(先后按字母顺序排列),关联表结构如下:

1,定义多对多关联

(1)在 User 和 Role 模型中我们可以使用 belongsToMany 方法定义多对多关系(关联表是不需要定义对应的模型的)

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model {

// 获取用户对应的所有角色

public function roles()

{

return $this->belongsToMany('App\Models\Role');

}

}

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Role extends Model {

// 获取角色对应的所有用户

public function users()

{

return $this->belongsToMany('App\Models\User');

}

}

(2)定义好关联之后,就可以使用 Eloquent 的动态属性取得关联对象。下面样例取得 id 为 1的用户拥有的所有角色:

$roles = User::find(1)->roles;

2,指定关联表名和关联字段

(1)如果我们关联表是按规定的格式命名的话(以关联的两个模型命名,先后按字母顺序排列),是不需要在手动指定关联表。否则,我们可以在 belongsToMany 方法中传入第二个参数,指定使用的关联表名。

return $this->belongsToMany('App\Models\Role', 'users_roles');

(2)同样的关联表中的关联字段默认同样采用“模型_id”的命名方式,如果不是的话,我们可以在 belongsToMany 第三、第四个参数指定使用的关联字段。

return $this->belongsToMany('App\Models\Role', 'users_roles', 'user_id', 'role_id');

五、关联查询

在取得模型数据时,我们可能想要以关联模型作为查询限制。下面同样以上面的用户(User)、电话(Phone)这个一对多关联场景进行演示。

1,has 方法

(1)想要取得所有“至少有一个电话”的用户。可以使用 has 方法达成目的。

$users = User::has('phones')->get();

(2)也可以指定运算符和数量:

$users = User::has('phones', '>=', 3)->get();

(3)也可以使用“点号”的形式来获取嵌套的 has 声明:

$users = User::has('phones.xxxx')->get();

2,whereHas 、 orWhereHas 方法

如果想要更进阶的用法,可以使用 whereHas 和 orWhereHas 方法,在 has 查询里设置 “where” 条件 :

$users = Post::whereHas('phones', function($q)

{

$q->where('number', 'like', '189%');

})->get();

附:预载入

预载入是用来减少 N + 1查询问题。例如,一个 Phone 模型数据会关联到一个 User ,关联会像下面这样定义。

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model {

// 获取电话对应的用户

public function user()

{

return $this->belongsTo('App\Models\User');

}

}

1,基本用法

(1)假设我们使用下面的循环会执行一次查询取回所有数据库表上的电话,然而每个电话又都会执行一次查询取得用户。所以若我们有 10 个电话记录,就会进行 11 次查询。

foreach (Phone::all() as $phone)

{

echo $phone->user->username;

}

(2)我们可以使用预载入大量减少查询次数。即使用 with 方法指定想要预载入的关联对象:

foreach (Phone::with('user')->get() as $phone)

{

echo $phone->user->username;

}

(3)上面的循环总共只会执行两次查询,对应的 sql 如下:

select * from phones

select * from users where id in (1, 2, 3, 4, 5, ...)

2,同时载入多种关联

使用预载入可以大大提高程序的性能,当然 with 方法也是可以同时载入多种关联的。

Phone::with('user', 'operator')->get()

3,预载入条件限制

(1)我们也可以指定预载入时的查询限制,比如下面只预载入李姓用户:

$phone = Phone::with(['user' => function($query)

{

$query->where('username', 'like', '李%');

}])->get();

(2)当然,预载入的闭合函数里不一定只能加上条件限制,也可以加上排序:

$phone = Phone::with(['user' => function($query)

{

$query->orderBy('age', 'desc');

}])->get();

mysql中的自关联详解_Laravel - MySQL数据库的使用详解6(Eloquent ORM用法3:模型关联、关联查询)...相关推荐

  1. MySQL中出现 错误 2003Can‘t connect to MySQL server on‘localhost‘ (0)

    MySQL中出现  错误 2003Can't connect to MySQL server on'localhost' (0) 在SQLyog这个工具上登陆不了,但是在cmd命令窗口中可以正常操作. ...

  2. jsp页面判断输入编号已存在mysql中_面试官让我聊聊Mysql基础架构之日志文件与数据文件...

    上一篇文章讲述了Mysql的基本框架,和sql执行的流程,这篇文章首先分析下每个流程的具体细节,然后介绍日志文件和数据文件以下面语句作为例子来分析流程中每一步的具体细节: select * from ...

  3. mysql中如何设置时区_如何设置MySQL的时区?

    我认为这可能是有用的: 有三个位置可以在MySQL中设置时区: 在[mysqld]部分中的"my.cnf"文件中default-time-zone='+00:00' @global ...

  4. mysql中日期相减_如何使用MySQL数据库

    如何使用MySQL数据库 前言:前面我们已经了解了如何搭建MySQL数据库,那么接下来我们就一起来了解一下,如何使用MySQL数据库. MySQL数据库系统也是一个典型的C/S(客户端/服务器)架构应 ...

  5. mysql中nchar_浅谈SQL Server、MySQL中char,varchar,nchar,nvarchar区别

    1,定义: char:    固定长度,存储ANSI字符,不足的补英文半角空格. nchar:   固定长度,存储Unicode字符,不足的补英文半角空格 varchar:  可变长度,存储ANSI字 ...

  6. MySql中json类型的使用___mybatis存取mysql中的json

    MySql中json类型的使用 MySQL从5.7.8起开始支持JSON字段,这极大的丰富了MySQL的数据类型.也方便了广大开发人员.但MySQL并没有提供对JSON对象中的字段进行索引的功能,至少 ...

  7. mysql存储引擎查看语句,在MySQL中,可以使用(??)语句查看MySQL服务器采用的默认存储引擎...

    在MySQL中,可以使用(??)语句查看MySQL服务器采用的默认存储引擎 答:SHOW VARIABLES; 名词解释:顾姑冠 答:蒙古族已婚妇女的首服,由帽子.冠体.披幅.系带.冠顶.羽毛五部分组 ...

  8. mysql中导入xml文件_xml文件导入MySQL数据库

    使用Load_File()函数导入XML数据 MySQL 5.1.5包括了两个新的函数:ExtractValue()和UpdateXML(). ExtractValue():使用XPath符号从XML ...

  9. mysql 中函数如何转存_mysql 导入导出数据库以及函数、存储过程 【转】

    MySQL常用导出数据命令: 1.mysql导出整个数据库 mysqldump -hhostname -uusername -ppassword databasename > backupfil ...

最新文章

  1. VMware上的ubuntu14.04与win7共享文件夹
  2. linux socket读写函数,Linux网络编程入门
  3. 进度条(5.16-5.22)
  4. C语言头歌educoder实训作业答案分享 结构体
  5. MD5类加密解密工具类
  6. windows server 2008R2 修改账户密码
  7. 2019个人目标——计划未来
  8. 浅谈嵌入式技术的发展
  9. 配置文件报错 Cannot convert value of type ‘java.lang.String‘ to required type ‘javax.sql.DataSource‘ for p
  10. python 拆分excel工作表_使用python拆分excel单元格方法
  11. 函数重载导致的二义性
  12. Photoshop如何改变背景底色并调整照片尺寸和图像大小
  13. NYOJ 32 组合数
  14. 拼多多店铺推广有哪些技巧?
  15. Criteria和DetachedCriteria
  16. Haiwell Cloud Scada Designer 3
  17. 【计量经济学】异方差性
  18. Single Image Dehazing via Multi-scale Convolutional Neural Networks with Holistic Edges 2020 个人学习笔记
  19. win10读取不了U盘或者移动硬盘的解决方法
  20. VS.net 2005 MFC QQ 2006 TM 2006 消息发送 简单核心代码

热门文章

  1. nn.Conv2d中padding详解【pytorch学习】
  2. linux mysql运维_Linux运维常用的 MySQL基础命令
  3. Linux学习之CentOS(三十六)--FTP服务原理及vsfptd的安装、配置
  4. DOM相关方法,属性整理
  5. Idea根据表自动生成实体
  6. 路由器原理及作用以及交换机
  7. 泛型类型通常在Dao和Service 中使用BaseDaoT extends Serializable的泛型
  8. gridview自动换行
  9. Python 类的定义、继承及使用对象
  10. UA MATH566 统计理论 QE练习 位置变换后的指数分布