【问题标题】:GraphQL (Apollo), Sequelize, MySQL & using non-standard foreign keysGraphQL (Apollo)、Sequelize、MySQL 和使用非标准外键
【发布时间】:2022-02-13 18:32:03
【问题描述】:

我正在使用 Apollo、Sequelize、Node 和 MySQL 开发 GraphQL 服务器。数据由视频和团队(在这些视频中)组成。我还使用非标准外键将团队连接到特定视频(数据库表 Teams 有一个名为“inVideo”的字段,而不是默认的“VideoId”字段)。创建视频和团队以及查询特定的(带有 id)或所有项目都不是问题。但是,当我尝试查询属于特定视频的团队时(通过提供特定视频的 id),后端的 SQL SELECT 查询包含一个附加字段名称,它是默认的外键构造“VideoId”,并且作为该字段在数据库中不存在,查询失败。

这里是创建 Teams 表的迁移文件(注意 inVideo-field 定义):

'use strict';
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Teams', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      inVideo: {
        allowNull: false,
        type: Sequelize.INTEGER
      },
      name: {
        allowNull: false,
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable('Teams');
  }
};

这是Sequelize的团队模型定义(注意belongsTo中的foreignKey定义)

'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Team extends Model {
    static associate(models) {
      Team.belongsTo(models.Video, { foreignKey: "inVideo" })
    }
  }
  Team.init({
    name: {
      allowNull: false,
      type: DataTypes.STRING
    }
  }, {
    sequelize,
    modelName: 'Team',
  });
  return Team;
};

在数据库中生成视频表的迁移文件没有什么特别之处,但这里是视频的Sequelize模型文件(因为我在该模型中添加了hasMany关系):

'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Video extends Model {
    static associate(models) {
      Video.hasMany(models.Team)
    }
  }
  Video.init({
    videoUrl: {
      allowNull: false,
      type: DataTypes.STRING
    }
  }, {
    sequelize,
    modelName: 'Video',
  });
  return Video;
};

然后是 GraphQL 架构定义

const { gql } = require('apollo-server');
const typeDefs = gql`
  type Video {
    id: Int!
    videoUrl: String!
    teams: [Team!]!
  }

  type Team {
    id: Int!
    name: String!
    video: Video!
  }

  type Query {
    teams(inVideo: Int!): [Team!]!
  }

  type Mutation {
    createVideo(videoUrl: String!): Video!
    createTeam(inVideo: Int!, name: String!): Team!
  }
`;
module.exports = typeDefs;

最后是服务器的解析器定义:

const resolvers = {
  Query: {
    async teams(root, { inVideo }, { models }) {
      return models.Team.findAll({
        where: {
          inVideo: inVideo
        }
      });
    },
  },
  Mutation: {
    async createVideo(root, { videoUrl }, { models }) {
      return models.Video.create({ videoUrl });
    },
    async createTeam( root, { inVideo, name }, { models }) {
      return models.Team.create({ inVideo, name });
    },
  },
  Video: {
    async teams(video) {
      return video.getTeams();
    },
  },
  Team: {
    async video(team) {
      return team.getVideo();
    },
  },  
};
module.exports = resolvers;

如上所述,创建视频和团队工作正常,并且数据库中的数据是正确的。但是,当我尝试查询服务器以获取某个视频的团队时,SQL SELECT 子句如下:

SELECT `id`, `name`, `createdAt`, `updatedAt`, `inVideo`, `VideoId` FROM `Teams` AS `Team` WHERE `Team`.`inVideo` = 1;

VideoId字段不应该在那里,因为它在数据库中不存在(关系信息存储在inVideo字段中)。

我怎样才能摆脱这种行为? (我认为 belongsTo 方法调用中的 foreignKey 选项可以解决这个问题)

另外,我使用关系定义关系/查询团队的方式(使用 findAll 的 where-option)可能不正确。有没有更好的方法来做到这一点?

【问题讨论】:

    标签: graphql sequelize.js apollo-server


    【解决方案1】:

    当您使用自己的显式外键字段时,不要忘记为两端的关联指明它:

    Video.hasMany(models.Team, { foreignKey: "inVideo" })
    

    否则,Sequelize 将使用默认外键名称 ModelName+Id(在本例中为 VideoId)。

    【讨论】:

    • 啊……当然!谢谢!它有效!
    猜你喜欢
    • 2017-07-19
    • 2021-04-07
    • 2019-06-29
    • 1970-01-01
    • 2017-09-01
    • 2015-03-19
    • 2021-04-10
    • 2021-09-13
    • 2018-09-07
    相关资源
    最近更新 更多