Sequelize.js onDelete:“级联”不删除记录续集

Posted

技术标签:

【中文标题】Sequelize.js onDelete:“级联”不删除记录续集【英文标题】:Sequelize.js onDelete: 'cascade' is not deleting records sequelize 【发布时间】:2014-06-01 11:16:09 【问题描述】:

我有Product 表和以下列[id, name, CategoryId]Category 表和[id, name]

产品型号:-

module.exports = function(sequelize, DataTypes) 
  var Product = sequelize.define('Product', 
    name: DataTypes.STRING
  , 
    associate: function(models) 
      Product.belongsTo(models.Category);
    
  );
  return Product

类别模型:-

module.exports = function(sequelize, DataTypes) 
  var Category = sequelize.define('Category', 
    name:  type: DataTypes.STRING, allowNull: false 
  , 
    associate: function(models) 
      Category.hasMany(models.Product,  onDelete: 'cascade' );
    
  );
  return Category

当我删除类别时,它只删除类别而不是与之关联的相应产品。我不知道为什么会这样?

更新: 续集版sequelize 1.7.0

================================================ ================================== 回答(我是如何解决的。):-

我通过使用Alter 命令在数据库上添加约束来实现这一点,因为Add Foreign Key Constraintmigrationsequelize 中的一个开放bug。

ALTER TABLE "Products"
ADD CONSTRAINT "Products_CategoryId_fkey" FOREIGN KEY ("CategoryId")
REFERENCES "Categories" (id) MATCH SIMPLE
ON DELETE CASCADE

【问题讨论】:

sequelize.sync 的输出是什么?是否添加具有删除约束的外键?你是哪个版本的? @JanAagaardMeier 产品表具有 CategoryId 列,但未添加外键约束。如何添加带有删除约束的外键? 添加外键约束是否需要添加迁移? @Sampat,您编辑此问题的方式令人困惑。如果 agchou 的答案有效,您应该接受它作为答案,而不是修改您的问题以使其看起来从未在代码中出现错误。它会让其他人更清楚地看到包含问题的问题,以及解决问题的公认答案。 【参考方案1】:

我相信您应该将 onDelete 放在 Category 模型而不是 products 模型中。

module.exports = function(sequelize, DataTypes) 
  var Category = sequelize.define('Category', 
    name:  type: DataTypes.STRING, allowNull: false 
  , 
    associate: function(models) 
      Category.hasMany(models.Product,  onDelete: 'cascade' );
    
  );
  return Category

【讨论】:

这对我不起作用,直到我也添加了hooks: true。不确定这是错误还是设计【参考方案2】:

从 "sequelize": "^3.5.1" 开始,它仅在您将 onDelete='CASCADE' 放入 belongsTo 声明时才有效,这就是您的情况下的 Product 模型。这与文档相矛盾:http://sequelize.readthedocs.org/en/latest/api/associations/index.html?highlight=onDelete#hasmanytarget-options

请看这个问题:Sequelize onDelete not working

【讨论】:

使用 hasMany() 对我来说效果很好,但我必须在选项中添加“hooks: true”。像 User.hasOne(Profile, onDelete: 'cascade', hooks:true) 喜欢@SoichiHayashi,onDelete: 'cascade', hooks: true hasMany 协会为我工作。我在续集“3.30”。以相反的方式进行关联实际上给我带来了一些问题。【参考方案3】:

由于偏执,我终于发现它对我不起作用。 Sequelize 不处理cascade,而是执行 mysql 级联删除。话虽如此,如果您对表格使用偏执狂 - 级联将不会发生,因为记录并没有真正从表格中删除。

【讨论】:

我非常想念 Hibernate 续集是可憎的。【参考方案4】:

我正在使用 Sequelize 4.38.0。

我必须将onDelete: 'CASCADE' 不仅放在关联定义上,还要放在迁移文件中。

// in models/user.js
User.associate = models => 
  User.belongsTo(models.Organization, 
    foreignKey:  name: 'organizationId', allowNull: true ,
    onDelete: 'CASCADE',
  )


// in migrations/create-users.js
up: (queryInterface, Sequelize) => 
  return queryInterface.createTable('Users', 
    // other fields...
    organizationId: 
      type: Sequelize.INTEGER,
      allowNull: true,
      onDelete: 'CASCADE',
      references: 
        model: 'Organizations',
        key: 'id',
        as: 'organizationId',
      ,
    ,
  )
,

【讨论】:

我曾经运行过迁移文件,现在我在其中添加了onDelete: 'CASCADE',。那么重新运行它会将这个东西添加到我的数据库中的表中而不会弄乱任何其他东西吗?【参考方案5】:

这里的问题是生成的一些时间迁移脚本缺少CONSTRAINT for foreign key

我仍然收到问题事件,请关注 official document for onDelete: 'cascade', hooks: true

这是我的解决方案:

第 1 步:像往常一样创建迁移文件,但还没有 foreign key。记得像你一样定义associate

    Product.belongsTo(models.Category);

    Category.hasMany(models.Product);

第 2 步:创建迁移脚本以将 foreign key 列添加到表中:

'use strict';
module.exports = 
  up: (queryInterface, Sequelize) => 
    return queryInterface.addColumn(
      'Product', // name of Source model
      'categoryId', // name of the key we're adding 
      
        type: Sequelize.INTEGER,
        references: 
          model: 'Category', // name of Target model
          key: 'id', // key in Target model that we're referencing
        ,
        onUpdate: 'CASCADE',
        onDelete: 'CASCADE',
      
    );
  ,
  down: (queryInterface, Sequelize) => 
    return queryInterface.removeColumn(
      'Product', // name of Source model
      'categoryId' // key we want to remove
    );
  
;

希望对您有所帮助!

我通过组合找到了这个解决方案:

[Express.js][Sequelize] How to delete child records ( cascade deleting ) at the time of deleting parent record.

How to define Sequelize associations using migrations

【讨论】:

它有效!谢谢! 为我工作,但必须输入复数名称。 references: model: 'Questions' 为我工作,但 references: model: 'Question' 没有。【参考方案6】:

hasMany 关联上添加 onDelete 级联并将钩子设置为 true 像这样

 Category.hasMany(models.Product,  onDelete: 'cascade', hooks:true );

【讨论】:

这可行,但使用 hooks:true 对性能有不良影响。在这里结帐:sequelize.org/master/manual/hooks.html【参考方案7】:

OP在问题中添加的答案:

我通过使用Alter 对数据库添加约束来实现这一点 命令,因为 Add Foreign Key Constraintmigration 是 在sequelize 中打开 [bug][1]。

ALTER TABLE "Products"
ADD CONSTRAINT "Products_CategoryId_fkey" FOREIGN KEY ("CategoryId")
REFERENCES "Categories" (id) MATCH SIMPLE
ON DELETE CASCADE

【讨论】:

【参考方案8】:

我不知道为什么,但是这个onDelete: 'cascade', hooks: true 对我不起作用。 如果您遇到同样的问题,请尝试在模型的 migration 文件中添加 reference 相关代码。

"use strict";
module.exports = 
    up: async (queryInterface, Sequelize) => 
        await queryInterface.createTable("TravelDetails", 
            id: 
                ......
            ,
            event_id: 
                type: Sequelize.INTEGER,
                onDelete: "CASCADE",
                references: 
                    model: "Events",
                    key: "id",
                    as: "eventData",
                ,
            ,
        );
    ,
    down: async (queryInterface, Sequelize) => 
        await queryInterface.dropTable("TravelDetails");
    ,
;

【讨论】:

【参考方案9】:

我无法管理最新的 "sequelize": "^6.6.5" 关联级联以使用此处提到的任何提示在现有的 postgres 数据库上工作,因此必须将其替换为模型 beforeDestroy 钩子,如下所示

User.beforeDestroy(async user => 
  await Role.destroy( where:  userId: user.id  )
)

【讨论】:

【参考方案10】:

您确定要声明模型之间的关联吗?

/models/index.js

const Category  = require('./Category');
const Product = require('./Product');
const ProductTag = require('./ProductTag');
const Tag = require('./Tag');

Category.associate(Product);
Product.associate(Category,Tag);
Tag.associate(Product);

module.exports=Category,Product,ProductTag,Tag;

模型 Category.js

'use strict';
const Model, DataTypes = require('sequelize');
const sequelize = require('../config/connection.js');

class Category extends Model 
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(Product) 
        // define association here
        console.log('Category associated with: Product');
        this.hasMany(Product, 
            foreignKey: 'category_id',
            onDelete: 'CASCADE'
        );
    


Category.init(
    category_id: type: DataTypes.INTEGER, autoIncrement: true, allowNull: false, primaryKey: true,
    category_name: type: DataTypes.STRING, allowNull: false
, 
    sequelize,
    timestamps: false,
    freezeTableName: true,
    underscored: true,
    modelName: "Category",
);

module.exports = Category;

【讨论】:

【参考方案11】:

至于sequelize ^6.6.5,因为这个话题在搜索sequelize CASCADE时很热门:

我必须在 hasMany 和 belongsTo 关联上都使用 onDelete:'cascade' 才能使其工作。

 Product.belongsTo(models.Category,  onDelete: 'CASCADE' );
 Category.hasMany(models.Product,  onDelete: 'CASCADE' );

【讨论】:

【参考方案12】:

您只需更新您的产品迁移文件。 为了在删除要与子产品一起删除的类别时,您需要在产品迁移中具有以下内容

...
categoryId: 
    type: Sequelize.INTEGER,
    references : 
      model : 'Category',
      key : 'id'
    ,
    onUpdate: 'CASCADE',
    onDelete: 'CASCADE',
,
...

不需要在模型中添加这个 onDelete: '级联'

【讨论】:

【参考方案13】:

删除父记录,同时删除子记录。

添加到子文件

onDelete: 'cascade'

它成功了。

例如

/migrations/profile.js(外键是'user_id')

'use strict'
module.exports = 
  up: async (queryInterface, Sequelize) => 
    await queryInterface.createTable('profiles', 
      id: 
        allowNull: false,
        primaryKey: true,
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
      ,
      name: 
        allowNull: false,
        type: Sequelize.STRING,
      ,
      age: 
        allowNull: false,
        type: Sequelize.STRING,
      ,
      user_id: 
        allowNull: false,
        type: Sequelize.UUID,
        references:  model: 'users', key: 'id' ,
        onDelete: 'CASCADE',    ← ※ Add here. ※
      ,
    )
  ,
  down: async (queryInterface, Sequelize) => 
    await queryInterface.dropTable('profiles')
  ,


【讨论】:

以上是关于Sequelize.js onDelete:“级联”不删除记录续集的主要内容,如果未能解决你的问题,请参考以下文章

级联=“删除” VS orphanRemoval=true VS ondelete="CASCADE

如何使用 prisma 2 或 3 和 nexus 模式生成同时生成生成的 crud 和“ondelete 级联”

使用 EF Core 进行级联删除

MySQL外键约束OnDelete和OnUpdate的使用

12.创建关系时的级联操作

Sequelize.js 外键