【问题标题】:Sequelize create through associationSequelize 通过关联创建
【发布时间】:2017-07-21 02:27:26
【问题描述】:

我正在为两个类之间的关联创建一个方法。 sequelize 文档表明这可以使用包含一步完成

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});
});

我的模型关联是这样的

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

IntramuralAthlete.belongsTo(Person);

我登录时校内运动员的价值是

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

但我收到错误 notNull Violation: personId cannot be null。这个错误听起来像是我向 Sequelize 指示我打算在同一个调用中创建 personId 的方式有问题。

我向create 语句指示要与 IntramuralAthlete 创建哪些关联表的方式有问题吗?

谢谢!

编辑: 我也尝试过以下结构,结果相同

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

我的模型如下:

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'
  });
};

【问题讨论】:

    标签: node.js associations sequelize.js


    【解决方案1】:

    首先,当您将模型与 belongsTo 关联时,sequelize 会自动将目标模型主键添加为源模型中的外键。在大多数情况下,您不需要自己定义它,因此在您定义IntramuralAthlete.belongsTo(Person) sequelize 时,会将PersonId 添加为IntramuralAthlete 中的外键。您的 IntramuralAthlete 模型应如下所示:

    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
        }
     });
    };
    

    现在您可以像上面的代码一样创建intramuralAthlete。例如:

     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
    });
    

    请注意型号名称。 其次,我想您的 IntramuralAthlete 模型有多个 belongsTo 关联。只是您需要将它们定义为前一个关联,并且 sequelize 会将它们的主键作为外键添加到 IntramuralAthlete 模型中。

    第三,当你定义一个模型时,sequelize 会自动添加一个id 数据字段作为主键和自动增量,并添加createdAtupdatedAt 数据字段,默认值为CURRENT_TIMESTAMP,所以你不需要在你的模型中定义它们

    【讨论】:

      【解决方案2】:

      我想你的模型被命名为PersonIntramuralAthletesequelize.define 方法的第一个参数)。在这种情况下,当您创建像您这样的关联,并且不定义 as 属性时,您的 create 数据对象应如下所示

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

      如果您想改用person(就像在您的代码中一样),您应该稍微不同地定义关联

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

      然后,您必须像这样在optionsinclude 属性中的create 查询中执行一些更改

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

      EDIT:用空值personId欺骗save()方法

      如果你这样做,你可以维护allowNull: false

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

      EDIT 2:创建时禁用验证。

      这种情况假设验证已关闭。省略模型验证似乎是个坏主意,但是仍然维护数据库表级验证 - 在迁移中定义,它仍然可以检查是否设置了 personId

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

      在这种情况下,data 对象可以与您的示例一样 - 没有 personId 属性。我们省略了允许传递 null 值的模型级别验证,但是如果在 save() 方法期间它仍然是 null 值 - 数据库级别验证会抛出错误。

      【讨论】:

      • 你说的很有道理,但我尝试了对对象结构的建议更改(在我的问题中作为编辑包含在内),但失败并出现同样的错误。
      • 是的,这也可能发生。能否也添加IntramuralAthlete模型定义代码?
      • 按要求添加模型
      • 一开始我没有考虑到这一点——如果personId 没有allowNull: false 属性,我的答案会起作用。在这种情况下,我需要重新考虑。如果有有用的东西会告诉你的:)
      • 是的,就是这样。不是很高兴为了进行一次调用创建,您必须删除外键上的约束,但在我们的情况下,它比巨大的嵌套承诺链更好。感谢您的帮助。
      猜你喜欢
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-16
      • 1970-01-01
      相关资源
      最近更新 更多