【问题标题】:Knex.js columns referencing foreign keys don't get created during migration迁移期间未创建引用外键的 Knex.js 列
【发布时间】:2018-06-19 03:19:17
【问题描述】:

当我执行我的 knex.js 迁移时,除了下面“recipe-in​​gredient”连接表中的两个外键表之外,所有内容都会构建。有人看到我做错了什么吗?这是迁移中的第三张表:

exports.up = function(knex, Promise) {
    return Promise.all([
        knex.schema.hasTable('recipe').then((exists) => {
            console.log('does knex have recipe table?', exists);
            if (!exists) {
                return knex.schema.createTable('recipe', (table) => {
                    table.uuid('id');
                    table.string('name');
                    table.string('description');
                })
            }
        }),
        knex.schema.hasTable('ingredient').then((exists) => {
            console.log('does knex have ingredient table?', exists);
            if (!exists) {
                return knex.schema.createTable('ingredient', (table) => {
                    table.uuid('id');
                    table.string('name');
                })
            }
        }),
        knex.schema.hasTable(`recipe-ingredient`).then((exists) => {
            console.log('does knex have recipe-ingredient table?', exists);
            if (!exists) {
                return knex.schema.createTable(`recipe-ingredient`, (table)=> {
                    table.uuid('recipe_id').references('id').inTable('recipe').notNull();
                    table.uuid('ingredient_id').references('id').inTable('ingredient').notNull();
                    table.string('qty');  // <-- chose string instead of int because receipes include qty such as '1/3 cup', '1 teaspoon', etc.
                })
            }
        })
    ])
};

exports.down = function(knex, Promise) {
    return Promise.all([
        knex.schema.dropTable('recipe-ingredient'),
        knex.schema.dropTable('ingredient'),
        knex.schema.dropTable('recipe')
    ])
};

这是我的 knexfile.js:

require('dotenv').config();

module.exports = {

  development: {
    client: 'mysql',
    connection: {
      host: process.env.DATABASE_HOST_DEV || '127.0.0.1',
      user: process.env.DATABASE_USER_DEV,
      password: process.env.DATABASE_PASSWORD_DEV,
      database: process.env.DATABASE_NAME_DEV
    },
    migrations: {
      directory: __dirname+'/database/migrations'
    }
  },

  staging: {
    client: 'mysql',
    connection: {
      host: '127.0.0.1',
      user: 'root',
      password: 'password',
      database: 'recipes'
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      directory: __dirname+'/database/migrations'
    }
  },

  production: {
    client: 'mysql',
    connection: {
      host: process.env.DATABASE_HOST,
      user: process.env.DATABASE_USER,
      password: process.env.DATABASE_PASSWORD,
      database: process.env.DATABASE_NAME
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      directory: __dirname+'/database/migrations'
    }
  }

};

请注意,.env 文件中的变量并没有什么特别之处。只是基本的用户名、密码和数据库名称。

【问题讨论】:

  • console.log('does knex have recipe-ingredient table?', exists); 执行了吗? exists 的值是多少?
  • @therobinkim 好问题。以前这些日志打印为 true,现在它们都打印为 false:does knex have recipe table? false does knex have ingredient table? false does knex have recipe-ingredient table? false 迁移失败,ER_CANNOT_ADD_FOREIGN: Cannot add foreign key constraint
  • @therobinkim 尽管它收到了失败消息,但表正在构建,包括外键列,并且种子现在也在工作!!!
  • 哪个数据库?在这种情况下,这也可能很重要。
  • @MikaelLepistö 我会将我的 knexfile 添加到帖子中,以便您查看。它只是 mySQL 的一个本地实例。

标签: javascript knex.js


【解决方案1】:

您不应使用 promise.all 并并行运行所有查询。

IIRC knex 为这些查询创建事务,但实际上 mysql 在第一个 CREATE TABLE 语句之后执行隐式提交,因此事务将被提交,其余的表创建可能会以多种方式失败。

Knex 可能会说它无法对已提交的事务执行更多查询,或者它可能只是忽略其他查询,或者它可能只是在事务之外运行它们,但通过相同的数据库连接。很难说当您运行该迁移时究竟会发生什么,但它肯定不会完全按照您的期望完成。

这应该会更好:

exports.up = function(knex, Promise) {
    return knex.schema.hasTable('recipe').then((exists) => {
        console.log('does knex have recipe table?', exists);
        if (!exists) {
            return knex.schema.createTable('recipe', (table) => {
                table.uuid('id');
                table.string('name');
                table.string('description');
            });
        }
    }).then(() => {
        return knex.schema.hasTable('ingredient').then((exists) => {
            console.log('does knex have ingredient table?', exists);
            if (!exists) {
                return knex.schema.createTable('ingredient', (table) => {
                    table.uuid('id');
                    table.string('name');
                })
            }
        });
    }).then(() => {
        return knex.schema.hasTable(`recipe-ingredient`).then((exists) => {
            console.log('does knex have recipe-ingredient table?', exists);
            if (!exists) {
                return knex.schema.createTable(`recipe-ingredient`, (table)=> {
                    table.uuid('recipe_id').references('id').inTable('recipe').notNull();
                    table.uuid('ingredient_id').references('id').inTable('ingredient').notNull();
                    table.string('qty');  // <-- chose string instead of int because receipes include qty such as '1/3 cup', '1 teaspoon', etc.
                })
            }
        })
    });
};

exports.down = function(knex, Promise) {
    return knex.schema.dropTable('recipe-ingredient')
      .then(() => knex.schema.dropTable('ingredient'))
      .then(() => knex.schema.dropTable('recipe'));
};

【讨论】:

  • 非常感谢@Mikael Lepisto。很抱歉没有早点回到这个线程。从那以后我不得不离开这个项目。
猜你喜欢
  • 2023-01-04
  • 2011-03-19
  • 2019-08-29
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-16
相关资源
最近更新 更多