-
카테고리
-
세부 분야
백엔드
-
해결 여부
미해결
Exception Filter편에서 POST할 때 EntityMetadataNotFoundError에러가 납니다.
24.01.12 13:55 작성 24.01.12 13:57 수정 조회수 187
0
// users.module.ts
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Users } from '../entities/Users';
@Module({
imports: [TypeOrmModule.forFeature([Users])],
providers: [UsersService],
controllers: [UsersController],
})
export class UsersModule {}
// app.module.ts
import { MiddlewareConsumer, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import { LoggerMiddleware } from './middlewares/logger.middleware';
import { UsersModule } from './users/users.module';
import { WorkspacesModule } from './workspaces/workspaces.module';
import { ChannelsModule } from './channels/channels.module';
import { DmsModule } from './dms/dms.module';
import { UsersService } from './users/users.service';
import * as process from 'process';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Users } from './entities/Users';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
UsersModule,
WorkspacesModule,
ChannelsModule,
DmsModule,
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: process.env.DB_USER,
password: process.env.DB_PW,
database: process.env.DB_NAME,
entities: ['./entities/*.{js,ts}'],
synchronize: false,
logging: true,
keepConnectionAlive: true,
migrations: [__dirname + '/src/migrations/*.ts'],
}),
TypeOrmModule.forFeature([Users]),
],
controllers: [AppController],
providers: [AppService, UsersService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer): void {
consumer.apply(LoggerMiddleware).forRoutes('*');
}
}
// users.controller.ts
import {
Body,
Controller,
Post,
Get,
Req,
Res,
UseInterceptors,
} from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { JoinRequestDto } from './dto/join.request.dto';
import { UsersService } from './users.service';
import { UserDto } from '../common/dto/user.dto';
import { User } from '../common/decorators/user.decorator';
import { UndefinedToNullInterceptor } from '../common/interceptors/undefinedToNull.interceptor';
@UseInterceptors(UndefinedToNullInterceptor)
@ApiTags('USER')
@Controller('api/users')
export class UsersController {
constructor(private usersService: UsersService) {}
//.....
@ApiOperation({ summary: '회원가입' })
@Post()
async join(@Body() body: JoinRequestDto) {
await this.usersService.join(body.email, body.nickname, body.password);
}
import { HttpException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Users } from '../entities/Users';
import bcrypt from 'bcrypt';
@Injectable()
export class UsersService {
constructor() {}
@InjectRepository(Users)
private usersRepository: Repository<Users>;
getUser() {}
async join(email: string, nickname: string, password: string) {
const user = this.usersRepository.findOne({ where: { email } });
if (!email) {
throw new HttpException('이메일이 없습니다.', 400);
}
if (!nickname) {
throw new HttpException('닉네임이 없습니다.', 400);
}
if (!password) {
throw new HttpException('비밀번호가 없습니다.', 400);
}
if (user) {
throw new HttpException('이미 존재하는 사용자입니다.', 400);
}
const hashedPassword = await bcrypt.hash(password, 12);
await this.usersRepository.save({
email,
nickname,
password: hashedPassword,
});
}
}
// a-nest/src/entities/Users.ts
import {
Column,
Entity,
Index,
OneToMany,
PrimaryGeneratedColumn,
} from "typeorm";
import { Channelchats } from "./Channelchats";
import { Channelmembers } from "./Channelmembers";
import { Dms } from "./Dms";
import { Mentions } from "./Mentions";
import { Workspacemembers } from "./Workspacemembers";
import { Workspaces } from "./Workspaces";
@Index("email", ["email"], { unique: true })
@Entity("users", { schema: "sleact" })
export class Users {
@PrimaryGeneratedColumn({ type: "int", name: "id" })
id: number;
@Column("varchar", { name: "email", unique: true, length: 30 })
email: string;
@Column("varchar", { name: "nickname", length: 30 })
nickname: string;
@Column("varchar", { name: "password", length: 100 })
password: string;
@Column("datetime", { name: "createdAt" })
createdAt: Date;
@Column("datetime", { name: "updatedAt" })
updatedAt: Date;
@Column("datetime", { name: "deletedAt", nullable: true })
deletedAt: Date | null;
@OneToMany(() => Channelchats, (channelchats) => channelchats.user)
channelchats: Channelchats[];
@OneToMany(() => Channelmembers, (channelmembers) => channelmembers.user)
channelmembers: Channelmembers[];
@OneToMany(() => Dms, (dms) => dms.sender)
dms: Dms[];
@OneToMany(() => Dms, (dms) => dms.receiver)
dms2: Dms[];
@OneToMany(() => Mentions, (mentions) => mentions.sender)
mentions: Mentions[];
@OneToMany(() => Mentions, (mentions) => mentions.receiver)
mentions2: Mentions[];
@OneToMany(
() => Workspacemembers,
(workspacemembers) => workspacemembers.user
)
workspacemembers: Workspacemembers[];
@OneToMany(() => Workspaces, (workspaces) => workspaces.owner)
workspaces: Workspaces[];
}
서버 실행 후 http://localhost:3002/api/users URL로 빈 값을 POST로 보내면 콘솔창에 400 이메일이 없습니다.
라는 문구가 뜬 이후에
C:\Users\xxx\Documents\Project\NestProject\a-nest\src\data-source\DataSource.ts:448
if (!metadata) throw new EntityMetadataNotFoundError(target)
^
EntityMetadataNotFoundError: No metadata for "Users" was found.
at DataSource.getMetadata (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\data-source\DataSource.ts:448:30)
at Repository.get metadata [as metadata] (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\repository\Repository.ts:53:40)
at Repository.findOne (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\repository\Repository.ts:597:42)
at UsersService.join (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\users\users.service.ts:13:39)
at UsersController.join (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\users\users.controller.ts:37:29)
at C:\Users\xxx\Documents\Project\NestProject\a-nest\node_modules\@nestjs\core\router\router-execution-context.js:38:29
at processTicksAndRejections (node:internal/process/task_queues:95:5)
위와 같이 EntityMetadataNotFoundError에러가 발생합니다. DB 커넥션 부분도 확인해보고, entities 부분이 문제인가 싶어 아래와 같이 변경도 해보았지만
TypeOrmModule.forRoot({
entities: ['./entities/*.{js,ts}'],
],
해결되지 않아 질문드립니다.
추가적으로 \data-source\DataSource.ts 부분과
\repository\Repository.ts부분은 실제 디렉토리에 없는 것들인데 왜 뜨는지도 모르겠습니다.
해결 방법이 있을까요?
답변을 작성해보세요.
0
조현영
지식공유자2024.01.12
에러가 throw되면 interceptor나 exceptionFilter에 걸려야하는데요. UndefinedToNull인터셉터와 글로벌 필터 코드 보여주세요
CB S
질문자2024.01.15
// undefinedToNull.interceptor.ts
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { map, Observable } from 'rxjs';
@Injectable()
export class UndefinedToNullInterceptor implements NestInterceptor {
intercept(
context: ExecutionContext,
next: CallHandler<any>,
): Observable<any> | Promise<Observable<any>> {
return next
.handle()
.pipe(map((data) => (data === undefined ? null : data)));
}
}
혹시 글로벌 필터 코드가 httpException.filter.ts을 의미 하시는걸까요?
// httpException.filter.ts
import { Catch, HttpException } from '@nestjs/common';
@Catch(HttpException)
export class HttpExceptionFilter {
catch(exception, host) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
const err = exception.getResponse() as
| string
| { error: string; statusCode: 400; message: string[] };
console.log(status, err);
// response.status(status).json({
// statusCode: status,
// timestamp: new Date().toISOString(),
// path: request.url,
// });
}
}
0
인프런 AI 인턴
2024.01.12
안녕하세요, 인프런 AI 인턴입니다. CB S님,
제공해주신 정보를 바탕으로 살펴보았을 때, EntityMetadataNotFoundError
는 TypeORM이 데이터베이스 테이블과 연결될 엔티티의 메타데이터를 찾을 수 없을 때 발생하는 오류입니다. 이 문제는 대개 엔티티 파일의 위치가 잘못되었거나, TypeOrmModule
에 엔티티를 잘못 등록했을 때 발생합니다.
질문에 있으신 코드와 에러 메시지에서 확인할 수 있는 몇 가지 지점은 아래와 같습니다:
entities
의 경로가 문자열로 처리되고,.ts
와.js
둘 다 포함되어 있으나, 실제 애플리케이션을 실행하는 환경(개발환경 또는 프로덕션)에서 올바르게 해석되지 않을 가능성이 있습니다. 실제 개발 환경에서는.ts
파일로 작업하며, 빌드 후 프로덕션 환경에서는.js
로 변환되기 때문입니다.\data-source\DataSource.ts
와\repository\Repository.ts
부분이 실제로 없다고 하셨는데, 이는 TypeORM이 내부적으로 사용하는 파일들입니다. 디렉토리에 직접적으로 존재하지 않아도 TypeORM이 작업을 수행하면서 런타임에 참조하는 것일 수 있습니다.
해결 방법으로는 다음과 같은 접근을 시도해보실 수 있습니다:
entities
경로를 절대경로로 제공하거나, 애플리케이션이 실행되는 환경에 맞게 확장자를 명확하게 지정해보세요.
- 만약 빌드 후
.js
파일들이 위치한dist
디렉토리를 참조해야 한다면, 해당 디렉토리 경로를 정확하게 지정해주셔야 합니다.
유사한 문제를 해결한 다른 질문들을 참고하셔도 좋을 것 같습니다:
DB 생성시 Error: Cannot find module ‘./index.js가 계속 뜨는데 뭐가 문제인가요??
- 이 질문에서는 경로 문제로 인해 모듈을 찾지 못하는 상황이 발생했으며, 제로초 강사님이 해당 문제를 해결하기 위해 구체적인 경로 수정 방법을 제시하셨습니다.
- 이 질문에서는 경로 문제로 인해 모듈을 찾지 못하는 상황이 발생했으며, 제로초 강사님이 해당 문제를 해결하기 위해 구체적인 경로 수정 방법을 제시하셨습니다.
typeorm을 통해 db 생성을 하려고 하는데 에러가 발생합니다.
- 이 경우에는 TypeORM 설정 시 entities에 대한 올바른 등록이 필요했었습니다.
- 이 경우에는 TypeORM 설정 시 entities에 대한 올바른 등록이 필요했었습니다.
-
- 환경변수 에러 관련 질문으로, 모듈 참조 방식이나 환경변수 설정에 관한 해결책이 제시되었습니다.
- 환경변수 에러 관련 질문으로, 모듈 참조 방식이나 환경변수 설정에 관한 해결책이 제시되었습니다.
기술적인 문제 해결의 경우, 상황에 따라 다양한 요소를 검토해야 하므로 질문 내용에서 제시된 내용만으로는 정확한 원인을 파악하기 어려울 수 있습니다. 따라서 위의 내용을 참고해보시되, 문제가 해결되지 않는다면 추가적으로 강의 내용을 검토하시거나 직접 강사님께 상세한 상황을 설명하신 후 보다 정확한 답변을 받으실 수 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
CB S
질문자2024.01.12
app.module.ts부분 중 아래와 같이 entities를 가져오는 부분을 수정했습니다.
@Module({
...
entities: [
Users,
Channels,
Dms,
Channelchats,
Mentions,
Channelmembers,
Workspacemembers,
Workspaces,
],
...
}
서버는 끊기지 않았지만
400 이메일이 없습니다.
query: SELECT `Users`.`id` AS `Users_id`, `Users`.`email` AS `Users_email`, `Users`.`nickname` AS `Users_nickname`, `Users`.`password` AS `Users_password`, `Users`.`createdAt` AS `Users_createdAt`, `Users`.`updatedAt` AS `Users_updatedAt`, `Users`.`deletedAt` AS `Users_deletedAt` FROM `users` `Users` LIMIT
1
콘솔창에 위와 같이 떴고, POSTMAN에서는 Sending request...가 뜨면서 무한 로딩에 걸렸습니다.
답변 2