이 프로젝트를 배포해서 실서비스로 사용할 수 있나요?
미해결
따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
새로운 기능을 붙여서 배포해 서비스하려고 합니다. 예외처리 같은 것을 추가해서 배포해도 문제가 없을까요?
- react
- node.js
- postgresql
- docker
- typescript
- 클론코딩
- next.js
173만명의 커뮤니티!! 함께 토론해봐요.
미해결
따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
새로운 기능을 붙여서 배포해 서비스하려고 합니다. 예외처리 같은 것을 추가해서 배포해도 문제가 없을까요?
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
vscode에서 계속 오류 떠서 playground에서 보내보았는데 server cannot be reached가 계속 뜨면서 docs도 무한 로딩중이에요 ㅠ
미해결
실습으로 배우는 선착순 이벤트 시스템
강의 잘 듣고 있습니다. 질문사항이 두개 있습니다. 1. 4강의 [문제점] 영상에서 쿠폰생성 10000개 요청으로 인해 mysql이 1분에 100개의 insert가 가능하다고 가정할 시 '주문생성/회원가입요청이 타임아웃 또는 10분뒤에 실행' 된다고 하셨는데요. 예제로 사용하신 Kafka 사용 예제에서는 Consumer 프로젝트도 어차피 API프로젝트와 같은 DB 를 바라보고 있으므로, 어차피 Kafka를 사용하여도 '주문생성/회원가입요청이 타임아웃 또는 10분뒤에 실행'되지 않나요? 왜 여쭤보냐면, 강의 내에서 Kafka 미사용시 주문생성/회원가입요청의 타임아웃 및 10분뒤 실행에 대한 해결책을 Kafka로 사용하셔서 문의드립니다. 2. 5강의 [Consumer 사용하기] 영상을 보면 API 프로젝트 Consumer 프로젝트가 별개로 존재합니다. 그러므로 API프로젝트의 테스트 케이스가 종료되어도 Consumer 프로젝트는 이미 Kafka로 100개의 데이터가 스트림으로 들어오는 상태이므로, 테스트케이스가 종료 되어도(즉, API프로젝트가 종료되어도) Cunsumer 프로젝트는 종료가 되지 않은 상태 이므로 100개의 쿠폰이 DB에 생성 이 되어야 하는게 아닌지요? 왜 여쭤보냐면, 강의 내에서는 API프로젝트가 종료되면 Consumer 프로젝트도 작업이 멈추는 현상이 있어서 문의드립니다.
해결됨
Next.js 시작하기(feat. 지도 서비스 개발)
안녕하세요 강의 정말 잘 듣고있습니다! SSG가 SSR보다 사용자 경험이 좋은건 이해했습니다! 근데 한가지 더 의문점인건 SSG가 아니고 SSR을 선택해야하는 케이스가 있을까요? 라는 의문이 듭니다! 예를 들면 검색결과 페이지라던가 매번 매순간 페이지의 내용이 달라지는 페이지라면 SSG가 아니고 SSR로 만드는게 더 적합한 그런 케이스가 실무에서 있을까요?
해결됨
인터페이스는 일단 객체를 못만든다고 알고 있어요 근데 익명이너클래스를 이용해서 만드는 방법이 있던데 interface A{ abstract void abc(); } 이거를 A a = new A(){ public void abc(){.....} }; 이렇게 할 수 있던데 익명이너클래스에 인터페이스를 상속해서 abstract메서드를 오버라이딩 했기때문에 가능하다는 건 알겠는데 그러면 객체는 익명이너클래스의 객체 아닌가요...? 익명객체가 인터페이스A를 상속받았기때문에 다형적인 표현으로 A a 이렇게 표현이 가능한건가요? 저런 표현이 가능한가요? 참조변수 a는 인터페이스A 타입인 객체를 가리킨다는 뜻 아닌가요..? 근데 인터페이스는 객체를 못만든다고 배웠는데.. ㅠㅠㅠ 정말 이 부분이 이해가 안 갑니다 ㅠㅠㅠ 왜 객체를 인터페이스 타입으로 지칭하는지 ㅠㅠ
해결됨
[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요, 좋은 강의 감사드립니다. 제가 좋아요 기능구현을 해보고 있는데, 클릭이 되면 state(clicked)를 통해 true로 만들어서 빨강색으로 만들고 1를 추가시키고 다시 클릭하면 false가 되면서 검게 되고 1을 감소하게 하는 기능을 구현하려고 하는데요. 각각 빨/검 1추가시키기는 되는데 둘이 합치려니까 1을 올리면서 리렌더링이 되고 clicked라는 스테이트가 바로 false로 초기화되버리는것 같습니다. 혹시 방법이있을까요? 뭐라고 검색해야 할지 감이 잘안잡혀서 질문남깁니다. const Heart = ({ pageId, id, currentIndex, postId, }) => { const dispatch = useDispatch(); const { coursePosts } = useSelector((state) => state.coursePost); const { clicked, setClicked } = useState(false); const heart = coursePosts[currentIndex].CourseReview[id].heart; const onClickHeart = () => { if (!clicked) { dispatch(coursePostActions.clickCourseReviewHeart({ pageId, postId })) } else { dispatch(coursePostActions.clickCourseReviewHeartAgain({ pageId, postId })) } setClicked(!clicked); } return ( <button type="button" onClick={onClickHeart} className={clicked === true ? styles.active : ""}> <FontAwesomeIcon icon={faHeart} /> <span>{heart}</span> </button> ); }; export default CourseReviewItems; const coursePostSlice = createSlice({ name: "coursePost", initialState, reducers: { clickCourseReviewHeart(state, action) { const postIndex = state.coursePosts.findIndex((v) => v.id === Number(action.payload.pageId)); const reviewIndex = state.coursePosts.findIndex((v) => v.id === action.payload.postId); state.coursePosts[postIndex].CourseReview[reviewIndex].heart += 1 }, clickCourseReviewHeartAgain(state, action) { const postIndex = state.coursePosts.findIndex((v) => v.id === Number(action.payload.pageId)); const reviewIndex = state.coursePosts.findIndex((v) => v.id === action.payload.postId); state.coursePosts[postIndex].CourseReview[reviewIndex].heart -= 1 } }
미해결
[리뉴얼] React로 NodeBird SNS 만들기
{commentFormOpened && ( <div> {commentEditMode ? <CommentContent post={post} commentEditMode={commentEditMode} onClickUpdateComment={onClickUpdateComment} onCancelUpdateComment={onCancelUpdateComment} /> : ( <> <CommentForm post={post} /> <CommentContent post={post} commentEditMode={commentEditMode} onClickUpdateComment={onClickUpdateComment} onCancelUpdateComment={onCancelUpdateComment} /> </> ) } </div> )} //PostCard.js import React, { useCallback, useEffect, useState } from 'react'; import { Avatar, Comment, List, Input, Button, Popover } from 'antd'; import { useDispatch, useSelector } from 'react-redux'; import Link from 'next/link'; import PropTypes from 'prop-types'; import { EllipsisOutlined } from '@ant-design/icons'; import { UPDATE_COMMENT_REQUEST } from '../reducers/post'; const {TextArea} = Input; const CommentContent = ({ post, onCancelUpdateComment, commentEditMode, onClickUpdateComment }) => { const dispatch = useDispatch(); const id = useSelector((state) => state.user?.me.id); const { updateCommentLoading, updateCommentDone } = useSelector((state) => state.post); const [editText, setEditText] = useState(post.Comments.content); useEffect(() => { if (updateCommentDone) { onCancelUpdateComment(); } }, [updateCommentDone]); const onChangeCommentText = useCallback((e) => { setEditText(e.target.value); }, []); const onChangeComment = useCallback(() => { dispatch({ type: UPDATE_COMMENT_REQUEST, data: { PostId: post.id, CommentId: post.Comments.id, UserId: id, content: editText, }, }); }, [post, id, editText, post.Comments.id]); return ( <div> {commentEditMode ? ( <> <TextArea value={editText} onChange={onChangeCommentText} /> <Button.Group> <Button loading={updateCommentLoading} onClick={onChangeComment}>수정</Button> <Button type="danger" onClick={onCancelUpdateComment}>수정 취소</Button> </Button.Group> </> ) : <List header={`${post.Comments.length}개의 댓글`} itemLayout="horizontal" dataSource={post.Comments} renderItem={(item) => ( <li> <Comment actions={[<Popover key="more" content={ <Button.Group> {id && item.User.id === id ? ( <> <Button onClick={onClickUpdateComment}>수정</Button> <Button type="danger"> 삭제 </Button> </> ) : ( <Button>신고</Button> )} </Button.Group> } > <EllipsisOutlined /> </Popover>,]} author={item.User.nickname} avatar={ <Link href={`/user/${item.User.id}`}> <a><Avatar>{item.User.nickname[0]}</Avatar></a> </Link> } content={item.content} /> </li> )} /> } </div> ) } CommentContent.propTypes = { post: PropTypes.shape({ id: PropTypes.number.isRequired, Comments: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.number.isRequired, content: PropTypes.string.isRequired, })) }), onCancelUpdateComment: PropTypes.func.isRequired, onClickUpdateComment: PropTypes.func.isRequired, commentEditMode: PropTypes.bool }; CommentContent.defaultsProps = { commentEditMode: false, } export default CommentContent; //CommentContent.js case UPDATE_COMMENT_REQUEST: draft.updateCommentLoading = true; draft.updateCommentDone = false; draft.updateCommentError = null; break; case UPDATE_COMMENT_SUCCESS: draft.updateCommentLoading = false; draft.updateCommentDone = true; const post = draft.mainPosts.find((v) => v.id === action.data.PostId); post.Comments = post.Comments.find((v) => v.id === action.data.CommentId); post.Comments = post.Comments.find((v) => v.id === action.data.UserId); post.Comments.content = action.data.content; break; case UPDATE_COMMENT_FAILURE: draft.updateCommentLoading = false; draft.updateCommentError = action.error; break; //reducers/post.js function updateCommentAPI(data) { return axios.patch(`/post/${data.PostId}/comment`, data); } function* updateComment(action) { try { const result = yield call(updateCommentAPI, action.data); yield put({ type: UPDATE_COMMENT_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ type: UPDATE_COMMENT_FAILURE, error: err.response.data, }); } } // sagas/post.js router.patch('/:postId/comment', isLoggedIn, async (req, res, next) => { // PATCH post/2/comment try { await Comment.update({ content: req.body.content, }, { where: { PostId: req.params.postId, UserId: req.user.id, }, }); res.status(200).json({ PostId: parseInt(req.params.postId, 10), UserId: req.user.id, content: req.body.content, }); } catch (error) { console.error(error); next(error); } }); //routes/post.js 이렇게 PostId, UserId, content가 보내지고, 실패가 뜨면서 새로고침을 하면 해당 글에 달았던 댓글들이 모두 다 "zzz"로 변경되어 있습니다. 그래서 CommentId를 보내줘야 될 거 같은데 여기서 막혀서 감이 도무지 잡히질 않습니다.
미해결
스프링 시큐리티
안녕하세요 강의 잘 듣고 있습니다! SecurityConfig에서 커스텀 필터 등록 시 @Bean 형식으로 필터객체를 생성하여 등록하면 ApplicationFilterChain에 등록되는게 맞는걸까요? Bean 만 선언한다면 ApplicationFilterChain 에 등록되고 addFilter(customFilter) 를 추가해주면 ApplicationFilterChain 리스트에도 등록되고 SecurityFilterChain 에도 등록이 됩니다. 문제는 제가 만든 커스텀 필터는, 특정 URL 에서는 동작 안하게끔 구현하고 싶은데 @Bean으로 등록했기 때문에 ApplicationFilterChain에 등록되어 어떤 요청이 들어오든 동작하는 게 문제입니다. @Bean 방식이 아닌 addFilter(New CustomFilter()) 로 하면 SecurityFilterChain에만 등록되긴 하는데 CustomFilter 는 스프링 컨테이너에 등록이 안되기 때문에 다른 Resource 객체들을 주입받지 못하는 상황입니다. 결론은 ApplicationFilterChain에는 추가 안하고 SecurityFilterChain에만 커스텀 필터를 추가하고 싶은데 New 방식 말고는 없는 것인지가 궁금합니다!
해결됨
Next.js 시작하기(feat. 지도 서비스 개발)
강의후반부에 window 에 접근하는 상황인 NoSSR 을 수강하면서 해당 상황이 어떤 케이스인지 확인차 질문 남깁니다. Next 에서 window 나 document 같이 WebAPI 에 기재된 객체들에 접근하는 코드를 쓸 때 백엔드 단에서 접근이 불가하니, dynamic 을 사용한다 정도로 이해하면 되려나요?.? 이와는 다르게, useEffect 의 경우 브라우저에서 렌더가 될 때 코드가 돌아가니까 WebAPI 에 접근이 가능하다 정도로 이해하면 되려나요?.?
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
섹션 8 강의 1:02:21 부분에서 문제가 발생했습니다 ㅠ utility type을 배우기 전 이렇게 해놨을 때는 문제가 없었습니다. 근데 강의처럼 바꾸어주니까 문제가 발생했고 IBoardWriteUIProps의 data 뒤에 물음표 때문인가해서 물음표를 주니까 container는 괜찮아 졌는데 presenter에서는 아직 defaultValue에 문제가 있다고 표시가됩니다.. data?.fetchBoard.writer -> data?.fetchBoard?.writer 이런식으로 바꿔줘도 defaultValue에 문제 발생... 분명 이렇게 타입명시를 잘 해줬는데 왜 강의처럼 안되는 건지 모르겠습니다..
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
안녕하세요. 기존에는(강의 듣기전) visual studio 2019 버전 C++로 코드를 작성하고 F10, F5 등으로 한줄씩 디버깅을 진행했던 경험이 있습니다. 그런데 프론트엔드쪽에 관심을 가지면서 해당 강의를 수강하고 있는데, visual studio code를 통해 html, css와 javascript 역시 F10과 F5를 활용하면 한줄씩 디버깅하면서 해당 변수에 어떠한 값이 할당되는지 알 수 있을까요? 예를 들면 싸이월드 만들기 4탄에서 javascript를 통해 끝말잇기 게임을 만들었는데 해당 javascript의 동작 과정을 한줄씩 디버깅 해보고 싶습니다.
미해결
스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
안녕하세요 김영한님! 강의 아주 잘 듣고있습니다!! 현재 김영한님 첫번째 강의를 다 듣고 저 혼자 만들어보고 싶은게 생겨서 만드는중인데요 현재 제가 군대에 있어서 사지방에서 코딩을 하느라 인텔리제이를 사용하지 못하고 깃허브에서 제공하는 codespaces와 gitpod을 사용하여 vscode 환경에서 코딩하는 중입니다. 근데 jpa의 JpaRepository나 lombok 혹은org.springframework.boot.autoconfigure.SpringBootApplication 이런 패키지들이 계속 does not exist라고 뜹니다. 김영한님꺼 따라할때는 잘 됐는데 이제 제가 혼자서 만들고 싶은거 만드려니 확실하지도 않고 실행도 잘 안돼서 패키지를 못읽는건지도 잘 모르겠습니다. 현재 build.gradle에 의존성도 다 넣어있고 vscode의 패키지 설치에도 java extention pack, lombok, spring extention pack또 다 깔았습니다. 당연 재설치도 해보았구요! 구글링을 지금 며칠째 하고있는데 도저히 안되서 여기에 질문 올려봅니다... springboot version : 3.1.3 jdk version : 17
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
참고 - https://stackoverflow.com/questions/19975954/a-yaml-file-cannot-contain-tabs-as-indentation codegen.yaml 파일에서 들여쓰기를 모두 지우고 띄어쓰기(space 키) 2번씩으로 바꿔주시면 해결됩니다!(plugins와 config는 띄어쓰기 4번, - typescript와 typesPrefix: I 는 띄어쓰기 6번, 이런식으로)
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
섹션8 - graphql-codegen 설치 및 실습과 기타 타입 영상시간 0:18:13 구간에서 yarn add --dev @graphql-codegen/cli 설치 시 에러가 날 경우 해당 프로젝트의 node_modules 를 삭제 yarn install 명령어로 node_modules를 재설치 다시 yarn add --dev @graphql-codegen/cli 로 설치 이렇게 해주면 에러없이 잘 설치가 됩니다! 혼자 검색도 해보고 컴퓨터랑 vscode 껐다켜보기도 하고 여러 시도 끝에 겨우 해결했네요 ㅠ 다른 수강생분들은 저처럼 시간낭비하지 않으시길 바라겠습니다!
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
강사님 안녕하세요~! 자유게시판의 댓글 기능과 중고마켓의 댓글 기능을 리팩토링하면서 공통으로 뺄 수 있는 부분은 최대한 빼보려고 하고 있는데요. 댓글생성, 댓글수정 등등 각각의 뮤테이션도 모두 다르고 조건(회원/비회원, 자유게시판/중고마켓) 따라 보여지는 부분도 상당히 달라서 최대한 공통인 부분으로 잘게 쪼개봤는데도 코드 길이가 너무 길어집니다 ㅜㅜ 받아오는 데이터의 타입들도 각기 달라서 점점 더 미궁속으로 빠지고 있습니다 .... 자유게시판과 중고마켓 각 디렉토리에서 댓글 컴포넌트를 만들고 그 안에서 공통 UI 컴포넌트와 사용하는 뮤테이션들을 추가하는 방식으로 하고 있는데 계속 생각해봐도 비효율적이라는 생각이 들어서요 .. 데이터 타입, 뮤테이션, 렌더링 조건 등등이 모두 다른 이런 상황에서 공통으로 기능을 어떻게 빼야할지 조언 부탁드려도 될까요?🥹
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
안녕하세요 강사님 ! 로그인한 회원이 자유게시판에 글을 쓸 때 작성자가 존재하지 않는다는 오류가 나옵니다. 피그마 화면에 작성자와 비밀번호 인풋이 없어서 똑같이 비회원일 때만 보여주도록 했고 뮤테이션을 날릴 때에도 필수값이 아니라 비회원 글작성 뮤테이션을 똑같이 썼습니다. 그런데 작성자가 존재하지 않는다는 오류가 나요. 플레이그라운드에서 토큰을 넣고 똑같이 시도해봤는데 CreateBoardInput 에 작성자랑 비밀번호를 다 넣어줘야 정상적으로 등록이 되더라구요. 타입을 보면 필수가 아닌데.. 제가 놓친 부분이 어디인지 잘 모르겠습니다 ㅠㅠ 강의는 완강했습니다! +댓글등록도 해보는데 댓글은 작성자가 없다는 오류 없이 정상적으로 등록되지만 user 정보가 같이 저장되지 않습니다. 저는 토큰에서 user 정보를 알아서 가져가는 줄 알았는데 그게 아닌건지, 그게 맞는데 제 코드가 잘못된건지 모르겠습니다 😂
해결됨
[신규 개정판] 이것이 진짜 크롤링이다 - 실전편 (인공지능 수익화)
안녕하세요 뉴스크롤링에서 크롤링 하고자 하는 뉴스의 기간을 정해주려면 response = requests.get(" https://search.naver.com/search.naver?where=news&sm=tab_jum&query=검색어 ") 위 코드의 " " 안에 뉴스기간을 옵션으로 설정하여 검색한 페이지의 URL을 긁어서 넣어주면 되는걸지요? 감사합니다.
미해결
스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예 [질문 내용] 여기에 질문 내용을 남겨주세요. 최초로 jdbc:h2:~/test로 연결을 실행 한 뒤 ~/ test.mv .db 파일 생성을 확인하였습니다. 그러고 영한님께서 말씀해주신 대로 jdbc:h2:tcp://l ocalhost/~/test 로 연결했더니 다음과 같은 오류가 발생하네요.. 해결방안 답변해주시면 감사하겠습니다. 참고로 h2 버전은 강의와 같은 버전을 사용하였습니다. +) 추가로 삭제 후 동일버전, 하위버전으로 재설치도 해보았는데 여전히 같은 오류가 발생합니다.
해결됨
[리뉴얼] React로 NodeBird SNS 만들기
강의 들은 부분을 툴킷으로 다시 만들어보는중 SSR 적용하는 부분 질문있습니다. 초기 로딩후 로그인은 정상적으로 동작하는데요 새로고침하고 로그인 풀린 화면이 나오고 다시 로그인하면 로그인되지 않습니다. 코드는 다음과 같이 작성했습니다. // toolkit/index.ts import axios from 'axios'; import userSlice, { UserInitialState } from './user'; import postSlice, { PostState } from './post'; import { AnyAction, CombinedState } from '@reduxjs/toolkit'; import { combineReducers } from 'redux'; import { HYDRATE } from 'next-redux-wrapper'; axios.defaults.baseURL = 'http://localhost:3065'; axios.defaults.withCredentials = true; export interface IState { user: UserInitialState; post: PostState; } const rootReducer = ( state: IState, action: AnyAction ): CombinedState<IState> => { switch (action.type) { case HYDRATE: return action.payload; default: { const combinedReducer = combineReducers({ user: userSlice.reducer, post: postSlice.reducer, }); return combinedReducer(state, action); } } }; export default rootReducer; 툴킷에 HYDRATE를 적용하고 // store/configureStore.ts import { AnyAction, Reducer, configureStore } from '@reduxjs/toolkit'; import { createWrapper } from 'next-redux-wrapper'; import rootReducer, { IState } from '../toolkit'; const makeStore = () => configureStore({ reducer: rootReducer as Reducer<IState, AnyAction>, devTools: true, middleware: (getDefaultMiddleware) => getDefaultMiddleware(), }); export default createWrapper<AppStore>(makeStore, { debug: process.env.NODE_ENV !== 'production', }); export type AppStore = ReturnType<typeof makeStore>; export type RootState = ReturnType<typeof rootReducer>; export type AppDispatch = AppStore['dispatch']; 리덕스 래퍼 부분은 저렇게 만들고 //pages/index.tsx export const getServerSideProps: GetServerSideProps = wrapper.getServerSideProps((store) => async ({ req }) => { const cookie = req ? req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; if (req && cookie) { axios.defaults.headers.Cookie = cookie; } await store.dispatch(loadPostAction()); await store.dispatch(loadUserAction()); }); export default Home; // toolkit/user.ts export const loadUserAction = createAsyncThunk( 'user/loadUser', async (data) => { const response = await axios.get(`/user/${data}`); return response.data; } ); .addCase(loadUserAction.fulfilled, (draft, action) => { draft.loadUserLoading = false; draft.loadUserDone = true; draft.me = action.payload || null; }) 툴킷쪽은 이런식으로 작성했습니다.
해결됨
자바 ORM 표준 JPA 프로그래밍 - 기본편
안녕하세요. 현재 JPA강의를 통해 회사내 프로젝트중인 직장인 입니다. 실무 중에 강의의 복합키 매핑과는 조금 다른 내용이 있어 며칠을 고민하다 문의 드립니다. 각각 복합키를 가진 두 개의 테이블 이 있습니다. 두 테이블은 code라는 공통 컬럼이있고 다대일관계로 매핑 을 구성하려고 합니다. @EmbeddedId관계 를 이용해 구성하려고 합니다. code 컬럼만 매핑시키는 방법을 찾지 못해 문의 남겨드립니다. 현재 문제의 테이블입니다.(회사프로젝트 테이블이라 자세히 올려드리는 못하는 점 양해 부탁드립니다.) Company Table은 code, biznumber 두 개의 pk로 구성돼 있습니다. Contract Table 역시 code, module 두 개의 pk로 구성돼 있습니다. 저는 두 테이블에서 code라는 컬럼만 갖고 다대일 매핑 을 구현하고 싶습니다. 즉 복합키를 각각 가진 두 개의 테이블에서 각각 하나의 컬럼만을 이용해 다대일 매핑을 구현하고 싶습니다. 제가 에러 내용과 과정을 올리고싶은데 회사코드라 올리면 문제가 생길까 싶어 이렇게 말로 표현드려 죄송합니다.