關聯

一旦定義好模型,就可以使用 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,
  },
})

此輔助函式會將 commentIds 屬性新增至 blogPost 模型,以及一些用於處理關聯的 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。

接下來,讓我們看看工廠,它利用您的模型定義來輕鬆建立關係資料圖。