关系

定义完模型后,可以使用 belongsTohasMany 辅助函数来定义它们之间的关系。每个辅助函数都会为你的模型添加一些动态方法。

belongsTo

要定义一对一关系,导入 belongsTo 辅助函数,并在指向另一个模型的模型上定义一个新属性

import { createServer, Model, belongsTo } from "miragejs"

createServer({
  models: {
    blogPost: Model.extend({
      author: belongsTo(),
    }),

    author: Model,
  },
})

这定义了与 Author 模型的 belongsTo 关系。

belongsTo 辅助函数为你的模型添加了一些新属性和方法。

在本例中,我们的 BlogPost 模型现在获得了一个 authorId 属性,以及一些用于处理关联的 author 模型的方法

blogPost.authorId // 1
blogPost.authorId = 2 // updates the relationship
blogPost.author // Author instance
blogPost.author = anotherAuthor
blogPost.newAuthor(attrs) // new unsaved author
blogPost.createAuthor(attrs) // new saved author (updates blogPost.authorId in memory only)

请注意,createAuthor 方法将创建一个新作者并立即将其保存到 db 中,但博客文章的外键仅在此实例中更新,并且不会立即持久保存到数据库。因此,blogPost.authorId 将在内存中更新,但如果你再次从 db 中获取 blogPost,则关系不会持久保存。

要持久保存新外键,你需要在创建新作者后调用 blogPost.save()

hasMany

要定义一对多关系,使用 hasMany 辅助函数

import { createServer, Model, hasMany } from "miragejs"

createServer({
  models: {
    blogPost: Model.extend({
      comments: hasMany(),
    }),

    comment: Model,
  },
})

该辅助函数为 blogPost 模型添加了 commentIds 属性,以及一些用于处理关联的 comments 集合的方法

blogPost.commentIds // [1, 2, 3]
blogPost.commentIds = [2, 3] // updates the relationship
blogPost.comments // array of related comments
blogPost.comments = [comment1, comment2] // updates the relationship
blogPost.newComment(attrs) // new unsaved comment
blogPost.createComment(attrs) // new saved comment (comment.blogPostId is set)

一对一

可以使用两个模型上的 belongsTo 辅助函数来定义一对一关系

import { createServer, Model, belongsTo } from "miragejs"

createServer({
  models: {
    supplier: Model.extend({
      account: belongsTo(),
    }),

    account: Model.extend({
      supplier: belongsTo(),
    }),
  },
})

默认情况下,Mirage 会将这两个关系标记为彼此的倒数,因此能够在它们发生变化时保持同步。例如,如果 supplierA.accountaccountB,则 accountB.supplier 将指向 supplierA。如果 supplierA.account 设置为 null,则 accountB.supplier 关系侧也将设置为 null 以保持关系同步。

一对多

可以使用一个模型上的 belongsTo 助手和逆模型上的 hasMany 助手来定义一对多关系。

import { createServer, Model, belongsTo, hasMany } from "miragejs"

createServer({
  models: {
    user: Model.extend({
      comments: hasMany(),
    }),

    comment: Model.extend({
      user: belongsTo(),
    }),
  },
})

Mirage 会将它们标记为彼此的逆,并在它们发生变化时保持同步。

多对多

可以使用两个模型上的 hasMany 助手来定义多对多关系。

import { createServer, Model, hasMany } from "miragejs"

createServer({
  models: {
    blogPost: Model.extend({
      tags: hasMany(),
    }),

    tag: Model.extend({
      blogPosts: hasMany(),
    }),
  },
})

Mirage 会将它们标记为彼此的逆,并在它们发生变化时保持同步。

关联选项

以下选项可用于自定义您的 belongsTohasMany 关系定义。

modelName

如果您的关联模型与关联本身的名称不同,则可以在关联上指定 modelName

例如,

import { createServer, Model, belongsTo, hasMany } from "miragejs"

createServer({
  models: {
    user: Model,

    annotation: Model,

    blogPost: Model.extend({
      author: belongsTo("user"),
      comments: hasMany("annotation"),
    }),
  },
})

将添加上面列出的所有名为 authorcomment 的方法,但使用 UserAnnotation 模型用于实际关系。

inverse

通常,关系可以是彼此的逆。

例如,假设我们有以下两个模型

import { createServer, Model, belongsTo, hasMany } from "miragejs"

createServer({
  models: {
    blogPost: Model.extend({
      comments: hasMany(),
    }),

    comment: Model.extend({
      blogPost: belongsTo(),
    }),
  },
})

在这种情况下,blogPost.comments 将指向 Comment 模型的集合,并且这些 Comment 模型中的每一个都将具有一个 comment.blogPost 关系,该关系指向原始帖子。

Mirage 通常可以推断出两个不同模型上的两个关系是彼此的逆,但有时您需要明确说明。这通常发生在模型具有两个指向相同模型类型的关系时。

例如,假设我们有以下模式

import { createServer, Model, belongsTo, hasMany } from "miragejs"

createServer({
  models: {
    user: Model.extend({
      blogPosts: hasMany(),
    }),

    blogPost: Model.extend({
      author: belongsTo("user"),
      reviewer: belongsTo("user"),
    }),
  },
})

在这种情况下,Mirage 不知道哪个关系(blogPost.authorblogPost.reviewer)应与 user.blogPosts 集合同步。因此,您可以使用 inverse 选项指定哪一个是逆。

import { createServer, Model, belongsTo, hasMany } from "miragejs"

createServer({
  models: {
    user: Model.extend({
      blogPosts: hasMany(),
    }),

    blogPost: Model.extend({
      author: belongsTo("user", { inverse: "blogPosts" }),
      reviewer: belongsTo("user", { inverse: null }),
    }),
  },
})

现在,如果将一篇博文添加到 user.blogPosts,该博文的 author 将被正确更新。

polymorphic

您可以通过传递 { polymorphic: true } 作为选项来指定关联是否为多态关联。

例如,假设您有 BlogPostPicture 模型,它们都可以有一个 Comment。以下是模型定义的示例

import { createServer, Model, belongsTo, hasMany } from "miragejs"

createServer({
  models: {
    blogPost: Model.extend({
      comments: hasMany(),
    }),

    picture: Model.extend({
      comments: hasMany(),
    }),

    comment: Model.extend({
      commentable: belongsTo({ polymorphic: true }),
    }),
  },
})

我们为 Comment 模型提供了一个 commentable 多态关系,因为被评论的模型可能是 BlogPostPicture。请注意,commentable 没有类型,因为在该关系上存在哪些类型的模型没有进行验证。

多态关联对其外键和构建/创建方法具有略微不同的方法签名。

let comment = server.schema.comments.create({ text: "foo" })

comment.buildCommentable("blog-post", { title: "Lorem Ipsum" })
comment.createCommentable("blog-post", { title: "Lorem Ipsum" })

// getter
comment.commentableId // { id: 1, type: 'blog-post' }

// setter
comment.commentableId = { id: 2, type: "picture" }

多对多关系也可以是多态的

import { createServer, Model, belongsTo, hasMany } from "miragejs"

createServer({
  models: {
    car: Model,

    watch: Model

    user: Model.extend({
      things: hasMany({ polymorphic: true })
    }),
  },
})
let user = server.schema.users.create({ name: "Sam" });

user.buildThing('car', { attrs });
user.createThing('watch', { attrs });

// getter
user.thingIds; // [ { id: 1, type: 'car' }, { id: 3, type: 'watch' }, ... ]

// setter
user.thingIds = [ { id: 2, type: 'watch' }, ... ];

请务必查看 Schema、Model 和 Collection API 文档,以了解所有可用的 ORM 方法。

我们还将在这些指南中介绍序列化器,您将在其中学习如何自定义模型和集合的序列化形式以匹配您的生产 API。

接下来,让我们看一下工厂,工厂利用您的模型定义来简化创建关系数据的图表。