续集验证:对于单个属性,仅允许一项为 true


export default function (sequelize, DataTypes) {
  const OrderAddress = sequelize.define('OrderAddress', {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      autoIncrement: true,
      allowNull: false,
    },
    is_default: {
      type: DataTypes.BOOLEAN,
      allowNull: true,
      defaultValue: false,
    },
    receiver_name: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    phone_number: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    address: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    address_detail: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    postcode: {
      type: DataTypes.STRING,
      allowNull: true,
    },
  }
});

我的orderAddress模型如上所示,我想进行验证以仅允许一个项目将is_default设置为 true

所以

const address = {
  is_default: true, // default one
}
const address2 = {
  is_default: true // no you can't!
}

我应该is_default字段unique: true还是为此模型添加一些自定义validation

可能有几种方法可以实现这一点。

  1. Sequelize 为在查询生命周期中的特定事件上触发的钩子提供了一个选项。
    使用 beforeCreateafterValidate 钩子,您可以进行获取并查找是否有任何记录以 is_default 作为true,只需抛出错误即可。
  2. 在数据库层上添加一个触发器,该触发器检查是否有任何现有行带有 is_default 。可以通过后续迁移来添加和管理此类触发器
您可以在

order_id(或任何关系字段(和is_defualt(第一个示例(上添加唯一索引,也可以对其进行一些重构以在Order上设置default_address,而不是在OrderAddress上设置它(第二个示例(

第一个选项,添加唯一索引

// ...
  indexes: [
    {
      fields: ['is_default', 'order_id'], // or whatever your relational field is
      unique: true,
    },
  ],
// ...

第二个选项,在订单级别检查

假设OrderAddress属于类似Order模型的东西,您还可以在此处添加验证以提高效率。由于您想知道哪个地址是默认地址,并且只允许一个地址,因此添加一个名为 Order.default_address 的字段并将值设置为"地址"或"address2"的枚举,指示应该使用哪个 - 自然只能设置一个,而不是两个。

然后,在Order模型上,您可以添加一个beforeValidate钩子,用于检查设置为"默认"的字段是否包含OrderAddress的 ID。

export default function (sequelize, DataTypes) {
  const Order = sequelize.define('Order', {
    // your fields
    default_address: {
      type: DataTypes.ENUM(),
      values: ['address', 'address2'],
      allowNull: false,
      // defaultValue: 'address',
  },
  {
    hooks: {
      beforeValidate: function(instance) {
        switch (instance.default_address) {
          case 'address':
          case 'address2': {
            // check to see if address_id or address2_id is set, as needed
            if (!instance[instance.default_address + '_id') { // or + 'Id' if you use camel case
              return Sequelize.Promise.reject(
                new Error(`Default "${instance.default_address}" not set`)
              );
            }
          }
          default: {
            return Sequelize.Promise.reject(
              new Error('You must set a default address')
            );
          }
        }  
      },
    }
  }
});

最新更新