属性 不应该存在的非空验证错误
Not null validation error on a property that shouldn't exist
我正在为使用 Sequelize 的节点服务器编写单元测试。插入一些虚假数据后,我收到错误
SequelizeValidationError: notNull Violation: QuestionId cannot be null
注意大小写:QuestionId
上的大写 Q
单元测试:
describe('answerQuestion', () => {
it('should insert an answer and get the next question', (done) => {
Survey.DBModel.create({lookType: 0}, {logging: false}).then(() => {
Question.DBModel.create({type: 0, text: 'Test question'}, {logging: false}).then(q1 => {
Question.DBModel.create({type: 1, text: 'Next question'}, {logging: false}).then(q2 => {
console.log('before');
QuestionOption.DBModel.create({text: 'Test option', questionId: 1, nextQuestionId: 2}, {logging: false}).then(() => {
console.log('after');
Survey.answerQuestion(1, 1, 1).then(question => {
question.should.have.property('id');
}, done);
}, done);
}, done);
}, done);
}, done);
});
});
控制台输出'before'但在到达'after'之前出错
question.js
'use strict';
module.exports = function(sequelize, DataTypes) {
var Question = sequelize.define('Question', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
type: {
allowNull: false,
type: DataTypes.INTEGER
},
text: {
allowNull: false,
type: DataTypes.STRING
},
nextQuestionId: {
type: DataTypes.INTEGER
}
}, {
classMethods: {
associate: function(models) {
models.Question.belongsTo(models.Question, {as: 'nextQuestion', foreignKey: {field: 'nextQuestionId', allowNull: true}});
models.Question.hasMany(models.Answer, {as: 'answers', foreignKey: {field: 'questionId', allowNull: false}});
models.Question.hasMany(models.QuestionOption, {as: 'options', foreignKey: {field: 'questionId', allowNull: false}});
models.Question.hasMany(models.QuestionOption, {as: 'referrers', foreignKey: {field: 'nextQuestionId', allowNull: true}});
}
}
});
return Question;
};
questionoption.js
'use strict';
module.exports = function(sequelize, DataTypes) {
var QuestionOption = sequelize.define('QuestionOption', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
questionId: {
allowNull: false,
type: DataTypes.INTEGER
},
text: {
allowNull: false,
type: DataTypes.STRING
},
nextQuestionId: {
type: DataTypes.INTEGER
}
}, {
classMethods: {
associate: function(models) {
models.QuestionOption.belongsTo(models.Question, {as: 'question', foreignKey: {field: 'questionId', allowNull: false}});
models.QuestionOption.belongsTo(models.Question, {as: 'nextQuestion', foreignKey: {field: 'nextQuestionId', allowNull: true}});
}
}
});
return QuestionOption;
};
这些模型非常紧密地耦合在一起,并且具有自引用连接和各种其他混乱。其他模型我觉得都与此无关,但如果需要可以提供。
直接在 SQLite 数据库上执行 SQL,以与上面的创建语句相同的顺序和相同的属性不会抛出异常,并且通过大量测试很明显Sequelize 不会尝试 运行 QuestionOption
的创建语句。它在将 SQL 生成为 运行.
之前出错
一些奇怪的行为是关联在模型中被精心定义,并且所有关联在其定义中都有 小写 q
for questionId
.所有关联也都定义了反向关联,因此 Sequelize 不应尝试为属性创建名称。
在每次测试(成功)之前,所有 table 都会被删除并重新创建。
如果我从 QuestionOption 的创建语句中删除 questionId: 1
,那么错误就变成了
SequelizeValidationError: notNull Violation: questionId cannot be null,
notNull Violation: QuestionId cannot be null
注意两个的外壳,一个在下面(我拆掉的那个)一个在上面
下一个怀疑是nextQuestionId
关联,但它已经在模型中定义,并且关联的每一侧为allowNull: true
和 我有在创建语句中提供它。
我对这种行为感到非常困惑,并质疑这是否是 sequelize 中的错误,尽管我需要在错误地报告之前确认这一点。
其他可能有用的信息是:
- 测试 运行 使用命令
NODE_ENV=test mocha
- 使用
sync
(下面的代码)自动创建测试数据库
- 所有其他测试均通过,但这是唯一一个在测试中使用 QuestionOption 的测试。
- 我正在尝试测试的方法有效 "in production"(运行在连接客户端的情况下在本地开发)
- 数据库模式已通过 SQLite GUI 验证并且所有列都是合适的(任何 table 中没有
QuestionId
字段带有大写 Q)
为测试创建数据库
beforeEach((done) => {
Survey.DBModel.sync({force: true, logging: false}).then(() => {
Question.DBModel.sync({force: true, logging: false}).then(() => {
Answer.DBModel.sync({force: true, logging: false}).then(() => {
QuestionOption.DBModel.sync({force: true, logging: false}).then(() => {
done();
}, done);
}, done);
}, done);
}, done);
});
所以在四处寻找答案并创建测试重现之后。事实证明,这是 Sequelize 的一个已知问题。解决方案,或者更脏的解决方法,是添加明显的 "missing" 属性 然后查询将起作用并且它将抛出分配给 ghost 属性.[=13 的值=]
describe('answerQuestion', () => {
it('should insert an answer and get the next question', (done) => {
Survey.DBModel.create({lookType: 0}, {logging: false}).then(() => {
Question.DBModel.create({type: 0, text: 'Test question'}, {logging: false}).then(q1 => {
Question.DBModel.create({type: 1, text: 'Next question'}, {logging: false}).then(q2 => {
QuestionOption.DBModel.create({
text: 'Test option',
questionId: 1,
QuestionId: 1, <------ Workaround
nextQuestionId: 2}, {logging: false}).then(() => {
Survey.answerQuestion(1, 1, 1).then(question => {
question.should.have.property('id');
}, done);
}, done);
}, done);
}, done);
}, done);
});
});
可以找到已知问题here
针对此问题进行测试重现here (如果更改,将删除 link)
希望这对解决此问题的其他人有所帮助。我确实希望这至少在他们的文档中记录为已知问题...
我正在为使用 Sequelize 的节点服务器编写单元测试。插入一些虚假数据后,我收到错误
SequelizeValidationError: notNull Violation: QuestionId cannot be null
注意大小写:QuestionId
单元测试:
describe('answerQuestion', () => {
it('should insert an answer and get the next question', (done) => {
Survey.DBModel.create({lookType: 0}, {logging: false}).then(() => {
Question.DBModel.create({type: 0, text: 'Test question'}, {logging: false}).then(q1 => {
Question.DBModel.create({type: 1, text: 'Next question'}, {logging: false}).then(q2 => {
console.log('before');
QuestionOption.DBModel.create({text: 'Test option', questionId: 1, nextQuestionId: 2}, {logging: false}).then(() => {
console.log('after');
Survey.answerQuestion(1, 1, 1).then(question => {
question.should.have.property('id');
}, done);
}, done);
}, done);
}, done);
}, done);
});
});
控制台输出'before'但在到达'after'之前出错
question.js
'use strict';
module.exports = function(sequelize, DataTypes) {
var Question = sequelize.define('Question', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
type: {
allowNull: false,
type: DataTypes.INTEGER
},
text: {
allowNull: false,
type: DataTypes.STRING
},
nextQuestionId: {
type: DataTypes.INTEGER
}
}, {
classMethods: {
associate: function(models) {
models.Question.belongsTo(models.Question, {as: 'nextQuestion', foreignKey: {field: 'nextQuestionId', allowNull: true}});
models.Question.hasMany(models.Answer, {as: 'answers', foreignKey: {field: 'questionId', allowNull: false}});
models.Question.hasMany(models.QuestionOption, {as: 'options', foreignKey: {field: 'questionId', allowNull: false}});
models.Question.hasMany(models.QuestionOption, {as: 'referrers', foreignKey: {field: 'nextQuestionId', allowNull: true}});
}
}
});
return Question;
};
questionoption.js
'use strict';
module.exports = function(sequelize, DataTypes) {
var QuestionOption = sequelize.define('QuestionOption', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
questionId: {
allowNull: false,
type: DataTypes.INTEGER
},
text: {
allowNull: false,
type: DataTypes.STRING
},
nextQuestionId: {
type: DataTypes.INTEGER
}
}, {
classMethods: {
associate: function(models) {
models.QuestionOption.belongsTo(models.Question, {as: 'question', foreignKey: {field: 'questionId', allowNull: false}});
models.QuestionOption.belongsTo(models.Question, {as: 'nextQuestion', foreignKey: {field: 'nextQuestionId', allowNull: true}});
}
}
});
return QuestionOption;
};
这些模型非常紧密地耦合在一起,并且具有自引用连接和各种其他混乱。其他模型我觉得都与此无关,但如果需要可以提供。
直接在 SQLite 数据库上执行 SQL,以与上面的创建语句相同的顺序和相同的属性不会抛出异常,并且通过大量测试很明显Sequelize 不会尝试 运行 QuestionOption
的创建语句。它在将 SQL 生成为 运行.
一些奇怪的行为是关联在模型中被精心定义,并且所有关联在其定义中都有 小写 q
for questionId
.所有关联也都定义了反向关联,因此 Sequelize 不应尝试为属性创建名称。
在每次测试(成功)之前,所有 table 都会被删除并重新创建。
如果我从 QuestionOption 的创建语句中删除 questionId: 1
,那么错误就变成了
SequelizeValidationError: notNull Violation: questionId cannot be null,
notNull Violation: QuestionId cannot be null
注意两个的外壳,一个在下面(我拆掉的那个)一个在上面
下一个怀疑是nextQuestionId
关联,但它已经在模型中定义,并且关联的每一侧为allowNull: true
和 我有在创建语句中提供它。
我对这种行为感到非常困惑,并质疑这是否是 sequelize 中的错误,尽管我需要在错误地报告之前确认这一点。
其他可能有用的信息是:
- 测试 运行 使用命令
NODE_ENV=test mocha
- 使用
sync
(下面的代码)自动创建测试数据库 - 所有其他测试均通过,但这是唯一一个在测试中使用 QuestionOption 的测试。
- 我正在尝试测试的方法有效 "in production"(运行在连接客户端的情况下在本地开发)
- 数据库模式已通过 SQLite GUI 验证并且所有列都是合适的(任何 table 中没有
QuestionId
字段带有大写 Q)
为测试创建数据库
beforeEach((done) => {
Survey.DBModel.sync({force: true, logging: false}).then(() => {
Question.DBModel.sync({force: true, logging: false}).then(() => {
Answer.DBModel.sync({force: true, logging: false}).then(() => {
QuestionOption.DBModel.sync({force: true, logging: false}).then(() => {
done();
}, done);
}, done);
}, done);
}, done);
});
所以在四处寻找答案并创建测试重现之后。事实证明,这是 Sequelize 的一个已知问题。解决方案,或者更脏的解决方法,是添加明显的 "missing" 属性 然后查询将起作用并且它将抛出分配给 ghost 属性.[=13 的值=]
describe('answerQuestion', () => {
it('should insert an answer and get the next question', (done) => {
Survey.DBModel.create({lookType: 0}, {logging: false}).then(() => {
Question.DBModel.create({type: 0, text: 'Test question'}, {logging: false}).then(q1 => {
Question.DBModel.create({type: 1, text: 'Next question'}, {logging: false}).then(q2 => {
QuestionOption.DBModel.create({
text: 'Test option',
questionId: 1,
QuestionId: 1, <------ Workaround
nextQuestionId: 2}, {logging: false}).then(() => {
Survey.answerQuestion(1, 1, 1).then(question => {
question.should.have.property('id');
}, done);
}, done);
}, done);
}, done);
}, done);
});
});
可以找到已知问题here
针对此问题进行测试重现here (如果更改,将删除 link)
希望这对解决此问题的其他人有所帮助。我确实希望这至少在他们的文档中记录为已知问题...