问题
I'm developing a simple API using MySQL and Node for the backend and Sequelize to handle the database operations. The user has to be able to generate time intervals according to a template, which will specify the starting hour, the finishing hour and the duration of each interval in minutes. For that, I've created 2 tables: TEMPLATE and TEMPLATE_HOURS which have a 1:M relationship. Graphically:
I'd like to avoid raw SQL queries as much as possible, and I'd like to know if there's a way to create a template and its time intervals using Sequelize methods. It's really easy to create a template, but I don't know how to create and assign its intervals at once. This is the code I have so far:
const Template = db.Template;
db.sequelize.transaction()
  .then((transaction) => {
    Template.create({ 
      name: req.body.name,
      hour_start: req.body.hour_start,
      hour_end: req.body.hour_end,
      interval_duration: req.body.interval_duration
    }, { transaction })
    .then((template) => {
      // The template has been created
      // This method generates an array with all the time intervals. F.i. [ '08:00', '08:30', '09:30', etc... ]
      var templateHours = generateTemplateHours(req.body.hour_start, req.body.hour_end, req.interval_duration);
      // <<<<<<< ??????
      // How could I create the time intervals and assign them to the newly created template??
      // <<<<<<< ??????
      // If everyting goes fine, do a transaction.commit()
    }).catch((error) => {
      // Error creating the template
      transaction.rollback();
      res.status(500).json(new ApiResponse(false, 'Something went wrong', error));
    });
  });
Thanks in advance,
回答1:
Assuming TemplateHours is defined as a model and the Template model has an "hasMany" association to it with the alias TemplateHours. You can use the "createTemplateHours" function which will be defined on the prototype of Template.
This will create an instance of TemplateHours and associate it to the instance of Template. Since you provided no information on which properties the model TemplateHours has I just assumed the property is called "hour_property"
const Template = db.Template;
const TemplateHours = db.TemplateHours;
db.sequelize.transaction()
.then(function(transaction)
{
    return Template.create({
      name: req.body.name,
      hour_start: req.body.hour_start,
      hour_end: req.body.hour_end,
      interval_duration: req.body.interval_duration
    }, {
        transaction: transaction
    })
    .then(function(template)
    {
        var templateHours = generateTemplateHours(req.body.hour_start, req.body.hour_end, req.interval_duration);
        return Promise.all(templateHours.map(function(templateHour)
        {
            return template.createTemplateHours({
                hour_property: templateHour
            }, {transaction: transaction});
        }));
    })
    .then(function()
    {
        transaction.commit();
        // res.status etc.
    })
    .catch(function(error)
    {
        transaction.rollback();
        // res.status etc.
    });
});
    回答2:
Updated
SOLUTION 1
I just found that bulkCreate allows to insert multiple child records in a very simple way, and it generates them in only one INSERT statement, which is what I was looking for (thanks to @tim-nilsson for noting this new feature):
    const Template = db.Template;
    const TemplateHour = db.TemplateHour;
    var templateHours = generateTemplateHours(req.body.hour_start, req.body.hour_end, req.body.interval_duration);
    Template.bulkCreate([{ 
      name: req.body.name,
      hour_start: req.body.hour_start,
      hour_end: req.body.hour_end,
      interval_duration: req.body.interval_duration,
      TemplateHours: templateHours
    }], { include: { model: TemplateHour } })
    .then((data) => {
      // All inserted OK
      res.status(200).json(new ApiResponse(true, 'Template created successfully'));
    })
    .catch((error) => {
        res.status(500).json(new ApiResponse(false, 'Error creating a new template', error));
    });
SOLUTION 2
Another solution, this time using transactions and bulkCreate on the template hours:
  const Template = db.Template;
  const TemplateHour = db.TemplateHour; 
  db.sequelize.transaction()
    .then(transaction => {
      // 1. Create the template
      Template.create({ 
        name: req.body.name,
        hour_start: req.body.hour_start,
        hour_end: req.body.hour_end,
        interval_duration: req.body.interval_duration,
      }, { transaction })
        .then((template) => {
          // 2. Insert all the template hours using bulkCreate
          var tid = template.id;    // Get the id of the newly created template
          // templateHours is an array: [{ hour: "08:00", TemplateId: tid }, { hour: "08:30", TemplateId: tid }, ...]
          var templateHours = generateTemplateHours(req.body.hour_start, req.body.hour_end, req.body.interval_duration, tid);
          return TemplateHour.bulkCreate(templateHours, { transaction });
        })
        .then((data) => {
          // 3. Both template and hours are created successfully, commit the transaction
          return transaction.commit();
        })
        .then(() => {
          // 4. commit OK
          res.status(200).json(new ApiResponse(true, 'Template created successfully'));
        })
        .catch((error) => {
          // Error during the process
          transaction.rollback(); // Rollback the transaction
          res.status(500).json(new ApiResponse(false, 'Error creating a new template', error));
        });
    })
    .catch(error => {
      // Transaction error
      res.status(500).json(new ApiResponse(false, 'Error starting a database transaction', error));
    });
    来源:https://stackoverflow.com/questions/57609269/using-sequelize-with-1m-associations