GraphQL (Apollo)、Sequelize、MySQL & 使用非标准外键
GraphQL (Apollo), Sequelize, MySQL & using non-standard foreign keys
我正在使用 Apollo、Sequelize、Node 和 MySQL 在 GraphQL 服务器上工作。数据由视频和团队(在那些视频中)组成。我还使用非标准外键将团队连接到特定视频(数据库 table Teams 有一个名为 'inVideo' 的字段,而不是默认的 'VideoId' 字段)。创建视频和团队以及查询特定的(带有 id)或所有项目都不是问题。但是,当我尝试查询属于特定视频的团队时(通过提供特定视频的 ID),后端的 SQL SELECT 查询包含一个额外的字段名称,这是默认的 foreign键构造“VideoId”,由于该字段在数据库中不存在,查询失败。
这是创建 Teams table 的迁移文件(注意 inVideo 字段定义):
'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;
};
在数据库中生成视频的迁移文件table没有什么特别的,但是这里是视频的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)可能不正确。有更好的方法吗?
当您使用自己的显式外键字段时,不要忘记为两端的关联指明它:
Video.hasMany(models.Team, { foreignKey: "inVideo" })
否则,Sequelize 将使用默认外键名称ModelName+Id
(在本例中为VideoId
)。
我正在使用 Apollo、Sequelize、Node 和 MySQL 在 GraphQL 服务器上工作。数据由视频和团队(在那些视频中)组成。我还使用非标准外键将团队连接到特定视频(数据库 table Teams 有一个名为 'inVideo' 的字段,而不是默认的 'VideoId' 字段)。创建视频和团队以及查询特定的(带有 id)或所有项目都不是问题。但是,当我尝试查询属于特定视频的团队时(通过提供特定视频的 ID),后端的 SQL SELECT 查询包含一个额外的字段名称,这是默认的 foreign键构造“VideoId”,由于该字段在数据库中不存在,查询失败。
这是创建 Teams table 的迁移文件(注意 inVideo 字段定义):
'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;
};
在数据库中生成视频的迁移文件table没有什么特别的,但是这里是视频的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)可能不正确。有更好的方法吗?
当您使用自己的显式外键字段时,不要忘记为两端的关联指明它:
Video.hasMany(models.Team, { foreignKey: "inVideo" })
否则,Sequelize 将使用默认外键名称ModelName+Id
(在本例中为VideoId
)。