SequelizeEagerLoadingError:模型未与 otherModel 关联

Dan*_*rra 5 postgresql node.js express sequelize.js

我在不同的论坛上多次看到这个问题,但一直无法解决。我正在使用 Express 和 PostgreSQL 以及 Sequelize。

基本上我有两个模型:校园和学术经理。两者是一对一的关系,Campus有一名学术经理。

我已经实现了两个模型和关联工作,我可以看到它显示在 postgres 服务器的 mi 数据库中。但是当我尝试实现校园的获取请求时,我尝试包含经理信息,但没有成功。我不断收到同样的错误:

SequelizeEagerLoadingError:academic_manager 未与校园关联!

我相信我的问题与包括有关

这是我的代码片段:

校园.js

const campus = (sequelize, DataTypes) =>{
    const Campus = sequelize.define('campus', {
        name: {
            type: DataTypes.STRING,
            allowNull: false,
        },
        manager: {
            type: DataTypes.INTEGER,
            allowNull: false,
            references: {
                model: 'academic_manager',
                key: 'id'
            }
        } 
    });    

    Campus.associate = models => {
        Campus.hasOne(models.Manager, { foreignKey: 'id'});
    }

    return Campus; 
};

export default campus;

Run Code Online (Sandbox Code Playgroud)

学术管理器.js

const manager = (sequelize, DataTypes) =>{
    const Manager = sequelize.define('academic_manager', {
        name: {
            type: DataTypes.STRING,
            allowNull: false,
        },
        email: {
            type: DataTypes.STRING,
            allowNull: false
        } 
    });    

    Manager.associate = models => {
        Manager.belongsTo(models.Campus, { foreignKey: 'id'});
    }

    return Manager; 
};

export default manager;

Run Code Online (Sandbox Code Playgroud)

以及获取方法:

router.get('/', async (req, res) => {
    const campus = await req.context.models.Campus.findAll({
        include: [
            { model: req.context.models.Manager }
        ]
    });
    return res.send(campus);
}); 
Run Code Online (Sandbox Code Playgroud)

get 请求无需包含即可工作。我知道关联已实现,因为当我描述我的校园表和我的经理表时,我有以下内容:

TABLE "campus" CONSTRAINT "campus_manager_fkey" FOREIGN KEY (manager) REFERENCES academic_manager(id)
Run Code Online (Sandbox Code Playgroud)

Cal*_*twr 5

您的模型定义有几个问题。Sequelize 可能会混淆您是否想要关联模型,或者只是让它们相互引用。

您添加了实现关系约束的关联,还添加了引用键,该引用键旨在允许引用但不允许实现约束。

可能想阅读:

  1. 如何在sequelize中实现多对多关联
  2. https://sequelize.org/v5/manual/associations.html

我已经评论了你的代码:

校园.js

const Campus = (sequelize, DataTypes) =>{
    const Campus = sequelize.define('Campus', {
        name: {
            type: DataTypes.STRING,
            allowNull: false,
        }
        // this is not correct.
        // read when to use reference key further below
        /* manager: {
            type: DataTypes.INTEGER,
            allowNull: false,
            references: {
                model: 'academic_manager',
                key: 'id' 
            }

        } */
    });    

    Campus.associate = models => {
        // Campus.hasOne(models.Manager, { foreignKey: 'id'});
        // foreignKey `id` is wrong. Your models already by default have `id`, which is their own.
        // you either define the name as `campus_id`, or just let sequelize handle it for you by not defining it at all and just use `Campus.hasOne(models.Manager)`.
        // but generally it's good practice to define, otherwise when you need it, you have to figure out what did sequelize help you name it as.
        // read: https://sequelize.org/master/manual/assocs.html#providing-the-foreign-key-name-directly
        Campus.hasOne(models.Manager, { foreignKey: 'campus_id'); // this means please inject `campus_id` into `Manager` 
    }

    return Campus; 
};

export default Campus;
Run Code Online (Sandbox Code Playgroud)

学术管理器.js

const Manager = (sequelize, DataTypes) =>{
    const Manager = sequelize.define('Manager', {
        name: {
            type: DataTypes.STRING,
            allowNull: false,
        },
        email: {
            type: DataTypes.STRING,
            allowNull: false
        }
    });    

    Manager.associate = models => {
        // you don't define foreignKey here. because by doing so you are saying
        // you want to inject this foreignKey into `Campus`, which you are not.
        Manager.belongsTo(models.Campus);
    }

    return Manager; 
};

export default Manager;
Run Code Online (Sandbox Code Playgroud)

附加信息 - 何时使用此引用密钥?

在关系数据库中,经验法则是在任何 2 个模型之间,只能有 1 条路径,否则会形成循环依赖,这可能会导致问题。

想象你有第三个实体Location

Campus.hasOne(Manager)
Manager.belongsTo(Campus)

Location.hasOne(Campus)
Location.belongsTo(Campus)
Run Code Online (Sandbox Code Playgroud)

一切都很好。让我们想象一下,假设Manager停留在 上,你可以这样Campus找到它们Location

Manager -> Campus -> Location
Run Code Online (Sandbox Code Playgroud)

直到您确定这是一个真实的陈述,Manager将始终留在该陈述中Location而不是其他地方,并且您的应用程序更频繁地需要此信息时,您将很想这样做:

Location.hasOne(Manager)
Manager.belongsTo(Location)
Run Code Online (Sandbox Code Playgroud)

现在您有了另一条路径Location -> Manager,并且完成了循环引用Location -> Manager -> Campus -> Location -> Manager....

要打破这一点,您必须在哪种关系更重要或更常访问之间做出选择。在这种情况下,看起来Location和之间的关系Manager似乎并不那么重要,那么就继续使用Manager -> Campus -> Location

但你想要蛋糕也吃它

在这里,您无需关联模型,只需使用引用键或使用constraints: false. 阅读https://sequelize.org/master/manual/constraints-and-circularities.html

constraints: false是我通常的选择,因为它仍然为我提供了所有的续集方法,就好像模型是关联的一样。reference keys但严格来说,最多使用是正确的。然后执行手动联接,或使用您找到的引用键执行 2 次查询,以在其引用表上找到其数据。


Dan*_*rra 3

我的解决方案是我没有在模型索引中建立关联。我错过了这个:

Object.keys(models).forEach(key => {
  if ('associate' in models[key]) {
    models[key].associate(models);
  }
});
Run Code Online (Sandbox Code Playgroud)

永远记住要真正进行联想。