我的架构中包含以下实体。
如何为User
和Post
类型之间的一对多关系建模,其中Post
可以是LinkPost
或NormalPost
的两种类型。
答案 0 :(得分:1)
我将利用GraphQL中存在的一种多态类型对这些模式进行建模。这种方法将为您将来的查询和扩展提供最大的灵活性。
User
这样拥有Posts
的数组非常方便:
type User {
id: Int!
email: String!
posts: [Posts!]
username: String!
}
这意味着Post
必须是interface
或union
类型。这两种类型中的任何一种都使我们能够利用NormalPost
和LinkedPost
仍然都是Post
的事实。就像上面user.posts
一样,它也使我们可以在同一位置查询它们。
在OOP中,interface
类型的行为与interface
类型非常相似。它定义了任何实现类型都必须具有的基本字段集。例如,所有Post
对象可能看起来像这样:
interface Post {
id: Int!
author: String!
dateCreated: String!
dateUpdated: String!
title: String!
}
任何类型的implements
Post
接口都必须同时具有字段id
,author
,dateCreated
,dateUpdated
和{{ 1}}以及除该类型特定的任何字段之外的其他实现。因此,使用title
,interface
和NormalPost
可能如下所示:
LinkedPost
type NormalPost implements Post {
id: Int!
author: String!
body: String!
dateCreated: String!
dateUpdated: String!
title: String!
}
union
类型允许将不需要实现相似字段的不同类型一起返回。 type LinkedPost implements Post {
id: Int!
author: String!
dateCreated: String!
dateUpdated: String!
link: String!
title: String!
}
类型的结构与使用接口的结构不同,因为union
类型不指定任何字段。在union
模式定义中定义的唯一内容是由union
分隔的联合类型。
该规则的唯一警告是|
中定义了相同字段名称的任何类型都必须具有相同的可空性(即,由于union
是不可空的({{ 1}}),那么NormalPost.title
也必须是不可为空的。
title: String!
LinkedPost.title
union Post = NormalPost | LinkedPost
上面的内容介绍了在从type NormalPost implements Post {
id: Int!
author: String!
body: String!
dateCreated: String!
dateUpdated: String!
title: String!
}
中查询type LinkedPost implements Post {
id: Int!
author: String!
dateCreated: String!
dateUpdated: String!
link: String!
title: String!
}
与LinkedPost
时如何区分它们的问题。在这两种情况下,您都需要使用条件Fragment。
条件片段允许从NormalPost
或user.posts
类型中查询一组特定的字段。它们看起来与常规查询片段相同,因为它们是在查询正文中使用interface
语法定义的。对于union
和... on <Type>
类型,条件片段的结构方式略有不同。
除了使用条件片段进行查询外,向多态查询中添加interface
Meta Field往往很有用,这样查询的使用者可以更好地识别代码中结果对象的类型
由于union
定义了一组特定的字段,所有实现类型都有相同的字段,因此可以像查询任何其他普通类型一样查询这些字段。区别在于__typename
类型具有特定于其类型的不同字段,例如interface
与interface
。选择整个NormalPost.body
接口,然后选择LinkedPost.link
和Post
的查询如下所示:
NormalPost.body
由于LinkedPost.link
在其类型之间未定义任何公共字段,因此所有要选择的字段必须存在于每个条件片段中。这是查询query getUsersNormalAndLinkedPosts {
user(id: 123) {
id
name
username
posts {
__typename
id
author
dateCreated
dateUpdated
title
... on NormalPost {
body
}
... on LinkedPost {
link
}
}
}
}
和union
之间的唯一区别。查询interface
类型如下:
union
这两种多态类型都有优点和缺点,由您决定哪种类型最适合您的用例。在构建GraphQL模式时,我都利用了两者,在使用union
或query getUsersNormalAndLinkedPosts {
user(id: 123) {
id
name
username
posts {
__typename
... on NormalPost {
id
author
body
dateCreated
dateUpdated
title
}
... on LinkedPost {
id
author
dateCreated
dateUpdated
link
title
}
}
}
}
时,我的具体区别是实现类型之间是否存在公共字段。
当实现类型之间的唯一区别只是一小部分字段而其余部分在它们之间共享时,接口具有很大的意义。这样可以减少查询量,并可能减少所需的条件片段。
当您的类型是互不相关但又重新组合在一起的多种不同类型的掩码(例如在一组搜索结果中)时,联合会真正发光。根据搜索类型的不同,返回的结果可能会返回许多看起来完全不同的不同类型。例如,在CMS上进行的搜索可能同时产生用户和帖子。在这种情况下,最好使用以下类型:
interface
。
然后可以从带有签名的查询中返回
union
在这个特定问题的背景下,我将使用union SearchResult = User | Post
方法,因为从关系和查询的角度来看,这是最有意义的。
答案 1 :(得分:-1)
您是否考虑过拥有单个Post
实体并使用枚举类型定义帖子类型?
用户
type User {
id: ID!
posts: [Post!]!
}
发布
type Post {
id: ID!
title: String!
createdBy: User!
type: PostType!
}
和Post
PostType
enum PostType {
NORMAL
LINK
}
-----更新! -----
如果您要分离实体,则可以这样做:
用户
type User {
id: ID!
linkPosts: [LinkPost!]!
normalPosts: [NormalPost]
}
LinkPost 类型
type LinkPost {
description: String!
url: String!
createdBy: User!
}
NormalPost 类型
type NormalPost {
title: String!
description: String!
createdBy: User!
}
让我知道这是否适合您
致谢