Overview
当您使用关系数据库时,Eloquent ORM 将模型存储为与模型类对应的表中的行。 当您使用MongoDB时,Laravel 集成会将模型存储为与模型类对应的集合中的文档。
要定义关系,请在模型类中添加一个函数,用于调用适当的关系方法。 此函数允许您将相关模型作为动态属性进行访问。 动态属性允许您使用与访问模型属性相同的事务语法来访问相关模型。
以下部分描述了 Laravel 集成中可用的 Laravel Eloquent 和MongoDB特定关系,并举例说明了如何定义和使用这些关系:
One to one relationship, created by using the
hasOne()method and its inverse,belongsTo()One to many relationship, created by using the
hasMany()and its inverse,belongsTo()Many to many relationship, created by using the
belongsToMany()methodEmbedded document pattern, a MongoDB-specific relationship that can represent a one to one or one to many relationship, created by using the
embedsOne()orembedsMany()method跨数据库关系,当您想要在 MongoDB 和 SQL 模型之间创建关系时需要
一对一关系
模型之间的一对一关系由与另一种类型的模型记录完全相关的模型记录组成。
当您添加一对一关系时,Eloquent 允许您使用动态属性访问模型,并将模型的文档 ID 存储在相关模型上。
在 Laravel MongoDB 中,您可以使用hasOne()方法或belongsTo()方法定义一对一关系。
当您使用belongsTo()方法添加反向关系时,Eloquent 允许您使用动态属性访问模型,但不添加任何字段。
要学习;了解有关一对一关系的更多信息,请参阅 一对一 Laravel 文档中的一对一。
一对一示例
以下示例类展示了如何使用hasOne()方法在Planet和Orbit模型之间定义HasOne一对一关系:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Relations\HasOne; class Planet extends Model { protected $connection = 'mongodb'; public function orbit(): HasOne { return $this->hasOne(Orbit::class); } }
以下示例类展示了如何使用belongsTo()方法定义Orbit和Planet之间的反向BelongsTo关系:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Relations\BelongsTo; class Orbit extends Model { protected $connection = 'mongodb'; public function planet(): BelongsTo { return $this->belongsTo(Planet::class); } }
以下示例代码展示了如何为每个类实例化模型并添加它们之间的关系。 单击VIEW OUTPUT按钮,查看通过运行代码创建的数据:
$planet = new Planet(); $planet->name = 'Earth'; $planet->diameter_km = 12742; $planet->save(); $orbit = new Orbit(); $orbit->period = 365.26; $orbit->direction = 'counterclockwise'; $planet->orbit()->save($orbit);
以下示例代码展示了如何使用示例类中定义的动态属性来访问相关模型:
$planet = Planet::first(); $relatedOrbit = $planet->orbit; $orbit = Orbit::first(); $relatedPlanet = $orbit->planet;
一对多关系
模型之间的一对多关系由作为父模型的模型和一个或多个相关的子模型记录组成。
当您添加一对多关系方法时,Eloquent 允许您使用动态属性访问模型,并在每个子模型文档中存储父模型的文档 ID。
在 Laravel MongoDB 中,您可以通过在父类上添加hasMany()方法以及在子类上添加belongsTo()方法(可选)来定义一对多关系。
当您使用belongsTo()方法添加反向关系时,Eloquent 允许您使用动态属性访问父模型,而无需添加任何字段。
要学习;了解有关一对多关系的更多信息,请参阅 一对多 Laravel 文档中的一对多。
一对多示例
以下示例类展示了如何使用hasMany()方法在Planet父模型和Moon子模型之间定义HasMany一对多关系:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Relations\HasMany; class Planet extends Model { protected $connection = 'mongodb'; public function moons(): HasMany { return $this->hasMany(Moon::class); } }
以下示例类展示了如何使用belongsTo()方法定义Moon子模型与Planet父模型之间的反向BelongsTo关系:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Relations\BelongsTo; class Moon extends Model { protected $connection = 'mongodb'; public function planet(): BelongsTo { return $this->belongsTo(Planet::class); } }
以下示例代码展示了如何为每个类实例化模型并添加它们之间的关系。 单击VIEW OUTPUT按钮,查看通过运行代码创建的数据:
$planet = new Planet(); $planet->name = 'Jupiter'; $planet->diameter_km = 142984; $planet->save(); $moon1 = new Moon(); $moon1->name = 'Ganymede'; $moon1->orbital_period = 7.15; $moon2 = new Moon(); $moon2->name = 'Europa'; $moon2->orbital_period = 3.55; $planet->moons()->save($moon1); $planet->moons()->save($moon2);
以下示例代码展示了如何使用示例类中定义的动态属性来访问相关模型。
$planet = Planet::first(); $relatedMoons = $planet->moons; $moon = Moon::first(); $relatedPlanet = $moon->planet;
多对多关系
多对多关系由两种不同模型类型之间的关系组成,其中,对于每种模型类型,该模型的一个实例都可以与另一种类型的多个实例相关。
在 Laravel MongoDB 中,您可以通过将belongsToMany()方法添加到两个相关类来定义多对多关系。
在关系数据库中定义多对多关系时,Laravel 会创建一个数据透视表来追踪这些关系。 当您使用 Laravel 集成时,它会省略数据透视表的创建,并将相关文档ID 添加到从相关模型类名称派生的文档字段中。
提示
由于 Laravel 集成使用文档字段而不是数据透视表,因此请从belongsToMany()构造函数中省略数据透视表参数或设立其设置为null 。
要学习;了解有关 Laravel 中多对多关系的更多信息,请参阅 多对多 Laravel 文档中的多对多。
以下部分举例说明了如何在模型类之间创建多对多关系。
多对多示例
以下示例类展示了如何使用belongsToMany()方法在Planet和SpaceExplorer模型之间定义BelongsToMany多对多关系:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Relations\BelongsToMany; class Planet extends Model { protected $connection = 'mongodb'; public function visitors(): BelongsToMany { return $this->belongsToMany(SpaceExplorer::class); } }
以下示例类展示了如何使用belongsToMany()方法定义SpaceExplorer和Planet模型之间的反向BelongsToMany多对多关系:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Relations\BelongsToMany; class SpaceExplorer extends Model { protected $connection = 'mongodb'; public function planetsVisited(): BelongsToMany { return $this->belongsToMany(Planet::class); } }
以下示例代码展示了如何为每个类实例化模型并添加它们之间的关系。 单击VIEW OUTPUT按钮,查看通过运行代码创建的数据:
$planetEarth = new Planet(); $planetEarth->name = 'Earth'; $planetEarth->save(); $planetMars = new Planet(); $planetMars->name = 'Mars'; $planetMars->save(); $planetJupiter = new Planet(); $planetJupiter->name = 'Jupiter'; $planetJupiter->save(); $explorerTanya = new SpaceExplorer(); $explorerTanya->name = 'Tanya Kirbuk'; $explorerTanya->save(); $explorerMark = new SpaceExplorer(); $explorerMark->name = 'Mark Watney'; $explorerMark->save(); $explorerJeanluc = new SpaceExplorer(); $explorerJeanluc->name = 'Jean-Luc Picard'; $explorerJeanluc->save(); $explorerTanya->planetsVisited()->attach($planetEarth); $explorerTanya->planetsVisited()->attach($planetJupiter); $explorerMark->planetsVisited()->attach($planetEarth); $explorerMark->planetsVisited()->attach($planetMars); $explorerJeanluc->planetsVisited()->attach($planetEarth); $explorerJeanluc->planetsVisited()->attach($planetMars); $explorerJeanluc->planetsVisited()->attach($planetJupiter);
以下示例代码展示了如何使用示例类中定义的动态属性来访问相关模型。
$planet = Planet::first(); $explorers = $planet->visitors; $spaceExplorer = SpaceExplorer::first(); $explored = $spaceExplorer->planetsVisited;
嵌入式文档模式
在 MongoDB 中,嵌入式文档模式将相关模型的数据添加到父模型中,而不是保留外键引用。 使用此模式可以满足以下一项或多项要求:
将关联的数据保存在单个集合中
对文档的多个字段和关联数据执行原子更新
减少获取数据所需的读取次数
在 Laravel MongoDB 中,您可以通过添加以下方法之一来定义嵌入式文档:
embedsOne()嵌入单个文档embedsMany()嵌入多个文档
注意
这些方法返回 Eloquent 集合,与查询构建器对象不同。
自动水合
当您访问权限嵌入式关系时,Laravel 集成默认将嵌入式数据返回为原始对象,而不是水合模型实例。当嵌入式文档作为原始对象返回时,以下行为应用:
id字段是ObjectId类型,而不是字符串。日期字段是
UTCDateTime对象,而不是格式化字符串。模型属性转换、方法和
toArray()序列化不应用。
要将嵌入式文档作为水合模型实例检索,请将关系名称添加到父模型上的 $with属性中。此属性会在每个查询中自动加载关系,以便 Laravel 集成将嵌入式文档水化为模型实例。
以下示例定义了一个 User 模型,该模型使用 $with 加载其嵌入式 addresses 关系:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Relations\EmbedsMany; class User extends Model { protected $with = ['addresses']; public function addresses() { return $this->embedsMany(Address::class); } }
由于该模型包含 $with = ['addresses'],因此 Laravel 集成将嵌入式地址作为 Address 模型实例返回。toArray() 方法将 id字段序列化为字符串,并将日期字段序列化为格式化字符串。所有 Address 模型转换和方法也可用。
要学习;了解有关MongoDB嵌入式文档模式的更多信息,请参阅以下MongoDB Server教程:
以下部分举例说明如何使用嵌入式文档模式。
嵌入式文档示例
以下示例类展示了如何使用embedsMany()方法在SpaceShip和Cargo模型之间定义EmbedsMany一对多关系:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Relations\EmbedsMany; class SpaceShip extends Model { protected $connection = 'mongodb'; protected $with = ['cargo']; public function cargo(): EmbedsMany { return $this->embedsMany(Cargo::class); } }
嵌入式模型类省略了关系定义,如以下Cargo模型类所示:
declare(strict_types=1); namespace App\Models; use MongoDB\Laravel\Eloquent\Model; class Cargo extends Model { protected $connection = 'mongodb'; }
以下示例代码展示了如何创建SpaceShip模型并嵌入多个Cargo模型,以及通过运行代码创建的 MongoDB 文档。 单击VIEW OUTPUT按钮可查看通过运行以下代码创建的数据:
$spaceship = new SpaceShip(); $spaceship->name = 'The Millenium Falcon'; $spaceship->save(); $cargoSpice = new Cargo(); $cargoSpice->name = 'spice'; $cargoSpice->weight = 50; $cargoHyperdrive = new Cargo(); $cargoHyperdrive->name = 'hyperdrive'; $cargoHyperdrive->weight = 25; $spaceship->cargo()->attach($cargoSpice); $spaceship->cargo()->attach($cargoHyperdrive);
跨数据库关系
Laravel MongoDB中的跨数据库关系是存储在关系数据库中的模型与存储在MongoDB database中的模型之间的关系。
添加跨数据库关系时,Eloquent 允许您使用动态属性访问相关模型。
Laravel 集成支持以下跨数据库关系方法:
hasOne()hasMany()belongsTo()
要定义跨数据库关系,您必须在存储在关系数据库中的类中导入MongoDB\Laravel\Eloquent\HybridRelations包。
以下部分举例说明如何定义跨数据库关系。
跨数据库关系示例
以下示例类展示了如何定义存储在关系数据库中的 SpaceShip 模型与存储在MongoDB database中的 Passenger 模型之间的 HasMany 关系:
declare(strict_types=1); namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; use MongoDB\Laravel\Eloquent\HybridRelations; class SpaceShip extends Model { use HybridRelations; protected $connection = 'sqlite'; public function passengers(): HasMany { return $this->hasMany(Passenger::class); } }
以下示例类展示了如何使用belongsTo()方法定义Passenger模型与Spaceship模型之间的反向BelongsTo关系:
declare(strict_types=1); namespace App\Models; use Illuminate\Database\Eloquent\Relations\BelongsTo; use MongoDB\Laravel\Eloquent\Model; class Passenger extends Model { protected $connection = 'mongodb'; public function spaceship(): BelongsTo { return $this->belongsTo(SpaceShip::class); } }
以下示例代码展示了如何在MySQL数据库中创建 SpaceShip 模型和在MongoDB database中创建相关的 Passenger 模型,以及通过运行代码创建的数据。 单击VIEW OUTPUT按钮可查看通过运行以下代码创建的数据:
$spaceship = new SpaceShip(); $spaceship->id = 1234; $spaceship->name = 'Nostromo'; $spaceship->save(); $passengerEllen = new Passenger(); $passengerEllen->name = 'Ellen Ripley'; $passengerDwayne = new Passenger(); $passengerDwayne->name = 'Dwayne Hicks'; $spaceship->passengers()->save($passengerEllen); $spaceship->passengers()->save($passengerDwayne);