首页 > 解决方案 > 由于带有 sequelize.js 的 UUID 外键,尝试将行插入表时出错

问题描述

我将 sequelize.js 与 node.js 和 postgres 一起使用。我从一个示例中得到了 2 个简单的表作为各种“POC”。我将 ID 更改为 UUID,并且在插入第二个表时遇到问题(使用 UUID FK )。

我正在使用邮递员对其进行测试。我正在使用 UUID 毫无问题地创建待办事项行,然后我正在尝试创建一个待办事项项,其中包含待办事项 id 作为外键,但似乎无法识别该 ID!

我在 postgres 中尝试了一个手动脚本并且它有效。我可能在代码方面遗漏了一些东西,但我不知道是什么。

这是邮递员返回给我的错误-

{
    "name": "SequelizeDatabaseError",
    "parent": {
        "name": "error",
        "length": 96,
        "severity": "ERROR",
        "code": "22P02",
        "file": "uuid.c",
        "line": "137",
        "routine": "string_to_uuid",
        "sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
    },
    "original": {
        "name": "error",
        "length": 96,
        "severity": "ERROR",
        "code": "22P02",
        "file": "uuid.c",
        "line": "137",
        "routine": "string_to_uuid",
        "sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
    },
    "sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
}

这是相关的js文件-

todoItems.js 控制器 -

const TodoItem = require('../dal/models').TodoItem;
const uuid = require('uuid/v4');

module.exports = {
  create(req, res) {
    return TodoItem
      .create({
        content: req.body.content,
        todoId: req.params.todoId,
      })
      .then(todoItem => res.status(201).send(todoItem))
      .catch(error => res.status(400).send(error));
  },

  update(req, res) {
    return TodoItem
      .find({
        where: {
          id: req.params.todoItemId,
          todoId: req.params.todoId,
        },
      })
      .then(todoItem => {
        if (!todoItem) {
          return res.status(404).send({
            message: 'TodoItem Not Found',
          });
        }

        return todoItem
          .update({
            content: req.body.content || todoItem.content,
            complete: req.body.complete || todoItem.complete,
          })
          .then(updatedTodoItem => res.status(200).send(updatedTodoItem))
          .catch(error => res.status(400).send(error));
      })
      .catch(error => res.status(400).send(error));
  },

  destroy(req, res) {
    return TodoItem
      .find({
        where: {
          id: req.params.todoItemId,
          todoId: req.params.todoId,
        },
      })
      .then(todoItem => {
        if (!todoItem) {
          return res.status(404).send({
            message: 'TodoItem Not Found',
          });
        }

        return todoItem
          .destroy()
          .then(() => res.status(204).send())
          .catch(error => res.status(400).send(error));
      })
      .catch(error => res.status(400).send(error));
  },
};

todos.js 控制器-

const Todo = require('../dal/models').Todo;
const TodoItem = require('../dal/models').TodoItem;

module.exports = {
  create(req, res) {
    return Todo
      .create({
        title: req.body.title,
      })
      .then((todo) => res.status(201).send(todo))
      .catch((error) => res.status(400).send(error));
  },

  list(req, res) {
    return Todo
      .findAll({
        include: [{
          model: TodoItem,
          as: 'todoItems',
        }],
        order: [
          ['createdAt', 'DESC'],
          [{ model: TodoItem, as: 'todoItems' }, 'createdAt', 'ASC'],
        ],
      })
      .then((todos) => res.status(200).send(todos))
      .catch((error) => res.status(400).send(error));
  },

  retrieve(req, res) {
    return Todo
      .findByPk(req.params.todoId, {
        include: [{
          model: TodoItem,
          as: 'todoItems',
        }],
      })
      .then((todo) => {
        if (!todo) {
          return res.status(404).send({
            message: 'Todo Not Found',
          });
        }
        return res.status(200).send(todo);
      })
      .catch((error) => res.status(400).send(error));
  },

  update(req, res) {
    return Todo
      .findByPk(req.params.todoId, {
        include: [{
          model: TodoItem,
          as: 'todoItems',
        }],
      })
      .then(todo => {
        if (!todo) {
          return res.status(404).send({
            message: 'Todo Not Found',
          });
        }
        return todo
          .update({
            title: req.body.title || todo.title,
          })
          .then(() => res.status(200).send(todo))
          .catch((error) => res.status(400).send(error));
      })
      .catch((error) => res.status(400).send(error));
  },

  destroy(req, res) {
    return Todo
      .findByPk(req.params.todoId)
      .then(todo => {
        if (!todo) {
          return res.status(400).send({
            message: 'Todo Not Found',
          });
        }
        return todo
          .destroy()
          .then(() => res.status(204).send())
          .catch((error) => res.status(400).send(error));
      })
      .catch((error) => res.status(400).send(error));
  },
};

待办事项表创建迁移 -

module.exports = {
  up: (queryInterface, Sequelize) =>
    queryInterface.createTable('Todos', {
      id: {
        allowNull: false,
        primaryKey: true,
        type: Sequelize.UUID,
      },
      title: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
    }),
  down: (queryInterface /* , Sequelize */) => queryInterface.dropTable('Todos'),
};

待办事项表创建迁移 -

module.exports = {
  up: (queryInterface, Sequelize) =>
    queryInterface.createTable('TodoItems', {
      id: {
        allowNull: false,
        primaryKey: true,
        type: Sequelize.UUID,
      },
      content: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      complete: {
        type: Sequelize.BOOLEAN,
        defaultValue: false,
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      todoId: {
        type: Sequelize.UUID,
        onDelete: 'CASCADE',
        references: {
          model: 'Todos',
          key: 'id',
          as: 'todoId',
        },
      },
    }),
  down: (queryInterface /* , Sequelize */) =>
    queryInterface.dropTable('TodoItems'),
};

待办事项模型 -

const uuid = require('uuid/v4');

'use strict';

module.exports = (sequelize, DataTypes) => {
  const Todo = sequelize.define('Todo', {
    title: {
      type: DataTypes.STRING,
      allowNull: false,
    }
  });
  Todo.associate = (models) => {
    Todo.hasMany(models.TodoItem, {
      foreignKey: 'todoId',
      as: 'todoItems',
    });
  };
  Todo.beforeCreate((item, _ ) => {
    return item.id = uuid();
  });
  return Todo;
};

待办事项模型 -

const uuid = require('uuid/v4');

'use strict';

module.exports = (sequelize, DataTypes) => {
  const TodoItem = sequelize.define('TodoItem', {
    content: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    complete: {
      type: DataTypes.BOOLEAN,
      defaultValue: false,
    }
  });
  TodoItem.associate = (models) => {
    TodoItem.belongsTo(models.Todo, {
      foreignKey: 'todoId',
      onDelete: 'CASCADE',
    });
  };
  TodoItem.beforeCreate((item, _ ) => {
    return item.id = uuid();
  });
  return TodoItem;
};

标签: node.jspostgresqlormsequelize.js

解决方案


你的路由器代码是什么样的?您是否为 todoId 使用正确的路径参数?例如,如果您使用的是快递。它应该看起来像app.post("/todos/:todoId/todo_items", todoItemController.create)。注意驼峰 todoId 。这将确保req.params.todoId您在 todoItems 控制器中引用的值具有正确的值。

此外,请确保您有正确的正文解析器来正确处理 req.body.content。在 express 中,这将通过 body-parser 库和app.use(bodyParser.json()). 在 todoItem 控制器创建代码中添加断点或日志语句并验证您是否确实具有正确的参数值。


推荐阅读