저장을 습관화

에러 기록 - SequelizeForeignKeyConstraintError 본문

공부/node.js

에러 기록 - SequelizeForeignKeyConstraintError

ctrs 2023. 7. 14. 13:52

- 증상

...(중략)...
const { postId } = req.params;
const { userId } = res.locals.user

...(중략)...

await this.likeService.addLike(postId, userId);

사용자 로그인한 후 Likes 테이블에 좋아요에 관한 데이터를 저장하려는 중 발생한 에러

sequelizeForeignKeyConstraintError 외래키 제약 조건 에러

 

 

에러 로그

외래키 제약 조건 때문에 전달인자로 받아온 userId를 Likes테이블의 UserId에 넣지 못한다고 나옴

Executing (default): INSERT INTO `Likes` (`likeId`,`UserId`,`PostId`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?,?,?);
Error
    at Query.run (C:\(생략)LV.5\node_modules\sequelize\lib\dialects\mysql\query.js:52:25)
    at C:\(생략)LV.5\node_modules\sequelize\lib\sequelize.js:315:28
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async MySQLQueryInterface.insert (C:\(생략)LV.5\node_modules\sequelize\lib\dialects\abstract\query-interface.js:308:21)
    at async Likes.save (C:\(생략)LV.5\node_modules\sequelize\lib\model.js:2490:35)
    at async Likes.create (C:\(생략)LV.5\node_modules\sequelize\lib\model.js:1362:12)
    at async LikeRepository.addLikePost (C:\(생략)LV.5\repositories\04_like_repository.js:32:30)
    at async LikeService.addLike (C:\(생략)LV.5\services\04_like_service.js:44:5)
    at async likeComment (C:\(생략)LV.5\controllers\04_like_controller.js:36:9) {
  name: 'SequelizeForeignKeyConstraintError',
  parent: Error: Cannot add or update a child row: a foreign key constraint fails (`lv5`.`Likes`, CONSTRAINT `Likes_ibfk_1` FOREIGN KEY (`UserId`) REFERENCES `Users` (`userId`) ON DELETE CASCADE)
      at Packet.asError (C:\(생략)LV.5\node_modules\mysql2\lib\packets\packet.js:728:17)
      at Execute.execute (C:\(생략)LV.5\node_modules\mysql2\lib\commands\command.js:29:26)
      at Connection.handlePacket (C:\(생략)LV.5\node_modules\mysql2\lib\connection.js:497:34)
      at PacketParser.onPacket (C:\(생략)LV.5\node_modules\mysql2\lib\connection.js:97:12)
      at PacketParser.executeStart (C:\(생략)LV.5\node_modules\mysql2\lib\packet_parser.js:75:16)
      at Socket.<anonymous> (C:\(생략)LV.5\node_modules\mysql2\lib\connection.js:104:25)
      at Socket.emit (node:events:513:28)
      at addChunk (node:internal/streams/readable:324:12)
      at readableAddChunk (node:internal/streams/readable:297:9)
      at Readable.push (node:internal/streams/readable:234:10) {
    code: 'ER_NO_REFERENCED_ROW_2',
    errno: 1452,
    sqlState: '23000',
    sqlMessage: 'Cannot add or update a child row: a foreign key constraint fails (`lv5`.`Likes`, CONSTRAINT `Likes_ibfk_1` FOREIGN KEY (`UserId`) REFERENCES `Users` (`userId`) ON DELETE CASCADE)',
    sql: 'INSERT INTO `Likes` (`likeId`,`UserId`,`PostId`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?,?,?);',
    parameters: [ '4', 18, '2023-07-14 04:14:24', '2023-07-14 04:14:24' ]
  },
  original: Error: Cannot add or update a child row: a foreign key constraint fails (`lv5`.`Likes`, CONSTRAINT `Likes_ibfk_1` FOREIGN KEY (`UserId`) REFERENCES `Users` (`userId`) ON DELETE CASCADE)
      at Packet.asError (C:\(생략)LV.5\node_modules\mysql2\lib\packets\packet.js:728:17)
      at Execute.execute (C:\(생략)LV.5\node_modules\mysql2\lib\commands\command.js:29:26)
      at Connection.handlePacket (C:\(생략)LV.5\node_modules\mysql2\lib\connection.js:497:34)
      at PacketParser.onPacket (C:\(생략)LV.5\node_modules\mysql2\lib\connection.js:97:12)
      at PacketParser.executeStart (C:\(생략)LV.5\node_modules\mysql2\lib\packet_parser.js:75:16)
      at Socket.<anonymous> (C:\(생략)LV.5\node_modules\mysql2\lib\connection.js:104:25)
      at Socket.emit (node:events:513:28)
      at addChunk (node:internal/streams/readable:324:12)
      at readableAddChunk (node:internal/streams/readable:297:9)
      at Readable.push (node:internal/streams/readable:234:10) {
    code: 'ER_NO_REFERENCED_ROW_2',
    errno: 1452,
    sqlState: '23000',
    sqlMessage: 'Cannot add or update a child row: a foreign key constraint fails (`lv5`.`Likes`, CONSTRAINT `Likes_ibfk_1` FOREIGN KEY (`UserId`) REFERENCES `Users` (`userId`) ON DELETE CASCADE)',
    sql: 'INSERT INTO `Likes` (`likeId`,`UserId`,`PostId`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?,?,?);',
    parameters: [ '4', 18, '2023-07-14 04:14:24', '2023-07-14 04:14:24' ]
  },
  sql: 'INSERT INTO `Likes` (`likeId`,`UserId`,`PostId`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?,?,?);',
  parameters: [ '4', 18, '2023-07-14 04:14:24', '2023-07-14 04:14:24' ],
  table: 'Users',
  fields: [ 'UserId' ],
  value: '4',
  index: 'Likes_ibfk_1',
  reltype: 'child'
}

 

- 원인과 해결

외래키 제약 조건 에러

Likes 테이블의 컬럼 UserId는 

Users 테이블의 기본키 userId를 외래키로 받아오도록 설정되어 있음

 

- /models/users.js

...(생략)...
static associate(models) {
      ...(생략)...
      this.hasMany(models.Likes, {
        sourceKey: "userId",
        foreignKey: "UserId",
      });
    }
...(생략)...

 

- /models/likes.js

...(생략)...
static associate(models) {
      // define association here
      this.belongsTo(models.Users, {
        targetKey: "userId",
        foreignKey: "UserId",
      });
...(생략)...

적어도 테이블 간 관계 문제는 없었음..

 

 

원인을 찾기 위해 로직의 흐름에 따라가며 각 부분에 로그를 찍은뒤 실행했고

// /controllers/04_like_controller.js
...
// 좋아요, 좋아요 취소 로직
      const didILike = await this.likeService.findLikedPost(userId, postId);
      console.log("기존 좋아요 확인 부분의 userId", userId);

      if (!didILike) {
        // 없다면 좋아요 등록
        console.log("아직 좋아요 하지 않았습니다. - 04_like_controller.js");
        console.log("좋아요 등록 부분의 userId", userId);

        await this.likeService.addLike(postId, userId);

        return res.status(200).json({ LIKE: "해당 게시글에 좋아요 했습니다." });
      }
...

// /services/04_like_service.js
...
// 게시글 좋아요
  addLike = async (userId, postId) => {
    console.log("게시글 좋아요 부분의 userId", userId);
    await this.likeRepository.addLikePost(userId, postId);

    return;
  };
...

// /repositories/04_like_repository.js
...
// 게시글 좋아요
  addLikePost = async (userId, postId) => {
    console.log("여기까진 들어옴", userId);

    try {
      const createLikeData = await Likes.create({
        UserId: userId,
        PostId: postId,
      });

      return createLikeData;
    } catch (error) {
      console.log(error);
    }
  };
...

출력된 로그는 아래와 같았음

기존 좋아요 확인 부분의 userId 18
아직 좋아요 하지 않았습니다. - 04_like_controller.js
좋아요 등록 부분의 userId 18
게시글 좋아요 부분의 userId 4
여기까진 들어옴 4

 

이를 통해 /controllers/04_like_controller.js에서 /services/04_like_service.js로 인자를 넘기는 동안

userId와 postId가 서로 뒤바뀌고 있다는 것을 확인함

 

해당 부분을 살펴 보니

/controllers/04_like_controller.js에서는 전달인자를 postId, userId 순으로 보냈으나

await this.likeService.addLike(postId, userId);

 

/services/04_like_service.js 에서는 매개변수를 userId, postId 순으로 받아 사용하였음

addLike = async (userId, postId) =>

 

그래서 원래 userId: 18, postId: 4 인 것이

userId: 4, postId: 18로 처리 되었고

 

코드는 Likes 테이블에 UserId에 4, PostId에 18을 저장하려 했으나

Users 테이블에 userId 4가 없었기에 외래키 제약 조건 에러가 발생한 것

 

 

해당 부분의 순서를 수정, 실행한 뒤 로그 확인

존 좋아요 확인 부분의 userId 18
아직 좋아요 하지 않았습니다. - 04_like_controller.js
좋아요 등록 부분의 userId 18
게시글 좋아요 부분의 userId 18
여기까진 들어옴 18

// 정상

Likes 테이블 조회

정상 등록 확인

 

바쁘다고 코드 막 구겨넣지 말자