新增一对一多态关联,并更新多态关联
ycs77_Lucas
5年前
修改理由:
相关信息:
- 类型:文档文章
- 文章: 模型关联
- 文档: 《Laravel 5.7 中文文档(5.7)》
此投稿已在 5年前 合并。
内容修改:
Old | New | Differences |
---|---|---|
7 | 7 | - [一对多 (反向)](#one-to-many-inverse) |
8 | 8 | - [多对多](#many-to-many) |
9 | 9 | - [远程一对多](#has-many-through) |
10 | - [多态关联](#polymorphic-relations) | |
11 | - [多对多多态关联](#many-to-many-polymorphic-relations) | |
10 | - [多态关联](#polymorphic-relations) | |
11 | - [一对一](#one-to-one-polymorphic-relations) | |
12 | - [一对多](#one-to-many-polymorphic-relations) | |
13 | - [多对多](#many-to-many-polymorphic-relations) | |
14 | - [自定义多态类型](#custom-polymorphic-types) | |
12 | 15 | - [查询关联](#querying-relations) |
13 | 16 | - [关联方法 Vs. 动态属性](#relationship-methods-vs-dynamic-properties) |
14 | 17 | - [基于存在的关联查询](#querying-relationship-existence) | … | … |
33 | 36 | - [一对多](#one-to-many) |
34 | 37 | - [多对多](#many-to-many) |
35 | 38 | - [远程一对多](#has-many-through) |
36 | - [多态关联](#polymorphic-relations) | |
37 | - [多对多多态关联](#many-to-many-polymorphic-relations) | |
39 | - [一对一 (多态关联)](#one-to-one-polymorphic-relations) | |
40 | - [一对多 (多态关联)](#one-to-many-polymorphic-relations) | |
41 | - [多对多 (多态关联)](#many-to-many-polymorphic-relations) | |
38 | 42 | |
39 | 43 | <a name="defining-relationships"></a> |
40 | 44 | ## 定义关联 | … | … |
423 | 427 | } |
424 | 428 | |
425 | 429 | <a name="polymorphic-relations"></a> |
426 | ### 多态关联 | |
430 | ## 多态关联 | |
431 | ||
432 | 多态关联允许一个模型在单个关联上属于多个其他模型。 | |
433 | ||
434 | <a name="one-to-one-polymorphic-relations"></a> | |
435 | ### 一对一 (多态关联) | |
427 | 436 | |
428 | 437 | #### 数据表结构 |
429 | 438 | |
430 | 多态关联允许一个模型在单个关联上属于多个其他模型。例如,想象一下使用你应用的用户可以「评论」文章和视频。使用多态关联,你可以用一个 `comments` 表同时满足这两个使用场景。让我们来看看构建这种关联所需的数据表结构: | |
439 | 一对一的多态关联类似于简单的一对一关联,但目标模型可以在单个关联上属于多个其他模型。例如,博客文章和用户可以共享与图像模型的多态关联,使用一对一的多态关联,您可以用一个 `images` 表同时满足这两个使用场景。让我们来看看构建这种关联所需的数据表结构: | |
440 | ||
441 | posts | |
442 | id - integer | |
443 | title - string | |
444 | body - text | |
445 | ||
446 | users | |
447 | id - integer | |
448 | title - string | |
449 | url - string | |
450 | ||
451 | images | |
452 | id - integer | |
453 | body - text | |
454 | imageable_id - integer | |
455 | imageable_type - string | |
456 | ||
457 | `images` 表中有两个需要注意的重要字段 `imageable_id` 和 `imageable_type`。`imageable_id` 用来保存文章或者用户的 ID 值,而 `imageable_type` 用来保存所属模型的类名。Eloquent 使用 `imageable_type` 来决定我们访问关联模型时,要返回的父模型的「类型」。 | |
458 | ||
459 | #### 模型结构 | |
460 | ||
461 | 接下来,我们来看看创建这种关联所需的模型定义: | |
462 | ||
463 | <?php | |
464 | ||
465 | namespace App; | |
466 | ||
467 | use Illuminate\Database\Eloquent\Model; | |
468 | ||
469 | class Image extends Model | |
470 | { | |
471 | /** | |
472 | * 获得拥有此图像的模型。 | |
473 | */ | |
474 | public function imageable() | |
475 | { | |
476 | return $this->morphTo(); | |
477 | } | |
478 | } | |
479 | ||
480 | class Post extends Model | |
481 | { | |
482 | /** | |
483 | * 获得此文章的图像。 | |
484 | */ | |
485 | public function image() | |
486 | { | |
487 | return $this->morphOne('App\Image', 'imageable'); | |
488 | } | |
489 | } | |
490 | ||
491 | class User extends Model | |
492 | { | |
493 | /** | |
494 | * 获得此用户的图像。 | |
495 | */ | |
496 | public function image() | |
497 | { | |
498 | return $this->morphOne('App\Image', 'imageable'); | |
499 | } | |
500 | } | |
501 | ||
502 | #### 获取多态关联 | |
503 | ||
504 | 一旦你的数据库表准备好、模型定义完成后,就可以通过模型来访问关联了。例如,我们只要简单地使用 `image` 动态属性,就可以获得某篇文章的图像: | |
505 | ||
506 | $post = App\Post::find(1); | |
507 | ||
508 | $image = $post->image; | |
509 | ||
510 | 你也可以在多态模型上,通过访问调用了 `morphTo` 的关联方法获得多态关联的拥有者。在当前例子中,是 `Image` 模型的 `imageable` 方法。所以,我们可以使用动态属性来访问这个方法: | |
511 | ||
512 | $image = App\Image::find(1); | |
513 | ||
514 | $imageable = $image->imageable; | |
515 | ||
516 | `Image` 模型的 `imageable` 关联会返回 `Post` 或者 `User` 实例,这取决于图像所属的模型类型。 | |
517 | ||
518 | <a name="one-to-many-polymorphic-relations"></a> | |
519 | ### 一对多 (多态关联) | |
520 | ||
521 | #### 数据表结构 | |
522 | ||
523 | 一对多的多态关联类似于简单的一对多关联,但目标模型可以在单个关联上属于多个其他模型。例如,您的应用程序的用户可以「评论」文章和视频,使用一对多的多态关联,您可以用一个 `comments` 表同时满足这两个使用场景。让我们来看看构建这种关联所需的数据表结构: | |
431 | 524 | |
432 | 525 | posts |
433 | 526 | id - integer | … | … |
445 | 538 | commentable_id - integer |
446 | 539 | commentable_type - string |
447 | 540 | |
448 | `comments` 表中有两个需要注意的重要字段 `commentable_id` 和 `commentable_type`。`commentable_id` 用来保存文章或者视频的 ID 值,而 `commentable_type` 用来保存所属模型的类名。 | |
541 | `comments` 表中有两个需要注意的重要字段 `commentable_id` 和 `commentable_type`。`commentable_id` 用来保存文章或者视频的 ID 值,而 `commentable_type` 用来保存所属模型的类名。Eloquent 使用 `commentable_type` 来决定我们访问关联模型时,要返回的父模型的「类型」。 | |
449 | 542 | |
450 | 543 | #### 模型结构 |
451 | 544 | … | … |
508 | 601 | |
509 | 602 | `Comment` 模型的 `commentable` 关联会返回 `Post` 或者 `Video` 实例,这取决于评论所属的模型类型。 |
510 | 603 | |
511 | ||
512 | ||
513 | ||
514 | ||
515 | ||
516 | ||
517 | ||
518 | ||
519 | ||
520 | ||
521 | ||
522 | ||
523 | ||
524 | 604 | |
525 | 605 | <a name="many-to-many-polymorphic-relations"></a> |
526 | ### 多对多 | |
527 |
| |
528 | #### | |
529 |
| |
530 | ||
606 | ### 多对多 (多态关联) | |
607 | ||
608 | #### 数据表结构 | |
609 | ||
610 | 「多对多」的多态关联比「一对一」和「一对多」的多态关联稍微复杂一些。举例而言,一个 `Post` 和 `Video` 模型共享一个 `Tag` 模型。使用多对多的多态关联将允许你去有一个在 `Video` 和 `Post` 之间共同使用一个唯一的标签列表。首先,让我们来看一下数据表结构: | |
531 | 611 | |
532 | 612 | ``` |
533 | 613 | posts | … | … |
550 | 630 | |
551 | 631 | #### 模型结构 |
552 | 632 | |
553 | 接下来,我们要 | |
633 | 接下来,我们要在模型上定义关联关系。 `Post` 和 `Video` 模型会有一个共同的 `tags` 方法,它们会被基础的模型的 `morphToMany` 方法调用: | |
554 | 634 | |
555 | 635 | ```php |
556 | 636 | <?php | … | … |
623 | 703 | // |
624 | 704 | } |
625 | 705 | ``` |
706 | ||
707 | ||
708 | <a name="custom-polymorphic-types"></a> | |
709 | ### 自定义多态类型 | |
710 | ||
711 | 默认,Laravel 会使用完全限定类名作为关联模型保存在多态模型上的类型字段值。比如,在上面的例子中,`Comment` 属于 `Post` 或者 `Video`,那么 `commentable_type`的默认值对应地就是 `App\Post` 和 `App\Video`。但是,你可能希望将数据库与程序内部结构解耦。那样的话,你可以定义一个「多态映射表」来指示 Eloquent 使用每个模型自定义类型字段名而不是类名: | |
712 | ||
713 | use Illuminate\Database\Eloquent\Relations\Relation; | |
714 | ||
715 | Relation::morphMap([ | |
716 | 'posts' => 'App\Post', | |
717 | 'videos' => 'App\Video', | |
718 | ]); | |
719 | ||
720 | 你可以在 `AppServiceProvider` 中的 `boot` 函数中使用 `Relation::morphMap` 方法注册「多态映射表」,或者使用一个独立的服务提供者注册。 | |
721 | ||
722 | ||
626 | 723 | <a name="querying-relations"></a> |
627 | 724 | ## 查询关联 |
628 | 725 | … | … |
672 | 769 | } |
673 | 770 | ``` |
674 | 771 | |
675 | 动态属性就像 | |
772 | 动态属性就像「懒加载」,也就是说当你确实会使用到它们的使用,它会自动进行加载。由于这一特性,开发者经常会使用到 [懒加载](#eager-loading) 去实现那些在获取到模型后必须要加载的关联模型。懒加载对 那些在模型上定了关联关系 SQL 查询上有了性能的提升,它们对 SQL 查询语句的执行次数有了明显的减少(也就是 n + 1性能问题)。 | |
676 | 773 | |
677 | 774 | <a name="querying-relationship-existence"></a> |
678 | 775 | ### 查询关联关系是否存在 | … | … |
690 | 787 | $posts = App\Post::has('comments', '>=', 3)->get(); |
691 | 788 | ``` |
692 | 789 | |
693 | `has` 方法也可可以接受以 | |
790 | `has` 方法也可可以接受以 「.」 点形式的嵌套加载。举例来说,你要获取到至少包含一条评论和投票的博客: | |
694 | 791 | |
695 | 792 | ```php |
696 | 793 | // 获取至少有一条评论的文章,并加载评论的投票信息 | … | … |
698 | 795 | ``` |
699 | 796 | |
700 | 797 | 如果你想要做更多特性,你还可以使用 `whereHas` 和 ` |
701 | orWhereHas` 方法,在方法中,你可以指定 | |
798 | orWhereHas` 方法,在方法中,你可以指定 「where」 条件在你的 `has` 语句之中。这些方法允许你在关联查询之中添加自定义的条件约束,比如检查评论的内容: | |
702 | 799 | |
703 | 800 | ```php |
704 | 801 | // 获取所有至少有一条评论的文章且评论内容以 foo 开头 | … | … |
723 | 820 | })->get(); |
724 | 821 | ``` |
725 | 822 | |
726 | 你可能要使用 | |
823 | 你可能要使用 「.」 点符号去执行一个嵌套的加载。举例来说,如下语句,将会获取到所有文章,同时加载了那些没有被禁用的用户的文章评论: | |
727 | 824 | |
728 | 825 | ```php |
729 | 826 | $posts = App\Post::whereDoesntHave('comments.author', function ($query) { | … | … |
771 | 868 | <a name="eager-loading"></a> |
772 | 869 | ## 懒加载 |
773 | 870 | |
774 | 当通过动态属性的方法去加载关联数据时,它已经是在 | |
871 | 当通过动态属性的方法去加载关联数据时,它已经是在 「懒加载」 了。也就是说,当你在未使用到该关联数据时,它其实是并没有查询数据的。然而, 当你在查询父级模型时, Eloquent 允许渴求式加载关联数据,渴求式加载避免了 N + 1 查询问题。为了说明 N + 1 的查询问题,思考 `Book` 模型关联了 `Auhtor` : | |
775 | 872 | |
776 | 873 | ```php |
777 | 874 | <?php | … | … |
832 | 929 | |
833 | 930 | #### 嵌套式的渴求式加载 |
834 | 931 | |
835 | 实现渴求式加载也很简单,你可以使用 | |
932 | 实现渴求式加载也很简单,你可以使用 「.」 点语法去实现。譬如,我们需要加载所有的书籍,并且包含作者以及作者的联系方式。那么我们就可以这样写: | |
836 | 933 | |
837 | 934 | ```php |
838 | 935 | $books = App\Book::with('author.contacts')->get(); |