사용 팁

1:N 관계 테이블 데이터 저장, 조회하기


지난 편에서는 템플릿을 활용해 예약 목록·등록·수정 화면을 구성하고, 각 화면에 데이터 카테고리를 연결했습니다. 이번 편에서는 그 위에 이벤트와 FlexSQL 서비스를 연결해 참석자를 추가·삭제하고 1:N 관계 데이터를 실제로 저장·조회하는 과정을 다룹니다. 이번 단계는 화면 구성보다 백엔드 관점에서 더 중요한 구간으로 부모 테이블과 자식 테이블을 어떻게 함께 다루는지 이해하는 것이 핵심입니다.

 

영상 강의로 학습하기 👉
사용된 코드 확인하기 👉

 

이벤트 설정 전 체크 포인트

이번 편부터는 스크립트와 서비스 설정이 많아집니다. 이벤트명, 스크립트명, 컬렉션키처럼 직접 타이핑하기 번거로운 값들은 강의자료에서 복사·붙여넣기로 작업하는 것이 가장 안전합니다.

또 하나 중요한 점은 f_ID는 시나리오마다 달라진다는 것입니다.

스크립트 안에 특정 영역을 새로고침하는 코드가 들어갈 때는, 반드시 내 화면의 컴포넌트 ID로 바꿔서 적용해야 합니다. 컴포넌트 선택 후 속성 영역 상단에서 확인할 수 있습니다.

 

📌 f_ID 확인이 필요한 이유

강의자료의 스크립트를 그대로 붙여넣어도, 새로고침 대상 영역의 f_ID가 다르면 화면이 갱신되지 않습니다.
특히 참석자 목록처럼 반복 그룹이 있는 구간은 이 값이 맞아야 추가·삭제 결과가 즉시 보입니다.

 

Step1 : 초기화와 전체 조회 이벤트 설정

Step1에서는 이미 템플릿과 데이터 연결이 끝난 상태이므로 이제 실제로 데이터를 다루는 이벤트를 채워 넣습니다.

① 새 예약 버튼 - initReservation 스크립트 채우기

먼저 새 예약 버튼에 연결된 initReservation 이벤트를 완성합니다. 버튼 클릭 후 이벤트 설정으로 이동한 뒤, 스크립트 액션을 하나 추가하고 코드를 입력합니다. 이 스크립트의 역할은 다음과 같습니다.

  • reservation 카테고리 비우기
  • reservAttendee 카테고리 비우기
  • selectData 카테고리 비우기
  • 회의 종료 기본값이 들어간 빈 섹터 1개 생성

 

📌 왜 세 카테고리를 모두 비우는 이유

사용자가 입력하다가 취소 후 다시 새 예약을 누르면 이전 값이 남아 있을 수 있습니다.
initReservation은 새 입력을 시작할 때 필요한 상태만 남기고 모두 초기화하는 역할을 합니다.

 

② Step1 스텝 이벤트 - queryReservation 서비스 연결

다음은 예약 목록을 조회하는 queryReservation 이벤트입니다.

Step1의 이벤트 설정으로 들어가 서비스를 추가하고 서비스 종류는 FlexSQL로 설정합니다. 이후 스크립트 네임(DEMO_queryReservation)을 등록하고 이전과 동일한 방식으로 SQL을 작성,발행한 뒤 버전을 연결합니다.

  • 보내는 데이터 카테고리명 : reservation
  • 필터 설정 : 없음
  • 받는 데이터 : 화면에 반영하기 사용
  • 카테고리명 : reservation
  • 반영 방식 : 덮어쓰기

 

📌 조회 결과를 왜 '덮어쓰기'로 받는 이유

목록 화면은 항상 최신 전체 목록을 기준으로 다시 그려야 합니다.
누적 저장 방식으로 받으면 기존 데이터와 새 데이터가 섞일 수 있으므로, 전체 목록 조회에서는 덮어쓰기가 맞습니다.

 

Step2 : 입력 화면 진입 시 초기화와 콤보 갱신

이번에는 입력 화면인 Step2의 이벤트를 설정합니다. 이 단계부터는 참석자 추가 기능이 본격적으로 들어갑니다.

① 스텝 이벤트 - step2Init 설정

Step2를 선택하고 이벤트 설정으로 이동한 뒤 스크립트를 추가해 step2Init 코드를 작성합니다.

사실 initReservation이 이미 Step1의 새 예약 버튼에서 초기화를 수행하므로 이 이벤트가 없어도 동작은 가능합니다.
하지만 이번 글에서는 Step2에 진입하는 시점에도 한 번 더 초기화를 두는 방식을 사용합니다.

 

📌 Step2에서도 초기화를 거는 이유

정상 경로라면 Step1의 새 예약 버튼을 통해 들어오지만, 나중에 다른 버튼이나 우회 경로가 생길 수 있습니다. 이런 상황까지 대비하는 것이 방어 코드입니다.

 

② 콤보 컨트롤 닫기 시 - AttendReload 이벤트 설정

참석자 영역의 각 콤보 컨트롤에는 다이얼로그를 닫는 시점에 AttendReload 이벤트가 연결됩니다. 이번 이벤트 역시 스크립트를 추가해 작성합니다.

여기서 중요한 것은 f_ID 변경입니다. 스크립트 안에 갱신 대상 컴포넌트가 들어 있으므로 내 화면의 참석자 관련 영역 f_ID로 바꿔야 합니다.

 

⚠️ f_ID를 바꾸지 않으면 생기는 문제

데이터는 실제로 바뀌었는데 화면만 갱신되지 않아 사용자가 추가/삭제 결과를 바로 확인하지 못할 수 있습니다.

 

참석자 추가 기능 만들기

Step2의 핵심은 참석자 추가입니다. 이번 편에서는 사원 단위로 한 명씩 추가하는 방식과 부서 단위로 여러 명을 한 번에 추가하는 방식 두 가지를 모두 구현합니다.

① 멤버 추가 버튼 - addMemberAttemdee 이벤트 설정

먼저 사원 단위 추가입니다. 멤버 추가 버튼을 클릭한 뒤 이벤트 설정으로 이동하고, 스크립트를 추가합니다.

이 스크립트는 크게 세 단계로 구성됩니다.

  1. 선택된 사원 이름이 없으면 “사원을 선택해 주세요” 토스트 메시지를 띄우고 중단
  2. 이미 참석자 목록에 같은 이름이 있으면 “이미 추가된 참석자입니다” 토스트 메시지를 띄우고 중단
  3. 중복이 아니면 reservAttendee에 참석자를 추가하고 화면 갱신

여기서도 새로고침 대상 영역의 f_ID는 실제 화면에 맞게 수정해야 합니다.

② 그룹 추가 버튼 - addGroupAttendee 이벤트 설정

다음은 부서 단위 일괄 추가입니다. 이 기능은 멤버 추가보다 한 단계 복잡합니다. 왜냐하면 선택한 부서에 누가 속해 있는지는 현재 화면 데이터만으로는 알 수 없고 DB에 다시 물어봐야 하기 때문입니다. 그래서 이 이벤트는 스크립트 - 서비스 - 스크립트 순서로 구성합니다.

 

첫 번째 스크립트 : 그룹 선택 여부 확인

먼저 사용자가 콤보에서 부서를 선택했는지 확인합니다. 선택하지 않았으면 토스트를 띄우고 이벤트를 종료합니다.

 

두번째 서비스 : 부서 소속 멤버 조회

다음으로 서비스를 추가하고 서비스 종류는 FlexSQL로 설정합니다. 스크립트 네임(DEMO_getMemberByGroup)을 작성한 뒤 SQL 작성 화면으로 이동해 쿼리를 등록하고 발행합니다. 이 서비스의 핵심은 보내는 데이터 값을 SQL에서 동적으로 사용하는 것입니다.

FlexSQL에서는 SQL 구문 안의 <% %> 사이에 자바스크립트 표현을 넣을 수 있으므로, 예를 들어 WHERE 절에서 <% sector.groupseq %>처럼 선택된 부서 시퀀스 값을 받아 조건으로 사용할 수 있습니다.

서비스 설정은 다음과 같이 맞춥니다.

  • 보내는 데이터 카테고리명 : selectData
  • 필터 : Active
  • 받는 데이터 카테고리명 : tempMembers
  • 저장 방식 : 덮어쓰기

 

📌 reservAttendee가 아니라 tempMembers를 사용하는 이유 

서비스 조회 결과를 바로 reservAttendee에 덮어쓰면 화면에 이미 추가되어 있던 참석자 목록이 사라질 수 있습니다. 그래서 먼저 임시 카테고리 tempMembers에 받아 둔 뒤 이후 스크립트에서 기존 참석자와 비교하며 필요한 사람만 골라 넣습니다.

서비스 결과를 바로 메인 카테고리에 넣지 않고 임시 카테고리에 받은 뒤 가공해서 반영하는 방식은 중복 제거, 병합, 조건 필터링이 필요한 경우 매우 유용합니다.

 

마지막 스크립트 : 중복 제거 후 reservAttendee 반영

서비스로 받아온 tempMembers를 순회하면서 이미 들어 있는 참석자는 건너뛰고 새로운 멤버만 reservAttendee에 추가합니다.
이 단계에서도 화면 갱신 코드가 들어가므로 참석자 목록 영역의 f_ID를 내 시나리오 값으로 바꿔 적용합니다.

 

참석자 삭제 기능 만들기

참석자를 추가했다면 잘못 넣은 사람을 제거할 수 있어야 합니다. 삭제 기능을 만들어보겠습니다.

removeAttendee 이벤트 설정

참석자 목록 오른쪽의 삭제 버튼에는 removeAttendee 이벤트를 연결합니다. 이 이벤트는 비교적 간단하게 스크립트 1개로 구현할 수 있습니다.

핵심은 Active 상태입니다. 반복 그룹 안에서 특정 행의 삭제 버튼을 누르면 플렉스튜디오는 그 행을 자동으로 Active 상태로 인식합니다. 따라서 스크립트는 현재 Active인 참석자 1건을 기준으로 삭제를 수행하면 됩니다. 삭제 후에는 화면을 갱신합니다.

 

📌 왜 삭제 대상을 별도로 찾지 않아도 되는가?

반복 그룹 안에서는 클릭한 행이 자동으로 Active가 되기 때문입니다. 이 구조를 이해하면 목록형 수정/삭제 기능을 훨씬 간단하게 구현할 수 있습니다.

 

1:N 관계 데이터를 한 번에 저장하기

이제 참석자 추가·삭제가 끝났으니, 실제 DB에 저장할 차례입니다. 하단의 예약 저장 버튼을 사용합니다.

저장 버튼 설정 전 - 필수값 체크 활성화

먼저 예약 저장 버튼에서 필수값 체크하기를 활성화합니다. 이 설정이 켜져 있어야 제목, 날짜, 시간 등 필수 입력값 누락되었을 때 저장되는 걸 방지할 수 있습니다.

saveReservation 이벤트 설정

saveReservation 이벤트는 크게 두 단계입니다.

  1. 필수 입력값 검증
  2. 서비스 호출

이벤트 설정에서 서비스를 추가하고 서비스 종류는 FlexSQL로 지정합니다. 이후 스크립트 네임(DEMO_saveReservation)을 등록하고 SQL 작성 화면에서 SQL을 작성해 발행합니다.

이번 저장 서비스의 핵심은 ParamBlock을 2개 사용하는 것입니다. 서비스 한 번 호출로 부모 테이블 데이터인 예약 정보, 자식 테이블 데이터인 참석자 목록을 함께 전송합니다.

  • ParamBlock1 : reservation
  • 필터 : Active
  • ParamBlock2 : reservAttendee
  • 필터 : 없음

 

📌 1:N 관계 저장의 핵심 원리

먼저 부모 테이블(예약)에 데이터를 저장해 PK를 생성하고 그 PK 값을 자식 테이블(참석자)의 외래키에 넣어 여러 건을 저장합니다. 예를 들어 예약번호가 42로 생성되었다면 참석자 N명 모두의 reservation_seq가 42로 들어가게 됩니다.

저장 서비스 뒤에는 스크립트를 하나 더 추가해 저장 성공 시 토스트 메시지를 띄우도록 합니다. 이번 이벤트에서는 받는 데이터 설정이 필요하지 않습니다. 저장 직후 현재 화면에서 다시 조회하는 구조가 아니라, 직전 스텝으로 돌아간 뒤 Step1의 Loaded 이벤트에서 전체 목록을 다시 조회하기 때문입니다.

 

예약 삭제 기능 만들기

저장이 끝났다면 이제 목록에서 예약을 삭제하는 기능을 구현합니다. Step1의 삭제 버튼에는 이미 confirmDelete 이벤트명이 연결되어 있습니다.

① confirmDelete - 확인 메시지 박스 띄우기

삭제는 되돌리기 어렵기 때문에, 클릭 즉시 삭제하면 안 됩니다. 먼저 confirmDelete 이벤트 설정으로 이동한 뒤 스크립트 액션을 추가하고, 메시지 박스를 띄우는 코드를 작성합니다. 이때 사용자가 취소를 누르면 stop 이벤트를 실행하고 삭제를 누르면 deleteReservation 이벤트를 실행하도록 구성합니다.

② stop 이벤트 만들기

먼저 stop 이벤트를 생성하고 이벤트를 종료하는 간단한 스크립트를 작성합니다.

③ deleteReservation 이벤트 만들기

다음은 실제 삭제를 수행하는 deleteReservation 이벤트입니다. 여기에 서비스를 추가하고 서비스 종류는 FlexSQL로 설정하고 스크립트 네임(DEMO_deleteReservation)을 입력합니다.

이번 SQL의 핵심은 삭제 순서입니다. 먼저 자식 테이블 데이터 삭제하고 부모 테이블 데이터를 삭제합니다.

 

📌 왜 저장할 때와 삭제할 때 순서가 반대인 이유

저장은 부모가 먼저 있어야 자식이 외래키를 참조할 수 있으므로 부모 → 자식 순입니다.
반대로 삭제는 자식이 부모를 참조하고 있으므로 자식 → 부모 순으로 지워야 관계 오류를 피할 수 있습니다.

 

서비스 설정은 다음과 같이 맞춥니다. 여기서 Active 필터는 특히 중요합니다.

  • 보내는 데이터 카테고리명 : reservation
  • 필터 : Active

 

⚠️ 삭제 서비스에 Active 필터가 꼭 필요한 이유

필터를 걸지 않으면 현재 조회된 예약 전체가 삭제될 수 있습니다. 삭제 서비스에서는 반드시 지금 클릭한 1건만 전달되도록 Active를 확인해야 합니다.

 

삭제 후에는 받는 데이터가 필요 없으므로 비워 둡니다. 그리고 마지막으로 후속 스크립트(deleteReservation)를 추가해 DB에서 삭제된 데이터를 화면 목록에서도 제거합니다. 목록 그룹의 f_ID를 실제 값으로 수정해야 합니다.

 

다음 강의 : 수정 화면과 자식 테이블 수정까지 확장하기

이번 편에서는 참석자 추가·삭제, 예약 저장, 예약 삭제까지 구현해 1:N 관계 데이터의 기본 저장 흐름을 완성했습니다.
다음 편에서는 수정 화면에서 기존 데이터를 불러오고 자식 테이블 데이터까지 함께 수정하는 방법을 이어서 다루겠습니다.

 

함께 알아두면 좋은 정보