从 Prisma 中的多对多表中获取元信息

Posted

技术标签:

【中文标题】从 Prisma 中的多对多表中获取元信息【英文标题】:Getting meta information from many-to-many table in Prisma 【发布时间】:2021-06-20 14:23:17 【问题描述】:

我有这个表结构

注意item_level

我需要完成的是拥有相同的物品,连接到许多玩家,但每个玩家都可以独立升级物品。

这是我能想到的最简单的结构,用 sql 术语来说,连接表、选择字段并显示这些连接很容易。

我的问题是,我正在使用 Apollo graphql 和 Prisma ORM (v ^2.18.0),即使我可以得到每个玩家的物品,但我也可以-versa,我不知道如何包含那个额外的字段。

prisma.schema

model Player 
    id      Int              @id @default(id())
    items   ItemToPlayer[]


model Item 
    id      Int              @id @default(id())
    players ItemToPlayer[]


model ItemToPlayer 
    player      Player  @relation(fields: [playerId], references: [id])
    playerId    Int
    item        Item    @relation(fields: [itemId], references: [id])
    itemId      Int
    itemLevel   Int     @default(0)

    @@id([playerId, itemId])

类型定义

const typeDefs = gql`
    type Player 
        id: ID!
        items: [Item]
    

    type Item 
        id: ID!
        players: [Player]
    

    type ItemToPlayer 
        playerId: Int!
        itemId: Int!
        itemLevel: Int!
    
`;

解析器

const resolvers = 
    Player: 
        items: (parent, args, context, info) => 
            return context.db.item.findMany(
                where: 
                    players: 
                        some: 
                            playerId: parent.id
                        
                    
                ,
                include: 
                    players: true
                
            );
        ,
    ,

    Item: 
        players: (parent, args, context, info) => 
            return context.db.player.findMany(
                where: 
                    items: 
                        some: 
                            itemId: parent.id
                        
                    
                ,
                include: 
                    items: true
                
            );
        ,
    ,

    Query:  /* ... */ ,

    Mutation:   /* ... */ ,
;

这是我在查询玩家包括他们的物品时想要得到的结果


    "data": 
        "players": [
            
                "id": 1
                "items": [
                    
                        "id": 1,
                        "itemLevel": 2 // <--- This is missing 
                    ,
                    
                        "id": 2,
                        "itemLevel": 3
                    ,
                ]
            ,
            
                "id": 2
                "items": [
                    
                        "id": 1,
                        "itemLevel": 0 // same item (id: 1) has different level per player
                    
                ]
            ,
        ]
    

在documentation 中,它将此描述为显式多对多关系,并提到

请注意,适用与 1-n 关系相同的规则(因为 Post↔ CategoriesOnPosts 和 Category ↔ CategoriesOnPosts 实际上都是 1-n-relations),这意味着关系的一侧需要是 使用@relation 属性进行注释。

但它没有提供示例。

进一步研究1-n-relations@relation,我发现的唯一示例是外键。

在 Internet 上搜索时,我发现其他人就不同的框架和 ORM 提出相同的问题,但没有找到 Prisma。 (除非我错过了

【问题讨论】:

【参考方案1】:

我建议将您的 typedef 更改为:

const typeDefs = gql`
    type Player 
        id: ID!
        items: [ItemToPlayer]
    

    type Item 
        id: ID!
        players: [ItemToPlayer]
    

    type ItemToPlayer 
        playerId: Int!
        itemId: Int!
        itemLevel: Int!
        player: Player!
        item: Item!
    
`;

然后Item 中的players 解析器将如下所示:

prisma.player.findMany(
    where: 
      items: 
        some: 
          itemId: parent.id,
        ,
      ,
    ,
    include: 
      items:  include:  item: true  ,
    ,
)

【讨论】:

将 typeDefs 更改为 ItemToPlayer 而不是 Item 有帮助,因为我可以在 db 中查询 itemToPlayer,然后在结果中查询 Item。嵌套的include 给了我一个错误。我设法在没有嵌套包含的情况下做到了。不过,我确实必须修改查询本身。【参考方案2】:

正如@Ryan 在他的回答中建议的那样,我设法通过将Item 更改为ItemToPlayer 并更改我的查询和解析器来获取元数据。

新的Item解析器

Item: 
    players: (parent, args, context, info) => 
        return context.db.itemToPlayer.findMany(
            where: 
                itemId: parent.id
            ,
            include: 
                item: true
            
        );
    ,
,

我现在正在查询ItemsToPlayers 表并取回ItemToPlayer 类型,然后我可以从中查询Item

CORRECT
query 
  players 
    id
    items 
      id
      itemLevel
      item 
        id
      
    
  


WRONG
query 
  players 
    id
    items 
      id
      itemLevel <--- This is wrong as itemLevel
                                    does not exist in Item
    
  

结果


    "data": 
        "players": [
            
                "id": 1
                "items": [
                    
                        "itemLevel": 2
                        "item": 
                             "id": 1,
                        
                    ,
                    
                        "itemLevel": 0
                        "item": 
                             "id": 1,
                        
                    ,
                ]
            ,
        ]
    

【讨论】:

以上是关于从 Prisma 中的多对多表中获取元信息的主要内容,如果未能解决你的问题,请参考以下文章

Nextjs / prisma:我可以手动命名多对多表吗?

填充具有访问权限的多对多表

Mybatis的多表(多对多)查询

如何从多对多表中选择一对一关系

Hibernate多表关系配置——多对多对关系映射

如何在多对多表中添加列(Django)