[문제해결] 시드 스크립트 실행 후 QueryFailedError: column 엔티티.칼럼명 does not exist 에러 해결하기(synchronize, namingStrategy 옵션)

cabbage·2023년 11월 18일
0

문제해결

목록 보기
3/3
post-thumbnail

서론

시드 스크립트를 실행한 뒤 회원가입 API를 실행했을 때 다음과 같은 에러가 발생했다.

이 에러가 발생한 이유가 너무 의아했다. 분명히 데이터베이스에는 유저 테이블과 모든 칼럼들이 제대로 들어 있는걸 확인했지만, 이 문제가 계속 발생했다.

문제 원인

이 문제가 발생한 원인은 데이터베이스 시드를 실행하기 위한 데이터베이스 연결 옵션과 기존의 데이터베이스 연결 옵션이 달라서 발생했던 문제였다.

기존의 데이터베이스 연결 옵션 코드는 다음과 같다.

...
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';

@Module({
	imports: [
		TypeOrmModule.forRootAsync({
			imports: [ConfigModule],
			inject: [ConfigService],
			useFactory: (configService: ConfigService) => ({
				type: 'postgres',
				host: configService.getOrThrow('POSTGRESQL_HOST'),
				port: configService.getOrThrow('POSTGRESQL_PORT'),
				username: configService.getOrThrow('POSTGRESQL_USER'),
				password: configService.getOrThrow('POSTGRESQL_PASSWORD'),
				database: configService.getOrThrow('POSTGRESQL_DATABASE'),
				entities: [__dirname + '/../**/*.entity.*'],
				synchronize: configService.getOrThrow('POSTGRESQL_SYNCHRONIZE'),
				logging: configService.getOrThrow('POSTGRESQL_LOGGING'),
				namingStrategy: new SnakeNamingStrategy(),
			}),
		}),
	],
})
export class DatabaseModule {}
  • 여기서 namingStrategy 옵션에 typeorm-naming-strategies 패키지의 SnakeNamingStrategy를 적용하여 모든 테이블의 칼럼 이름을 스네이크 케이스로 자동으로 변환하게 하였다.

다음은 데이터베이스 시드를 실행하기 위한 DataSource 코드이다.

import { ConfigService } from '@nestjs/config';
import { config } from 'dotenv';
import { DataSource, DataSourceOptions } from 'typeorm';
import { SeederOptions } from 'typeorm-extension';
import { BaseEntity } from 'src/global';
import { User } from 'src/users';
import { MonthlyBudgetsFactory, MainSeeder, UsersFactory, CategoryBudgetsFactory } from 'src/database';
import { MonthlyBudget } from 'src/monthly-budgets';
import { CategoryBudget } from 'src/category-budgets';
import { Category } from 'src/categories';

config({
	path: '.development.env',
});
const configService = new ConfigService();

const options: DataSourceOptions & SeederOptions = {
	type: 'postgres',
	host: 'localhost',
	port: configService.getOrThrow<number>('POSTGRESQL_PORT'),
	username: configService.getOrThrow('POSTGRESQL_USER'),
	password: configService.getOrThrow('POSTGRESQL_PASSWORD'),
	database: configService.getOrThrow('POSTGRESQL_DATABASE'),
	synchronize: configService.getOrThrow<boolean>('POSTGRESQL_SYNCHRONIZE'),
	entities: [BaseEntity, User, MonthlyBudget, CategoryBudget, Category],
	factories: [UsersFactory, MonthlyBudgetsFactory, CategoryBudgetsFactory],
	seeds: [MainSeeder],
};
export const dataSource = new DataSource(options);
  • namingStrategy 옵션에 typeorm-naming-strategies 패키지의 SnakeNamingStrategy를 적용하지 않았다.

처음으로 서버를 실행하면 기존의 데이터베이스 연결 옵션을 따라 모든 테이블의 칼럼 이름들은 다음과 같이 스네이크 케이스로 변환된다.

  • 스네이크 케이스 적용 칼럼 이름이 스네이크 케이스로 변환되었음

서버 실행 이후 시드 스크립트를 실행하면 synchronize 옵션에 따라 엔티티 파일에 선언한 모든 칼럼들이 카멜 케이스로 다시 바뀌어 버린다.

  • 스네이크 케이스가 적용되었던 칼럼 이름이 다시 카멜 케이스로 변환되었음

하지만 서버에 API를 요청하면 기존의 데이터베이스 연결 옵션에 따라 스네이크 케이스로 쿼리를 보내게 된다. 여기서 이 차이 때문에 QueryFailedError: column 엔티티.칼럼명 does not exist 에러가 계속 발생했던 것이다.

문제 해결

데이터베이스 시드를 실행하기 위한 DataSource의 데이터베이스 연결 옵션을 수정하였다.

  • synchronize 옵션 제거 및 namingStrategy 옵션 동일화
    import { ConfigService } from '@nestjs/config';
    import { config } from 'dotenv';
    import { DataSource, DataSourceOptions } from 'typeorm';
    import { SeederOptions } from 'typeorm-extension';
    import { BaseEntity } from 'src/global';
    import { User } from 'src/users';
    import { MonthlyBudgetsFactory, MainSeeder, UsersFactory, CategoryBudgetsFactory } from 'src/database';
    import { MonthlyBudget } from 'src/monthly-budgets';
    import { CategoryBudget } from 'src/category-budgets';
    import { Category } from 'src/categories';
    import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
    
    config({
    	path: '.development.env',
    });
    const configService = new ConfigService();
    
    const options: DataSourceOptions & SeederOptions = {
    	type: 'postgres',
    	host: 'localhost',
    	port: configService.getOrThrow<number>('POSTGRESQL_PORT'),
    	username: configService.getOrThrow('POSTGRESQL_USER'),
    	password: configService.getOrThrow('POSTGRESQL_PASSWORD'),
    	database: configService.getOrThrow('POSTGRESQL_DATABASE'),
    	entities: [BaseEntity, User, MonthlyBudget, CategoryBudget, Category],
    	namingStrategy: new SnakeNamingStrategy(),
    	factories: [UsersFactory, MonthlyBudgetsFactory, CategoryBudgetsFactory],
    	seeds: [MainSeeder],
    };
    export const dataSource = new DataSource(options);

몇시간 삽질하면서 구글링을 통해 문제 해결 방법을 찾을 수 없었지만, 에러 메세지를 통해 문제를 해결할 수 있었다.

profile
캐비지 개발 블로그입니다. :)

0개의 댓글