Reputation: 6806
On my schema, I've this...
const userSchema = db.define('USER',
{
id: { type: Sequelize.UUIDV4, allowNull: false, primaryKey: true},
...
}
On my MSSQL database, I've this:
id uniqueidentifier NOT NULL DEFAULT NEWID(),
so, NEWID() will populate the id with a new UUIDV4 data. However, when I perform a User.create(...), this throw me a ValidationError [SequelizeValidationError]: notNull Violation: USER.id cannot be null
Then I decided to make an attempt:
hooks : {
beforeCreate(user, options) {
user.id = generateNewUUID()
}
}
but it's also not working because hooks is just executed after the schema validation.
is there some work around for this that's not involves placing the id as a parameter of User.create ? It's something I'd like to avoid.
Upvotes: 1
Views: 2886
Reputation: 1218
Other commenters have observed OP might have been playing with a primary key, which has special behaviour around validation. But the title asks about 'values' generally. The common advice on that question is:
allowNull
requirement on the model definition, orThese are not great answers. Option 1 is effectively permanently distorting your model (and validations). Option 2 is closer to correct, but still annoying and unintuitive: what's the point in setting a default if I have to build logic to apply it?
For the record: if you did want to go with Option 2, beforeCreate
will not help (as you have noticed) because that hook is called after validation. You would have to use the beforeValidate
hook-- and then specifically add logic to ensure the hook is only triggered upon the record creation. Like so:
hooks: {
beforeValidate: async (user) => {
if (user.isNewRecord) await applyDefaults(user);
},
}
This^ works. But here's the real solution:
Don't write any hooks. Define your default value on the model like so:
const userSchema = db.define('USER', {
id: {
type: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
defaultValue: generateNewUUID()
}})
Then, when creating instances, use Model.build() instead of Model.create(). The former applies the defaults properly, before validation. Eg:
var user = User.build({
email: "[email protected]"
})
user = await user.save()
console.log(user.id) // <--- Now works as expected
CAVEAT: At time of writing, Sequelize still doesn't seem to support promises for default values. If you need to apply a resolved promise as defaultValue, you're stuck with Options 1 or 2.
Upvotes: 1
Reputation: 538
You need to remove the { allowNull: false }
constraint in order to use a default value from the DBMS side.
But if you want to keep the { allowNull: false }
constraint, you can alternatively set the default value to UUIDV4 from the ORM side by setting the default value of the column to Sequelize.UUIDV4
like so:
const userSchema = db.define('USER',
{
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true
},
...
}
(you don't need a beforeCreate hook in this case)
Upvotes: 0