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 이벤트 설정
먼저 사원 단위 추가입니다. 멤버 추가 버튼을 클릭한 뒤 이벤트 설정으로 이동하고, 스크립트를 추가합니다.
이 스크립트는 크게 세 단계로 구성됩니다.
- 선택된 사원 이름이 없으면 “사원을 선택해 주세요” 토스트 메시지를 띄우고 중단
- 이미 참석자 목록에 같은 이름이 있으면 “이미 추가된 참석자입니다” 토스트 메시지를 띄우고 중단
- 중복이 아니면 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 이벤트는 크게 두 단계입니다.
- 필수 입력값 검증
- 서비스 호출
이벤트 설정에서 서비스를 추가하고 서비스 종류는 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 관계 데이터의 기본 저장 흐름을 완성했습니다.
다음 편에서는 수정 화면에서 기존 데이터를 불러오고 자식 테이블 데이터까지 함께 수정하는 방법을 이어서 다루겠습니다.