【问题标题】:Sequelize - Association Many to Many - 3 Foreign KeysSequelize - 多对多关联 - 3 个外键
【发布时间】:2020-03-05 19:30:06
【问题描述】:

我正在寻求有关在 Sequelize 模型中正确定义具有 3 个外键的关联表的帮助:

情况:我正在构建一个电子邮件客户端,这个问题的相关模型是:

  • 用户模型(用户记录)
  • 线程模型(每个新电子邮件线程的线程记录)
  • 文件夹模型(默认文件夹的文件夹,例如收件箱、已发送等和自定义文件夹)
  • ThreadFolder 模型(关联链接特定的 a)User 模型,到特定的 b)Thread 模型,到特定的 c)文件夹 型号)

问题:我的问题是关联模型/表(ThreadFolder),我无法为 ThreadFolder 关联模型中的所有 3 个表创建关联。


第一次尝试我能够创建与 Sequelize 的关联,允许 ThreadFolder 模型为上述三个模型中的 2 个创建外键,但不是全部 3 个。这是该关联:

Thread.belongsToMany(Folder, { through: ThreadFolder, foreignKey: 'thread_id', otherKey: 'folder_id' })
Folder.belongsToMany(Thread, { through: ThreadFolder, foreignKey: 'folder_id', otherKey: 'thread_id' })

SQL 输入尝试:

  1. user_id: 1 |线程 ID:1 |文件夹ID:1 |成功插入
  2. user_id: 1 |线程 ID:1 |文件夹ID:2 |成功插入
  3. user_id: 1 | thread_id:2 |文件夹ID:1 |插入失败 -- 下方错误...
  4. user_id: 2 |线程 ID:1 |文件夹ID:1 |成功插入
  5. user_id: 2 |线程 ID:1 |文件夹ID:2 |成功插入

第一次尝试的错误:

Executing:
INSERT INTO `iwantmail-core`.`thread_folders` (`user_id`, `deleted`, `archived`, `created_at`, `updated_at`, `thread_id`, `folder_id`) VALUES ('1', '0', '0', '2020-03-05 23:34:16', '2020-03-05 23:34:16', '30', '1');

Operation failed: There was an error while applying the SQL script to the database.
ERROR 1062: 1062: Duplicate entry '30-1' for key 'PRIMARY'
SQL Statement:
INSERT INTO `iwantmail-core`.`thread_folders` (`user_id`, `deleted`, `archived`, `created_at`, `updated_at`, `thread_id`, `folder_id`) VALUES ('1', '0', '0', '2020-03-05 23:34:16', '2020-03-05 23:34:16', '30', '1')

第二次尝试我可以指定如下所示的关联,以允许我添加具有不同 user_id 和 folder_id 的记录,但是,如果我使用不同的 thread_id,我会收到如下所示的错误。

Folder.hasMany(ThreadFolder, { foreignKey: 'folder_id' })
ThreadFolder.belongsTo(Folder, { foreignKey: 'folder_id' })
Thread.belongsToMany(Folder, { through: ThreadFolder })

Thread.hasMany(ThreadFolder, { foreignKey: 'thread_id' })
ThreadFolder.belongsTo(Thread, { foreignKey: 'thread_id' })

User.hasMany(ThreadFolder, { foreignKey: 'user_id' })
ThreadFolder.belongsTo(User, { foreignKey: 'user_id' })
Folder.belongsToMany(User, { through: ThreadFolder })

SQL 输入尝试:

  1. user_id: 1 |线程 ID:1 |文件夹ID:1 |成功插入
  2. user_id: 1 |线程 ID:1 |文件夹ID:2 |成功插入
  3. user_id: 1 | thread_id:2 |文件夹ID:1 |插入失败 -- 下方错误...
  4. user_id: 2 |线程 ID:1 |文件夹ID:1 |成功插入
  5. user_id: 2 |线程 ID:1 |文件夹ID:2 |成功插入

第二次尝试的错误

Operation failed: There was an error while applying the SQL script to the database.
ERROR 1062: 1062: Duplicate entry '1-1' for key 'PRIMARY'
SQL Statement:
INSERT INTO `mail-core`.`thread_folders` (`user_id`, `thread_id`, `folder_id`) VALUES ('1', '2', '1')

请注意,我基本上是在尝试指出 Thread#1 的 User#1 在 Folder#1 中,一旦我尝试指出 Thread#2 的 User#1 在 Folder#1 中,就会出现上述错误发生。


帮助:

  • 有人可以为我指明正确的方向/展示如何编写关联以考虑到第三个关联吗?
  • 是否有不同的方法来编写此关联,以便在关联表中考虑所有 3 个外键?

提前感谢您的任何帮助/协助!

(使用的相关技术:MySQL、MySQL Workbench、Node 12.x、TypeScript、Serverless Framework)

编辑:对帖子进行了编辑,第二次尝试作为部分解决方案提供,经过进一步测试,当第二个用户添加到关联表 ThreadFolder 中的同一线程和文件夹时,第一次和第二次尝试均失败。

【问题讨论】:

  • 能否请您发布 Sequelize 使用 Sequelize.sync({ force: true }) 生成的创建语句
  • @SohamLawar 如果不存在则创建表 thread_folders (user_id INTEGER, deleted TINYINT(1) 默认为 false,archivedTINYINT(1) 默认为 false,created_at DATETIME NOT NULL , updated_at DATETIME NOT NULL, thread_id INTEGER , folder_id INTEGER , 主键 (thread_id, folder_id), 外键 (thread_id) 参考threads (@98766543) UPDATE CASCADE, FOREIGN KEY (folder_id) REFERENCES folders (id) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB;

标签: mysql sequelize.js many-to-many associations


【解决方案1】:

查看您的 create 语句后,我认为您已经正确定义了关联 thread_folders。在我看来,您定义关联的第二次尝试是正确的。

您在插入记录时遇到错误,因为您的主键是 thread_idfolder_id 这两个属性的组合键。假设在您的thread_folders 表中已经有thread_id 1 和folder_id 1 的记录,那么您不能插入另一条带有thread_id 1 和folder_id 1 的记录。

如果您删除thread_idfolder_id 的组合主键,那么您将能够在thread_folders 表中插入要插入的记录。

希望对你有帮助!

【讨论】:

  • 谢谢@Soham,我不确定如何从关联中获取主键,我尝试使用primaryKey:false。也就是说,我确实采取了第二条路线,经过更多的尝试和错误,我找到了解决方案,我很快就会在这里发布,非常感谢!
  • @Speros,欢迎您。很高兴知道您找到了解决方案。
【解决方案2】:

工作解决方案最终成为第二次尝试的变体:

User.hasMany(ThreadFolder, { foreignKey: 'user_id' })
ThreadFolder.belongsTo(User, { foreignKey: 'user_id' })

Folder.hasMany(ThreadFolder, { foreignKey: 'folder_id' })
ThreadFolder.belongsTo(Folder, { foreignKey: 'folder_id' })

Thread.hasMany(ThreadFolder, { foreignKey: 'thread_id' })
ThreadFolder.belongsTo(Thread, { foreignKey: 'thread_id' })

我的大多数模型调用(基于它们之前的编写方式)最终都会更改为首先从关联表开始,例如

 ThreadFolder.findAll({
        where: {
            user_id: 1,
            folder_id: 1,
        },
        include: [
            {
                model: Thread,
                include: [
                    'recipient',
                    'sender'
                ]
            }
        ]
    })

希望这有助于其他尝试创建超过 2 个外键的多外键关联表的人,推测这种方法应该适用于关联表中任意数量的外键。

【讨论】:

    猜你喜欢
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-02
    • 2018-08-21
    • 1970-01-01
    相关资源
    最近更新 更多