使用Sequelize,NodeJS和AngularJS创建具有n:m关系的记录

时间:2016-06-23 14:41:32

标签: angularjs node.js sequelize.js

更新:我已经进一步发展了。请看帖子的底部......

我正在开发一个基于sql-fullstack yeoman生成器的项目,并且一直使用包含的示例代码作为指南。在大多数情况下,事情进展顺利,但我现在处于一个场景,我有两个表格/模型,双向n:m关系:

任务组:

module.exports = function(sequelize, DataTypes) {
  var TaskGroup = sequelize.define("TaskGroup", {
    taskGroupID: {
      field: "TaskGroupID",
      type: DataTypes.INTEGER,
      allowNull: false,
      unique: true,
      autoIncrement: true,
      primaryKey: true
    },
    name: {
      field: "Name",
      type: DataTypes.STRING,
      allowNull: false
    },
    description: {
      field: "Description",
      type: DataTypes.STRING
    },
    modifiedBy: {
      field: "ModifiedBy",
      type: DataTypes.STRING
    }
  });

和任务:

module.exports = function(sequelize, DataTypes) {
  var Task = sequelize.define("Task", {
    taskID: {
      field: "TaskID",
      type: DataTypes.INTEGER,
      allowNull: false,
      unique: true,
      autoIncrement: true,
      primaryKey: true
    },
    name: {
      field: "Name",
      type: DataTypes.STRING,
      allowNull: false
    },
    description: {
      field: "Description",
      type: DataTypes.STRING
    },
    isOnRunsheet: {
      field: "IsOnRunsheet",
      type: DataTypes.BOOLEAN
    },
    modifiedBy: {
      field: "ModifiedBy",
      type: DataTypes.STRING
    }
  });

关系:

  // Tasks can belong to more than one group, and groups can belong to more than one task
  db['TaskGroup'].belongsToMany(db['Task'], {as: 'Tasks', through: 'TaskGrouping'});
  db['Task'].belongsToMany(db['TaskGroup'], {as: 'TaskGroups', through: 'TaskGrouping'});

在客户端,用户可以创建新任务并通过多选列表指定关联的任务组。保存任务时,我同时拥有任务字段和关联任务组的数组。使用包含此信息的请求正文创建post,以便服务器可以创建任务记录。

不幸的是,我似乎无法获得创建的记录。我已经经历了多次迭代,而且我正处于一个看似合理的例外的地步 - 我只是难以理解“合理”的事情是......

例外:

Unhandled rejection SequelizeDatabaseError: Cannot insert the value NULL into column 'TaskTaskID', table 'HelpCard
.dbo.TaskGrouping'; column does not allow nulls. INSERT fails.
    at Query.formatError (C:\Projects\helpcard2\node_modules\sequelize\lib\dialects\mssql\query.js:215:10)
    at Request.userCallback (C:\Projects\helpcard2\node_modules\sequelize\lib\dialects\mssql\query.js:66:25)
    at Request.callback (C:\Projects\node_modules\tedious\lib\request.js:33:27)
    at Connection.message (C:\Projects\node_modules\tedious\lib\connection.js:1179:27)
    at Connection.dispatchEvent (C:\Projects\node_modules\tedious\lib\connection.js:519:45)
    at MessageIO.<anonymous> (C:\Projects\node_modules\tedious\lib\connection.js:439:23)
    at emitNone (events.js:67:13)
    at MessageIO.emit (events.js:166:7)
    at ReadablePacketStream.<anonymous> (C:\Projects\node_modules\tedious\lib\message-io.js:92:15)
    at emitOne (events.js:77:13)
...

以下是客户端的代码:

$scope.createTask = function() {
  if($scope.newTask === '') {
    return;
  }
  $scope.newTask.modifiedBy = 'tkturney';
  var taskBundle = {
      task: $scope.newTask,
      taskGroups: $scope.selectedGroups
  };
  $http.post('/api/tasks', taskBundle);
  setTimeout(function() {
    $scope.currentTask = $scope.newTask;
    $scope.newTask = '';
    $scope.addingTask = false;
    refreshTasks();
  }, 250);
};

......在服务器端:

exports.create = function(req, res) {
  var task = Task(req).build(req.body.task);
  task.setTaskGroups(req.body.taskGroups);
  task
    .save()
    .then(function() {
      return res.status(201).json(task);
    })
    .catch(function (err){
      if(err) { return handleError(res, err); }
    });
};

我确信我错过了一些明显的东西,但我发现的文档对于这样的场景非常清楚。我很感激任何指导;我刚刚进入续集状态,我觉得有时候我可能咬得比我咀嚼更多......:)

更新:在仔细研究SQL之后,我发现在尝试插入连接表(TaskGroupings)时会抛出异常。它试图为任务的主ID插入一个NULL,这通常不是一件好事。看看代码,我意识到我在保存记录之前尝试添加关联,让我没有PK。在task.addTaskGroups()处理该问题后移动save()

但是,我也意识到我正在将一个TaskGroup对象数组传递给'addTaskGroup()`调用,而不是实际的ID。所以,我修改了客户端控制器,如下所示:

$scope.createTask = function() {
  if($scope.newTask === '') {
    return;
  }
  $scope.groupKeys = [];
  angular.forEach($scope.selectedGroups, function(taskGroup) {
    $scope.groupKeys.push(taskGroup.taskGroupID);
  });
  $scope.newTask.modifiedBy = 'tkturney';
  var taskBundle = {
      task: $scope.newTask,
      taskGroups: $scope.groupKeys
  };
  $http.post('/api/tasks', taskBundle);
  ...

当我查看调试器时,我可以看到taskGroup对象中的所有内容,但taskGroup.taskGroupID将以undefined的形式返回,所以我仍然会收到异常,因为我我没有通过协会另一方的PK。

有什么事情可以解决这个代码片段的问题吗?

1 个答案:

答案 0 :(得分:2)

好的,通过更改服务器端控制器:

exports.create = function(req, res) {
  var task = Task(req).build(req.body.task);
  task.setTaskGroups(req.body.taskGroups);
  task
    .save()
    .then(function() {
      return res.status(201).json(task);
    })
    .catch(function (err){
      if(err) { return handleError(res, err); }
    });
};

对此:

exports.create = function(req, res) {
  var task = Task(req).build(req.body.task);
  task
    .save()
    .then(function() {
      task.setTaskGroups(req.body.taskGroups);
      return res.status(201).json(task);
    })
    .catch(function (err){
      if(err) { return handleError(res, err); }
    });
};

那个特殊的例外消失了。我失踪的东西(虽然它正盯着我看)是事实,有两个单独的插入发生 - 一个用于任务,一个用于关联。我以为我需要在保存任务之前设置关联,而不是意识到设置该关联会导致另一个插入。

我仍然需要弄清楚为什么协会另一方的PK没有被填充,但这超出了原始问题的范围......