【发布时间】:2022-08-02 21:25:26
【问题描述】:
我要这个:
我可以在几分钟内使用 SQL 手动完成此操作,这是一个非常常见的场景,所以我不得不认为 Sequelize 中有一种方法。
用户可以在许多组织中担任许多角色。我可能是 Acme 的管理员,但只是 Microsoft 的用户。看起来像这样的数据:
用户数据:
组织数据:
角色:
然后,当然,我可以把它们放在一起:
select
u.username,
r.name,
o.name
from
\"user\" u
inner join
user_role_organization uro on u.id = uro.user_id
inner join
organization o on uro.organization_id = o.id
inner join
role r on uro.role_id = r.id
我正在使用的真实世界模型如下所示:
const orgModel = {
id: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
name: {
type: DataTypes.STRING(100),
allowNull: false
}
};
const roleModel = {
id: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
name: {
type: DataTypes.STRING(100),
allowNull: false
}
};
const userModel = {
id: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
username: {
type: DataTypes.STRING(100),
allowNull: false
}
};
const organizationUserToRoleModel = {
id : {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
organization_id: {
type: DataTypes.UUID,
allowNull: false
},
role_id: {
type: DataTypes.UUID,
allowNull: false
},
user_id: {
type: DataTypes.UUID,
allowNull: false
}
};
...以及他们各自的关系
auth_user.belongsToMany(auth_organization, { as: \"AuthOrganizations\", through: organization_to_user_to_role, foreignKey: \"user_id\" });
auth_organization.belongsToMany(auth_user, { as: \"AuthUsers\", through: organization_to_user_to_role, foreignKey: \"organization_id\" });
auth_organization.belongsToMany(role, { as: \"Roles\", through: organization_to_user_to_role, foreignKey: \"organization_id\" });
role.belongsToMany(auth_organization, { as: \"RoleOrganizations\", through: organization_to_user_to_role, foreignKey: \"role_id\" });
auth_user.belongsToMany(role, { as: \"OrganizationUserRoles\", through: organization_to_user_to_role, foreignKey: \"user_id\" });
role.belongsToMany(auth_user, { as: \"OrganizationRoleUsers\", through: organization_to_user_to_role, foreignKey: \"role_id\" });
我最终得到了一些看起来正确的东西:
但是,在播种类似数据时出现以下错误:
ValidationErrorItem {
message: \'organization_id must be unique\',
type: \'unique violation\',
path: \'organization_id\',
value: \'385e2860-094d-11ed-a072-25e64f3c77e7\',
origin: \'DB\',
instance: null,
validatorKey: \'not_unique\',
validatorName: null,
validatorArgs: []
}
没有任何意义,除了“id”之外的任何东西都需要在该表中是唯一的,不是吗?我猜它是因为是外键而强制唯一性?我使用如下填充的值来做到这一点:
let acmeOrg = await auth_organization.findOne({ where: { name: \"ACME Corp.\" } });
let fakeOrg = await auth_organization.findOne({ where: { name: \"Fake, Inc.\" } });
let user1 = await auth_user.findOne({ where: { username: \"user1\" } });
let user2 = await auth_user.findOne({ where: { username: \"user2\" } });
let ownerRole = await role.findOne({ where: { name: \"Owner\" } });
let adminRole = await role.findOne({ where: { name: \"Admin\" } });
let userRole = await role.findOne({ where: { name: \"User\" } });
await user1.addAuthOrganizations(acmeOrg,
{
through: {
role_id: ownerRole.id
}
});
await user2.addAuthOrganizations(acmeOrg,
{
through: {
role_id: adminRole.id
}
});
await user1.addAuthOrganizations(fakeOrg,
{
through: {
role_id: userRole.id
}
});
我拥有比 Sequelize 更多的历史和关系数据。我还为连接表尝试了这个模型,它创建了一个非常陌生的模型,它在 user_id 和 organization_id 字段上强制使用复合主键,即使我设置了 primaryKey: false。
编辑 1:
我怀疑这完全取决于我如何为模型构建 FK,只是来自之前的 Sequelize 冒险。我只是尝试将 unique 设置为 false 并像这样设置 FK - 它现在抱怨 \"user_id\" 必须是唯一的,即使这不是真的,至少根据我的意图。
let organizationUserToRoleModel = {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
organization_id: {
type: DataTypes.UUID,
allowNull: false,
unique: false
},
role_id: {
type: DataTypes.UUID,
allowNull: false,
unique: false
},
user_id: {
type: DataTypes.UUID,
allowNull: false,
unique: false
}
};
auth_user.belongsToMany(auth_organization, { as: \"AuthUserOrganizations\", through: organization_to_user_to_role, foreignKey: \"user_id\" });
auth_organization.belongsToMany(auth_user, { as: \"OrganizationAuthUsers\", through: organization_to_user_to_role, foreignKey: \"organization_id\" });
auth_organization.belongsToMany(role, { as: \"AuthOrganizationRoles\", through: organization_to_user_to_role, foreignKey: \"organization_id\" });
role.belongsToMany(auth_organization, { as: \"RoleAuthOrganizations\", through: organization_to_user_to_role, foreignKey: \"role_id\" });
编辑2:
找到原因了!无论我对模型做什么,都会将唯一约束添加到外键中。这是连接表的最新模型:
let organizationUserToRoleModel = {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
organization_id: {
type: DataTypes.UUID,
allowNull: true,
constraints: false,
unique: false
},
role_id: {
type: DataTypes.UUID,
allowNull: true,
constraints: false,
unique: false
},
user_id: {
type: DataTypes.UUID,
allowNull: true,
constraints: false,
unique: false
}
};
但是,当我检查结果时它们仍然被创建:
ALTER TABLE auth.organization_to_user_to_role ADD CONSTRAINT organization_to_user_to_role_organization_id_role_id_key UNIQUE (organization_id, role_id)
ALTER TABLE auth.organization_to_user_to_role ADD CONSTRAINT organization_to_user_to_role_user_id_key UNIQUE (user_id)
如果我手动删除它们,我可以播种预期的数据并在没有问题的情况下查询它,如下所示:
select
u.username
from
auth_user u
inner join
organization_to_user_to_role our
on u.id = our.user_id
inner join
auth_organization ao
on ao.id = our.organization_id
inner join
\"role\" r
on r.id = our.role_id
我觉得我超级接近,但不知道如何防止FK 约束被创建。将约束设置为 false 似乎在这里没有任何作用。我想我可以在事后对它们的删除进行编码,但这似乎很笨拙且不正确。
编辑 3:
我在模型本身上尝试了一些不同的东西,以及键的关系,但是我得到了完全相同的结果和完全相同的唯一约束。如果我什至可以让它设置一个单身的对所有 3 个键的唯一约束(现在它们都是复合键的一部分),这就足够了。
当前型号,我更喜欢:
let organizationUserToRoleModel = {
organization_id: {
type: DataTypes.UUID,
primaryKey: true,
constraints: false,
unique: false
},
role_id: {
type: DataTypes.UUID,
primaryKey: true,
constraints: false,
unique: false
},
user_id: {
type: DataTypes.UUID,
primaryKey: true,
constraints: false,
unique: false
}
};
似乎 \"constraints\" 和 \"unique\" 的效果为零。与我之前的尝试相比,唯一的区别是复合键比无用的自动增量 PK 更有意义。
-
再次:请简化并澄清:请给minimal reproducible example。这包括剪切&粘贴&可运行代码&示例输入;期望和实际输出(包括逐字错误消息);标签和版本;明确的规范和解释。对于 SQL 包括 DDL 和表格初始化代码。对于包含最少代码的调试,您可以提供的代码是您显示的代码可以通过您显示的代码扩展为不正常。请不要插入 \"EDIT\"s/\"UPDATE\"s,只是让您的帖子成为编辑时最好的演示文稿。
-
源源不断的坏问题帖子并不能说明什么是好问题。也不是所有的问题都是好的 SO 问题。阅读链接。我试图帮助你改善这一点。祝你好运。
标签: javascript sql database database-design sequelize.js