序列化复合唯一约束

问题描述 投票:0回答:8

定义模型:

export default function(sequelize, DataTypes) {
   return sequelize.define('Item', {
       minor: DataTypes.INTEGER,
       major: DataTypes.INTEGER,
   });
}

我可以将次要和主要对定义为复合 UNIQUE 约束吗?

mysql node.js sequelize.js
8个回答
46
投票

最近在V4中,Sequelize在查询接口上有一个方法

addConstraint

queryInterface.addConstraint('Items', {
  fields: ['minor', 'major'],
  type: 'unique',
  name: 'custom_unique_constraint_name'
});

27
投票
queryInterface.createTable(
  'Item', 
  {
    minor: {
      type: Sequelize.INTEGER,
    },
    major: {
      type: Sequelize.INTEGER,
    }
  }, 
  {
    uniqueKeys: {
      Items_unique: {
        fields: ['minor', 'major']
      }
    }
  }
);

22
投票

这是简单的答案:

major: { type: DataTypes.INTEGER, unique: 'compositeIndex'},
minor: { type: DataTypes.INTEGER, unique: 'compositeIndex'}

来源:https://sequelize.org/master/manual/model-basics.html#column-options

// Creating two objects with the same value will throw an error. > The unique property can be either a
// boolean, or a string. If you provide the same string for > multiple columns, they will form a
// composite unique key.
uniqueOne: { type: DataTypes.STRING,  unique: 'compositeIndex' },
uniqueTwo: { type: DataTypes.INTEGER, unique: 'compositeIndex' },

如果是连接表,您还可以通过belongsToMany关联创建唯一约束:

Major = sequelize.define('major', {})
Minor = sequelize.define('minor', {})

Major.belongsToMany(Project)
Minor.belongsToMany(User)

来源:http://docs.sequelizejs.com/en/v3/docs/associations/

就我而言,我想找到一种方法在迁移中强制执行此操作。我通过在 up 函数末尾附加原始 sql 查询来做到这一点:

  up: function(queryInterface, Sequelize) {
return queryInterface.createTable('Item', {
  major: {
    allowNull: false,
    type: Sequelize.INTEGER
  },
  minor: {
    allowNull: false,
    type: Sequelize.INTEGER
  },
})
.then(function() {
  return queryInterface.sequelize.query(
    'ALTER TABLE `Item` ADD UNIQUE `unique_index`(`major`, `minor`)'
  );
});

相关问题:

序列化,外键作为复合主键

Sequelize 模型中外键的唯一约束


8
投票

我通过使用

addConstraint(...)
解决了这个问题:

await queryInterface.addConstraint('Item', {
  fields: ['minor', 'major'],
  type: 'unique',
  name: 'unique_constraint_name'
});

这是至少从 v6+ 开始的。


1
投票

你可以使用这样的东西:

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.sequelize.transaction(t => {
      return queryInterface.createTable('item',
        {
          minor: {
            type: Sequelize.INTEGER,
          },
          major: {
            type: Sequelize.INTEGER,
          }
        }, { transaction: t }
      ).then(() => {
        return queryInterface.addConstraint(
          'item',
          ['minor', 'major'],
          {
            type: 'unique',
            name: 'Items_unique'
          },
          {
            transaction: t
          }
        );
      });
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('item');
  }
}

1
投票

对于 ES6 迁移

const item = {
  up: (queryInterface, Sequelize) => queryInterface.createTable('Items', {
    minor: {
      type: Sequelize.INTEGER,
      allowNull: false,
    },
    major: {
      type: Sequelize.INTEGER,
      allowNull: false,
    },
  }).then(() => queryInterface.addConstraint('Items', ['minor', 'major'], {
    type: 'unique',
    name: 'composite_key_name'
  })),
  down: queryInterface => queryInterface.dropTable('Items')
};

export default item;

0
投票

sequelize.define('', {}, {indexes: [ { unique: true

除了杰克的回答之外,还有另一种方法:

const Item = sequelize.define('Item', {
    minor: DataTypes.INTEGER,
    major: DataTypes.INTEGER,
  }, {
    indexes: [
      {
        fields: ['minor', 'major'],
        unique: true,
      }
    ]
  }
)

它会根据字段自动创建名称,SQLite 查询:

CREATE TABLE IF NOT EXISTS `Items` (
  `id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `minor` INTEGER,
  `major` INTEGER,
  `createdAt` DATETIME NOT NULL,
  `updatedAt` DATETIME NOT NULL
);
PRAGMA INDEX_LIST(`Items`)
CREATE UNIQUE INDEX `items_minor_major` ON `Items` (`minor`, `major`)

记录于:https://sequelize.org/master/class/lib/model.js~Model.html#static-method-init

options.indexes[].unique
: 索引应该是唯一的吗?也可以通过将类型设置为 UNIQUE

来触发

Jake 的回答方法:

const Item = sequelize.define('Item', {
  minor: { type: DataTypes.INTEGER, unique: 'asdf' },
  major: { type: DataTypes.INTEGER, unique: 'asdf' },
})

产生一个匿名

UNIQUE
约束(它自动暗示我相信的索引),所以除了名称之外,两者都非常相似:

CREATE TABLE IF NOT EXISTS `Items` (
  `id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `minor` INTEGER,
  `major` INTEGER,
  `createdAt` DATETIME NOT NULL,
  `updatedAt` DATETIME NOT NULL,
  UNIQUE (`minor`, `major`)
);
PRAGMA INDEX_LIST(`Items`)
PRAGMA INDEX_INFO(`sqlite_autoindex_Items_1`)

PostgreSQL 查询是类似的。

完整的可运行示例:

main.js

#!/usr/bin/env node
const assert = require('assert')
const path = require('path')
const { DataTypes, Sequelize } = require('sequelize')
let sequelize
if (process.argv[2] === 'p') {
  sequelize = new Sequelize('tmp', undefined, undefined, {
    dialect: 'postgres',
    host: '/var/run/postgresql',
  })
} else {
  sequelize = new Sequelize({
    dialect: 'sqlite',
    storage: 'tmp.sqlite'
  })
}
;(async () => {
const Item = sequelize.define('Item', {
    minor: DataTypes.INTEGER,
    major: DataTypes.INTEGER,
  }, {
    indexes: [
      {
        fields: ['minor', 'major'],
        unique: true,
      }
    ]
  }
)
await Item.sync({ force: true })
await Item.create({ minor: 1, major: 1 })
await Item.create({ minor: 1, major: 2 })
let threw = false
try {
  await Item.create({ minor: 1, major: 2 })
} catch (e) {
  threw = true
}
assert(threw)
})().finally(() => { return sequelize.close() })

package.json

{
  "name": "tmp",
  "private": true,
  "version": "1.0.0",
  "dependencies": {
    "pg": "8.5.1",
    "pg-hstore": "2.3.3",
    "sequelize": "6.14.0",
    "sql-formatter": "4.0.2",
    "sqlite3": "5.0.2"
  }
}

在 PostgreSQL 13.5 上测试。


0
投票

为了子孙后代,我想提一下这一点。我有一个 Postgres 数据库,正在研究如何添加约束。我们最终使用索引作为约束,在模型上它看起来像这样

        sequelize,
        tableName: "table_name",
        timestamps: false,
        paranoid: true,
        indexes: [
            {
                name: "PRIMARY",
                unique: true,
                using: "BTREE",
                fields: [{ name: "field_id" }],
            },
            {
                name: "UniqueConstraint_1",
                unique: true,
                using: "BTREE",
                fields: [
                    { name: "user_id" },
                    { name: "player_id" },
                    { name: "game_id" },
                ],
            },

这将允许您对数据库有一个独特的“约束”。然而,它将显示在索引中而不是约束中。

© www.soinside.com 2019 - 2024. All rights reserved.