【问题标题】:Create with Include Sequelize使用 Include Sequelize 创建
【发布时间】:2018-09-24 12:19:28
【问题描述】:

最近我在 sequelize 文档中发现了this,您可以在其中使用包含进行创建。现在我试图在我的程序上做到这一点,但只创建“父”模型的记录,而不是为孩子创建的记录。

这是我的模型和控制器。

var MainMenu = sequelize.define('MainMenu', {
    Name: {
      type: DataTypes.STRING(50)      
    },
    Day: {
      type: DataTypes.DATE
    },
    RecordStatus:{
      type: DataTypes.BOOLEAN,
      defaultValue: true
    },    
    DeletedAt: {
      type: DataTypes.DATE
    }
  },
  {
    associate: function(models){
      models.MainMenu.hasMany(models.MainMeal, {as: 'Menu'});
    }
  }
);

exports.createIn = (req, res) => {

 let Menu = {
   Name: 'MenuTest',
   MainMeal: [{
     Type: 'Breakfast',
     Name: 'MealTest1'
   }, {
     Type: 'Lunch',
     Name: 'MealTest2'
   }]
 };

  db.MainMenu.create(Menu, {
    include: [{
      model: db.MainMeal,
      as: 'Menu'
    }]
  })
    .then( mainmenu => {
      if (!mainmenu) {
        return res.send('users/signup', {
          errors: 'Error al registrar el mainmenu.'
        });
      } else {
        return res.jsonp(mainmenu);
      }
    })
    .catch( err => {
      console.log(err);
      return res.status(400)
        .send({
          message: errorHandler.getErrorMessage(err)
        });
    });
};

在我的情况下,它只创建 MainMenu 记录而不是 MainMeal 记录。我做错了什么?

【问题讨论】:

    标签: javascript node.js sequelize.js


    【解决方案1】:

    更改您的 menu 对象,并包含 Menu 数组而不是 MainMeal

    • 您必须在对象中提供别名
    let mainMenu = {
       Name: 'MenuTest',
       Menu: [{
         Type: 'Breakfast',
         Name: 'MealTest1'
       }, {
         Type: 'Lunch',
         Name: 'MealTest2'
       }]
     };
    

    现在,

    db.MainMenu.create(mainMenu, {
        include: [{
          model: db.MainMeal,
          as: 'Menu'
        }]
      })
        .then( mainmenu => {
          if (!mainmenu) {
            return res.send('users/signup', {
              errors: 'Error al registrar el mainmenu.'
            });
          } else {
            return res.jsonp(mainmenu);
          }
        })
        .catch( err => {
          console.log(err);
          return res.status(400)
            .send({
              message: errorHandler.getErrorMessage(err)
            });
        });
    

    【讨论】:

    • 天哪!哈哈哈有趣的是变量名是如何工作的。谢谢。
    • 现在利用您的回答,如果我想在 MainMenu 中做第二个Include,首先可以吗?我只是在Menu 中添加对象或数组吗?
    【解决方案2】:

    最主要的当然是Menu 的命名应该在传递给.create() 本身的数据中,以及那里提供的参数和如果你真的需要指定别名“两次”,你没有。但是还有一些其他的事情需要注意。

    我个人更喜欢将关联存储为它自己的导出并将其包含在语句中。当您稍后了解该关联的用法时,这通常会变得更加清晰。

    我还强烈建议,当您跨多个表“编写”内容时,请实施 transactions 以确保实际创建所有相关项目,并且在出现任何错误时不会被孤立。

    作为基于示例的简要列表:

    const Sequelize = require('sequelize');
    
    const sequelize = new Sequelize('sqlite:menu.db',{ logging: console.log });
    
    const MainMeal = sequelize.define('MainMeal', {
      Type: { type: Sequelize.STRING(50) },
      Name: { type: Sequelize.STRING(50) }
    });
    
    const MainMenu = sequelize.define('MainMenu', {
      Name: { type: Sequelize.STRING(50) }
    });
    
    MainMenu.Meals = MainMenu.hasMany(MainMeal, { as: 'Menu' });
    
    (async function() {
    
      try {
    
        await sequelize.authenticate();
        await MainMeal.sync({ force: true });
        await MainMenu.sync({ force: true });
    
        let result = await sequelize.transaction(transaction => 
          MainMenu.create({
            Name: 'MenuTest',
            Menu: [
              { Type: 'Breakfast', Name: 'MealTest1' },
              { Type: 'Lunch', Name: 'MealTest2' }
            ]
          },{
            include: MainMenu.Meals,
            transaction
          })
        );
    
      } catch(e) {
        console.error(e);
      } finally {
        process.exit();
      }
    })();
    

    会输出如下内容:

    Executing (default): SELECT 1+1 AS result
    Executing (default): DROP TABLE IF EXISTS `MainMeals`;
    Executing (default): CREATE TABLE IF NOT EXISTS `MainMeals` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `Type` VARCHAR(50), `Name` VARCHAR(50), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `MainMenuId` INTEGER REFERENCES `MainMenus` (`id`) ON DELETE
    SET NULL ON UPDATE CASCADE);
    Executing (default): PRAGMA INDEX_LIST(`MainMeals`)
    Executing (default): DROP TABLE IF EXISTS `MainMenus`;
    Executing (default): CREATE TABLE IF NOT EXISTS `MainMenus` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `Name` VARCHAR(50), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL);
    Executing (default): PRAGMA INDEX_LIST(`MainMenus`)
    Executing (3d645847-56ca-435a-b786-6be62a05e8d5): BEGIN DEFERRED TRANSACTION;
    Executing (3d645847-56ca-435a-b786-6be62a05e8d5): INSERT INTO `MainMenus` (`id`,`Name`,`createdAt`,`updatedAt`) VALUES (NULL,'MenuTest','2018-04-14 08:08:17.132 +00:00','2018-04-14 08:08:17.132 +00:00');
    Executing (3d645847-56ca-435a-b786-6be62a05e8d5): INSERT INTO `MainMeals` (`id`,`Type`,`Name`,`createdAt`,`updatedAt`,`MainMenuId`)
    VALUES (NULL,'Breakfast','MealTest1','2018-04-14 08:08:17.152 +00:00','2018-04-14 08:08:17.152 +00:00',1);
    Executing (3d645847-56ca-435a-b786-6be62a05e8d5): INSERT INTO `MainMeals` (`id`,`Type`,`Name`,`createdAt`,`updatedAt`,`MainMenuId`)
    VALUES (NULL,'Lunch','MealTest2','2018-04-14 08:08:17.153 +00:00','2018-04-14 08:08:17.153 +00:00',1);
    Executing (3d645847-56ca-435a-b786-6be62a05e8d5): COMMIT;
    

    重要的部分是事务BEGINCOMMIT 在创建数据时包装所有这些INSERT 语句。即使没有实现事务,您仍然会看到这两个项目与相关的“父项”一起创建。但争论的重点是这是您“应该”实施交易的地方。

    另请注意,用于数据创建和后续访问的"aliased" Menu 实际上并不是“必需”包含在include 选项的.create() 方法中。它是“可选的”,并且已经在 .hasMany() 参数下定义,所以你真的不需要再做一次了。

    即使你这样做了,那么该部分仍然是与 model 参数一起使用的“关联”:

    {
      include: {
        model: MainMenu.Meals,
        as: 'Menu'
      },
      transaction
    }
    

    所以不要将其与引用的“表”模型的原始名称混淆,这也可能是另一个混​​淆点。

    【讨论】:

    • 我把答案告诉了另一个人,因为它只需要一个简单的改变就可以满足我的需求。但我会通过交易尝试您的解决方案。感谢您的所有解释。
    猜你喜欢
    • 2016-02-05
    • 2019-03-19
    • 2020-12-13
    • 1970-01-01
    • 2019-10-24
    • 2020-09-05
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多