简体   繁体   中英

Sequelize create through association

I'm working on a create method for an association between two classes. The sequelize documentation indicates that this can be done in one step using includes

IntramuralAthlete.create(intramuralAthlete,{
         include: [Person]
    }).then((data,err)=>{
         if(data)res.json(data);
         else res.status(422).json(err);
    }).catch(function(error) {
         res.status(422).json({message: "failed to create athlete", error: error.message});
});

My model association looks like this

var Person = require('../models').person;
var IntramuralAthlete = require('../models').intramuralAthlete;

IntramuralAthlete.belongsTo(Person);

And the value of intramural athlete when I log it is

{ 
   person: 
   { firstName: 'Test',
     lastName: 'User',
     email: 'test@user.com'
  },
  grade: '12th',
  organizationId: 1 
}

But I get the error notNull Violation: personId cannot be null . This error makes it sound like something is wrong with the way I'm indicating to Sequelize that I'm intending to create the personId in that same call.

Is there something wrong in the way I indicate to the create statement what associated tables to create with the IntramuralAthlete?

Thanks!

EDIT: I have also tried with the following structure with the same result

{ 
  Person: { 
    firstName: 'Test',
    lastName: 'User',
    email: 'test@user.com'
 },
 grade: '12th',
 organizationId: 1 
}

My model is as follows:

module.exports = function(sequelize, DataTypes) {
  return sequelize.define('intramuralAthlete', {
    id: {
      type: DataTypes.INTEGER(11),
      allowNull: false,
      primaryKey: true,
      autoIncrement: true
    },
    createdAt: {
      type: DataTypes.DATE,
      allowNull: false,
      defaultValue: sequelize.literal('CURRENT_TIMESTAMP')
    },
    updatedAt: {
      type: DataTypes.DATE,
      allowNull: false,
      defaultValue: sequelize.literal('CURRENT_TIMESTAMP')
    },
    grade: {
      type: DataTypes.STRING,
      allowNull: true
    },
    age: {
      type: DataTypes.INTEGER(11),
      allowNull: true
    },
    school: {
      type: DataTypes.STRING,
      allowNull: true
    },
    notes: {
      type: DataTypes.STRING,
      allowNull: true
    },
    guardianId: {
      type: DataTypes.INTEGER(11),
      allowNull: true,
      references: {
        model: 'contact',
        key: 'id'
      }
    },
    personId: {
      type: DataTypes.INTEGER(11),
      allowNull: false,
      references: {
        model: 'person',
        key: 'id'
      }
    },
    mobileAthleteId: {
      type: DataTypes.INTEGER(11),
      allowNull: true,
      references: {
        model: 'mobileAthlete',
        key: 'id'
      }
    },
    organizationId: {
      type: DataTypes.INTEGER(11),
      allowNull: false,
      references: {
        model: 'organization',
        key: 'id'
      }
    }
  }, {
    tableName: 'intramuralAthlete'
  });
};

I suppose that your models are named Person and IntramuralAthlete (first arguments of sequelize.define method). In this case, when you create an association like yours, and do not define the as attribute, your create data object should look as follows

{
    Person: {
        firstName: 'Test',
        lastName: 'User',
        email: 'test@user.com'
    },
    grade: '12th',
    organizationId: 1 
}

If you want to use person instead (just as in your code), you should define the association a little bit differently

IntramuralAthlete.belongsTo(Person, { as: 'person' });

Then, you would have to perform some changes in the create query in the include attribute of the options like this

IntramuralAthlete.create(data, {
    include: [
        { model: Person, as: 'person' }
    ]
}).then((result) => {
    // both instances should be created now
});

EDIT : Trick the save() method with empty value of personId

You can maintain the allowNull: false if you do something like that

{
    person: {
        // person data
    },
    personId: '', // whatever value - empty string, empty object etc.
    grade: '12th',
    organizationId: 1
}

EDIT 2 : Disable validation when creating.

This case assumes that the validation is turned off. It seems like a bad idea to omit model validation, however there still maintains the database table level validation - defined in migrations, where it can still check if personId value was set

IntramuralAthlete.create(data, {
    include: [
        { model: Person, as: 'person' }
    ],
    validate: false
}).then((result) => {
    // both instances should be created now
});

In this case the data object can be as in your example - without the personId attribute. We omit the model level validation which allows to pass null value, however if during the save() method it would still be null value - database level validation would throw an error.

first of all, when you associatea a model with belongsTo , sequelize will add automatically the target model primary key as a foreign key in the source model. in most of cases you don't need to define it by yourself, so in your case when you define IntramuralAthlete.belongsTo(Person) sequelize adds PersonId as a foreign key in IntramuralAthlete . your IntramuralAthlete model should looks like:

module.exports = function(sequelize, DataTypes) {
  return sequelize.define('intramuralAthlete', {
    grade: {
      type: DataTypes.STRING,
      allowNull: true
    },
    age: {
      type: DataTypes.INTEGER(11),
      allowNull: true
    },
    school: {
      type: DataTypes.STRING,
      allowNull: true
    },
    notes: {
      type: DataTypes.STRING,
      allowNull: true
    }
 });
};

now you can create an intramuralAthlete like your code above. for example:

 let data = {
   Person: {
     firstName: 'Test',
     lastName: 'User',
     email: 'test@user.com'
   },
   grade: '12th',
   notes: 'test notes'
 }
IntramuralAthlete.create(data, {include: [Person]}).then((result) => {
// both instances should be created now
});

be carefull with the model name. second I suppose that your IntramuralAthlete model has more than one belongsTo association. just you need to define them as the previous one association and sequelize will add their primary keys as foreign keys in the IntramuralAthlete model.

third, when you define a model, sequelize adds automatically an id datafield as a primary key and autoincrement and also adds createdAt and updatedAt datafields with a default CURRENT_TIMESTAMP value, so you don't need to define them in your model

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM