【问题标题】:SequelizeForeignKeyConstraintError on nested findOrCreate inside a loop循环内嵌套 findOrCreate 上的 SequelizeForeignKeyConstraintError
【发布时间】:2018-04-24 07:22:19
【问题描述】:

我正在尝试使用 mysql 的 sequelize 在 2 个相关表上插入多行。

基于sequelize transaction cannot insert because of foreign key?,我尝试创建一个事务,如果我只执行一次承诺,它似乎可以工作,但如果我在显示外键问题的循环上执行代码,它会失败。

代码如下:

const config = {
    "username": "root",
    "password": "",
    "database": "sequelize_test",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "pool": {
        "max": 1,
        "min": 0,
        "idle": 20000,
        "acquire": 20000
    }
};

const Sequelize = require('sequelize')
const sequelize = new Sequelize(config.database, config.username, config.password, config)

const Project = sequelize.define('projects', {
    id: {
        type: Sequelize.INTEGER,
        allowNull: false,
        autoIncrement: true,
        primaryKey: true
    },
    authorId: {
        type: Sequelize.INTEGER
    },
    name: {
        type: Sequelize.STRING
    }
})

const Author = sequelize.define('authors', {
    id: {
        type: Sequelize.INTEGER,
        allowNull: false,
        autoIncrement: true,
        primaryKey: true
    },
    name: {
        type: Sequelize.STRING,
    }
})

Author.hasMany(Project, {
    foreignKey: 'authorId',
    sourceKey: 'id'
})
Project.belongsTo(Author, {
    foreignKey: 'id'
})

sequelize
    .sync({
        force: true
    })
    .then(() => {

        var projectAuthors = [{
            projectName: "Proj 1",
            authorName: "Author 1"
        }, {
            projectName: "Proj 2",
            authorName: "Author 1"
        }, {
            projectName: "Proj 3",
            authorName: "Author 1"
        }, {
            projectName: "Proj 4",
            authorName: "Author 2"
        }, {
            projectName: "Proj 5",
            authorName: "Author 3"
        }];

        //Insert all the records on the array
        projectAuthors.forEach(function(project) {

            sequelize
                .transaction(function(t) {
                    //First insert the author
                    return Author.findOrCreate({
                        where: {
                            name: project.authorName
                        },
                        transaction: t

                    }).spread(function(author) {
                        //With the id obtained on the previous step, insert the project
                        return Project.findOrCreate({
                            where: {
                                name: project.projectName,
                                authorId: author.id
                            },
                            transaction: t
                        });
                    })

                });

        });
    });

编辑

根据 Ellebkey 的建议,这是我使用 include 的控制器。

sequelize
.sync({
    force: true
})
.then(() => {

    var projectAuthors = [{
        projectName: "Proj 1",
        authorName: "Author 1"
    }, {
        projectName: "Proj 2",
        authorName: "Author 1"
    }, {
        projectName: "Proj 3",
        authorName: "Author 1"
    }, {
        projectName: "Proj 4",
        authorName: "Author 2"
    }, {
        projectName: "Proj 5",
        authorName: "Author 3"
    }];

    //Insert all the records on the array
    projectAuthors.forEach(function(project) {

        sequelize
            .transaction(function(t) {
                //First insert the author
                return Project.findOrCreate({
                    where: {
                        name: project.projectName,
                        author: {
                            name: project.authorName
                        }
                    },
                    include: [{
                        association: Project.Author,
                    }],
                    transaction: t
                });

            });
    });
});

它确实失败了:

无效值 { name: 'Author 3' }

Edit 2(表格创建工作)

感谢 Ellebkey 和一些人的建议,我的模型如下所示:

const Project = sequelize.define('projects', {
    name: {
        type: Sequelize.STRING
    }
});

const Author = sequelize.define('authors', {
    name: {
        type: Sequelize.STRING,
    }
});

Project.belongsTo(Author, { as: 'Author', foreignKey : 'authorId'});
Author.hasMany(Project, { as: 'Author', foreignKey : 'authorId'});

但是使用答案中的 create() 代码,我仍然得到这个:

未处理的拒绝错误:无效值{名称:未定义}

顺便说一句,我正在使用 sequelize 4.37.6

提前致谢

【问题讨论】:

  • 您可以在create 上使用include here 是文档。
  • 感谢您的回答。我检查了包含,但似乎无法使其与 findOrCreate() 一起使用,我得到:无效值 { 名称:'作者 3'} 问题似乎与此有关:stackoverflow.com/questions/45530818/…
  • 你能更新你的新控制器吗?
  • 我刚刚用新控制器更新了我的问题

标签: javascript node.js promise sequelize.js


【解决方案1】:

首先,根据我的经验,不建议将foreignKey 用于关联,这会让人感到困惑。改用as,而且你不需要为每个模型创建id,sequelize为你做。

const Project = sequelize.define('projects', {
    name: {
        type: Sequelize.STRING
    }
})

现在,回到关联,这将在您的 Project 表上创建一个 AuthorId

Project.belongsTo(Author, { as: 'Author'})

const Author = sequelize.define('authors', {
    name: {
        type: Sequelize.STRING,
    }
})

Author.hasMany(Project, { as: 'Author'})


sequelize
    .sync({
        force: true
    })
    .then(() => {

最后,对于您的createinclude,您必须根据之前声明的方式创建对象。想一想,你会用Find 做它,你会得到你的AuthorProjects,所以每个对象应该是这样的:

        var projectAuthors = [{
            name: "Author 1",
            //This must have the same syntax as you declared on your asociation
            Author: [{
                name: "Proj 1"
            },{
                name: "Proj 2"
            }]
        },{
            name: "Author 2",
            Author: [{
                name: "Proj 3"
            },{
                name: "Proj 4"
            }]
        },];

        projectAuthors.forEach(function(project) {

        sequelize
            .transaction(function(t) {
                //First insert the author
                return Author.findOrCreate({
                    where: {
                        //check this I'm not sure
                        name: project.name, //this is the Author name
                    },
                    include: [{
                        model: Project,
                        as: 'Author'
                    }],
                    transaction: t
                });

            });
        });
    });

您遇到的错误是因为您从未在模型上声明 authorName

【讨论】:

  • 非常感谢对模型上的id和外键列进行编辑的建议!它使实体定义更简单......但是,当我更改 belongsTo() 和 hasMany 子句时,该示例引发以下错误: equelizeDatabaseError: Duplicate column name 'authorId' (我先删除了以前的表) 显然查询试图两次创建同一列...我将更新问题。
  • 然后只需更改 as 关联上的 as 名称即可。它将保留 belongsTo 名称。
  • 更正,我想我设法修复了表的创建,但插入仍然失败。我会更新问题
  • 哦,我明白了,我没有更改 where 上的变量,记住我们更改了对象,所以 project. projectName 不存在。现在对于重复的项目,我不太确定该怎么做。
猜你喜欢
  • 1970-01-01
  • 2021-05-30
  • 1970-01-01
  • 1970-01-01
  • 2019-03-08
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 2020-09-17
相关资源
最近更新 更多