Laravel Eloquent ORM 关系查询

索引
[隐藏]

在信息系统中有很多一对多的关系,常见的一个例子是一个订单(order)中包含多种商品(product)。我们通常会使用一个order表来存储订单,同时使用一个product表来存储商品,并在product表中加入 order_id外键来将产品关联到订单中。

在以前开发项目时,我一直使用先查询order,再通过 order_id查询product,并遍历查询到的order对象,将product插入order中的做法。但是这样做非常不优雅,并且会严重影响性能。同时,由于数据库中没有外键约束,一旦业务代码中出现bug,则会影响数据的一致性。

在这次的项目开发中,我使用Laravel的Eloquent ORM来实现外键的关系查询。

一些概念

我们首先来复习一些数据库系统导论中的一些概念

主键(Primary Key)

主关键字(Primary Key)是表中的一个或多个字段,它的值用于唯一地标识表中的某一条记录。主键通常名为 id,并且为自增。

外键(Foreign Key)

外键(Foreign Key)的作用是建立两个表之间的关联。下面这张图可以直观地展示外键的作用。

外键

连接(Join)

连接(Join)将两张表中能关联起来的数据连接后返回。关于连接的更多内容请参考这篇文章:图解 SQL 里的各种 JOIN — 码志

Laravel的Eloquent ORM中并没有实现Join,如果需要在Laravel中使用Join则需要在Query Builder中完成。请注意不要将本文所述内容和join混淆,Eloquent中的with方法的实现是通过模型中定义的关系另外进行一次查询,并没有使用join。

场景

我们假设一个网上商城中,每个用户有若干个订单,每个订单中有若干个产品。我们需要实现在一次查询中,通过用户id查询其所有订单和及订单中的所有产品,并返回一个如下格式的json。

编写数据库迁移

外键需要在编写迁移时就定义好,请注意代码中的注释。

Users表

Orders表

Products表

创建Model并定义关系

Orders模型

Products模型

这部分代码表示order属于users,并且对应多个products;同时product属于orders。

查询

通过下面的语句即可查询某一用户的所有订单,及订单中的所有产品。

预加载(Eager Loading)

如果我们 dd一下 Order::query()->where('user_id',1)的结果,我们会发现其中并不包含products。因为这部分结果只有在products属性被访问时才会被查询。如果我们需要将order及products的数据在一次查询中获取,则需要使用预加载(Eager Loading)。使用如下语句即可。

此外,在https://laravel.com/docs/5.7/eloquent-relationships#eager-loading 所述的场景中,每次循环中都需要进行一次查询来获得book的author。而使用预加载则可以将所有对author的查询在一次查询中完成。

如果需要实现嵌套预加载,例如通过 orderItems中的 product_id从product表中查询产品信息,使用如下语句即可。

w

参考资料

Show CommentsClose Comments

Leave a comment