gpt4 book ai didi

javascript - 如何在 GraphQL 接口(interface)上将模型与 "has one"关系相关联

转载 作者:行者123 更新时间:2023-11-30 19:36:04 24 4
gpt4 key购买 nike

我有一个使用 Sequelize/mysql 的 GraphQL/Apollo 服务器。我的 GraphQL 类型(Employee、Contractor)各自实现了一个 Person 接口(interface)。我的数据库模型包含一个雇员、承包商和事件表。我希望我的人物类型与事件有“很多”关系。而我的事件类型“属于”员工或承包商的人员类型。

我猜它与事件类型中的 person_id 字段有关。我可以让它在没有单个表“Employee”上的界面并将 person_id 更改为 employee_id 的情况下工作。所以我猜它只是不知道如何区分 Employee 和 Contractor 来引用该表?

//typeDefs.js

const typeDefs = gql`
type Event {
id: ID!
person_id: ID!
location: String!
escort: String!
}

interface Person {
id: ID!
first_name: String!
last_name: String!
department_company: String!
events: [Event]
}

type Employee implements Person {
id: ID!
first_name: String!
last_name: String!
department_company: String!
events: [Event]
employee_sh_id: String
}

type Contractor implements Person {
id: ID!
first_name: String!
last_name: String!
department_company: String!
events: [Event]
escort_required: Boolean!
}
//Employee model

module.exports = (sequelize, DataTypes) => {
const Employee = sequelize.define('Employee', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
department_company: DataTypes.STRING,
emplyee_sh_id: DataTypes.STRING
}, {});
Employee.associate = function(models) {
Employee.hasMany(models.Event);
};
return Employee;
};
// Contractor model

module.exports = (sequelize, DataTypes) => {
const Contractor = sequelize.define('Contractor', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
department_company: DataTypes.STRING,
escort_required: DataTypes.BOOLEAN,
}, {});
Contractor.associate = function(models) {
Contractor.hasMany(models.Event);
};
return Contractor;
};
// Event model

module.exports = (sequelize, DataTypes) => {
const Event = sequelize.define(
"Event",
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
person_id: DataTypes.INTEGER,
location: DataTypes.STRING,
escort: DataTypes.STRING
},
{}
);
Event.associate = function(models) {
Event.belongsTo(models.Employee),
Event.belongsTo(models.Contractor)
};
return Event;
};
// resolvers.js

const resolvers = {
Query: {
async employee(root, { id }, { models }) {
return models.Employee.findByPk(id);
},
async contractor(root, { id }, { models }) {
return models.Contractor.findByPk(id);
},
async employees(root, args, { models }) {
return models.Employee.findAll();
},
async contractors(root, args, { models }) {
return models.Contractor.findAll();
},
async event(root, { id }, { models }) {
return models.Event.findByPk(id);
},
async events(root, args, { models }) {
return models.Event.findAll();
}
},

Mutation: {
async addEmployee(
root,
{
first_name,
last_name,
department_company,
employee_sh_id
},
{ models }
) {
return models.Employee.create({
first_name,
last_name,
department_company,
employee_sh_id
});
},

async addContractor(
root,
{
first_name,
last_name,
department_company,
escort_required,
},
{ models }
) {
return models.Contractor.create({
first_name,
last_name,
department_company,
escort_required,
});
},

async addEvent(
root,
{ person_id, location, escort },
{ models }
) {
return models.Event.create({
person_id,
location,
escort
});
},

Person: {
__resolveType: person => {
if (person.employee) {
return "Employee";
}
return "Contractor";
}
},

Employee: {
events: (parent, args, context, info) => parent.getEvents(),
},

Contractor: {
events: (parent, args, context, info) => parent.getEvents(),
}
};

最佳答案

你甚至需要一个界面吗?

抽象类型(如接口(interface)和联合)背后的主要目的是它们允许特定字段解析为一组类型中的一个。如果您有 ContractorEmployee 类型并希望特定字段返回任一类型,那么添加接口(interface)或联合来处理该场景是有意义的:

type Event {
contractors: [Contractor!]!
employees: [Employee!]!
people: [Person!]! # could be either
}

如果您不需要此功能,则您实际上不需要任何抽象类型。 (旁注:您可以仅使用接口(interface)来强制共享字段的类型之间的一致性,但此时您只是将它们用作验证工具,它们的存在可能不应影响您设计底层数据层的方式)。

没有 Elixir

处理关系数据库中的继承 can be tricky并且没有放之四海而皆准的答案。使用 Sequelize 或其他 ORM 时,事情甚至变得很奇怪,因为您的解决方案也必须在该特定库的限制内工作。这里有几种不同的方法可以解决这个问题,但目前还不是一个详尽的列表:

  • 如果您只有几个返回Person 类型的字段,您可以使用单独的表和单独的模型并自行合并结果。像这样的东西:
people: async (event) => {
const [employees, contractors] = await Promise.all([
event.getEmployees(),
event.getContractors(),
])
const people = employees.concat(contractors)
// Sort here if needed
return people
}

这确实意味着您现在要查询数据库两次,并且可能会花费额外的时间进行排序,否则数据库会为您完成这些工作。但是,这意味着您可以为承包商和雇员维护单独的表和模型,这意味着查询这些实体非常简单。

  • 将 Contractors 和 Employees 集中在一个表中,使用某种 type 字段来区分两者。然后你可以 use scopes帮助您在 Sequelize 中适本地建模关系:
Event.hasMany(models.Person, { as: 'employees', scope: {type: 'EMPLOYEE'} ... })
Event.hasMany(models.Person, { as: 'contractors', scope: {type: 'CONTRACTOR'} ... })
Event.hasMany(models.Person, { as: 'people', /** no scope **/ ... })

这很有效,即使它“感觉”不到将所有内容都放在一张表中也是如此。您必须记住正确确定关联和查询的范围。

  • 如果您将 Sequelize 严格用作 ORM 而不是从您的 Sequelize 模型生成数据库(即不调用 sync),也可以对 view 进行建模作为 Sequelize 模型。编写和维护 View 有点麻烦,但这将允许您为员工和承包商保留单独的表,同时从其他两个表创建一个可用于查询所有人员的虚拟表。

关于javascript - 如何在 GraphQL 接口(interface)上将模型与 "has one"关系相关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55944084/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com