프로젝트 시작
- Mendix Academy 에는 Mendix Studio Pro 9.12.4 버전이 올라와 있는데, 최신-_- 의 버전으로 컴버트 해서 올립니다!
현재 기준 : 10.23.0
. 멘딕스 스튜디오 프로 10.23.0 열기
. Import App Package를 클릭합니다.
. 다운로드한 SoccerSquad.mpk 파일을 열기로 클릭합니다.
. 로컬에서 열기로 선택 하고 확인
엔티티를 상속을 하는 이유
Mendix의 상속은 일반화(generalization) 이라고 불리며, 이는 엔티티가 다른 엔티티를 상속받는 것을 말합니다.
다음은 상속의 예 입니다!
. 개는 동물을 상속 받았습니다.
. 자동차는 탈것을 상속받습니다.
. 기밀 유지 계약은 일반 계약을 상속 받습니다.
Mendix의 System 엔티티에도 여러 예제들이 있습니다.
Account 엔티티의 경우 System.User 를 상속 받습니다.
위의 자동차는 탈것을 상속받는것의 예제 구성입니다. ( 기차도 추가됨! )
일반화를 추가하면 ( 상속을 추가하면 ) 특수화된 엔티티 ( 상속을 받은 하위 엔티티 )는 어트리뷰트, 어소시에이션, 이벤트 처리 마이크로플로우, 유효성 검사 규칙 및 기타 속을 모두 받습니다. 이렇게 하므로써, 논리를 재사용하고, 엔티티를 깨끗하게 관리 하고, 에플리케이션을 좀더 편하게 관리할 수 있습니다.
또 다른 예로, 고객은 직원과 동일한 몇가지 특성을 가지므로, Employee 및 Customer 를 일반화 하여 Person 엔티티를 만드는 것이 좋을 수 있습니다. 하지만 고객목록이나 직원목록을 단일목록으로 표현할때 Person을 쓰거나, 어트리뷰트만 이용하기 위해 일반화를 사용하면 안됩니다.
Mendix 의 Generalization 은 코딩에서 추상화나 인터페이스를 사용하듯이 사용하면 안됩니다.
일반화(상속) 구성
특수화 할 엔티티의 속성에 있는 Generalization 에 일반화 엔티티를 설정하면됩니다.
아래 예는 Train 엔티티에 Vehicle 을 지정하는 화면 입니다.
일반화를 사용하여 도메인 모델 확장하기
Adrian의 현재 앱은 각 팀의 팀 구성원만 관리합니다. 각 팀에는 팀을 관리하고 지원하는 직원이 있습니다. 직원은 팀 구성원, 사람과 같지만 코치 인증 및 라이선스 번호와 같은 팀 구성원과 다른 특정 정보를 가지고 있습니다. 이 실습에서는 팀 구성원과 직원을 모두 동등하게 처리하되 특수한 세부 정보를 사용할 수 있도록 상속을 사용하여 직원과 함께 앱을 확장합니다.
1. SoccerSquad 도메인 모델 열기
2. 엔티티 추가 Person , Staff
- Person
- FullName(String/200)
- EmailAddress(String/200)
- Staff
- Function(Enumeration/ Head coach-감독, Assistant coach-수석코치, Coalkeeper coach-골키퍼 코치, Team manager - 팀 매니저, Medical staff - 의료진, Equipment staff 장비담당)
- LicenseNumber(String/200)
3. Staff 와 Player 에 Person을 Generalization 으로 지정합니다. -> EmailAddress 중복 오류가 발생합니다.
4. Player 엔티티의 EmailAddress 속성을 EmailAddressOld 로 변경합니다.
5. Staff_Team 으로 association 을 추가 합니다. ( Staff *-> Team )
6. 엔티티 접근을 셋팅합니다.
- Person & Staff
- Administrator/TeamMember 에
- access
- Allow creating & deleting object
- Full read, full write
- Administrator/TeamMember 에
- Player
- 새로 추가된 속성에
- full read and write
* 스탭 페이지 만들기
Staff 엔티티의 Generalization 으로 Person 지정해서 도메인 모델을 확장했습니다. 이제 Staff 을 추가할 수 있는 페이지를 만들어 봅시다.
1. Team_NewEdit 페이지를 엽니다.
2. Tab Container 에서 오른쪽 클릭해서 탭을 추가합니다. 이름은 스탭으로 합니다.
3. 스탭 탭에 컨테이너를 추가 하고 아래와 같이 설정 합니다.
4. 컨테이너에 create button 을 추가 하고 아래와 같이 구성 한다.
- 엔티티 : Team/Staff_Team/Staff
- Caption : 스탭 추가
- Button style : Success
- Events > On click page : 신규 페이지 추가 - 이름 Staff_NewEdit ( Form horizontal/PopupLayout(Atlas )
- 페이지에 Administrator 와 TeamMember 접근 규칙 추가
5. 컨테이너 아래에 빌딩 블록 List 1 추가
6. 데이터 소스로 Team/Staff_Team/Staff 지정 ( 자동 추가 하지 말것!! )
7. Staff/FullName 이 표시되도록 수정
8. 오른쪽 화살표 버튼(chevron link button) 에 Staff_NewEdit 연결
9. 웹 프로그램 실행
10. Adrian/Mendix123 으로 로그인
11. 스탭을 팀에 추가 해서 확인
* 상속이 DB 구조에 미치는 영향
아래 2개의 엔티티가 별도로 있는경우 고유한 테이블과 고유한 ID를 가지고 있는 상태입니다.
Car 가 Vehicle 을 Generalization 하게 되면, 아래 2가지 변경사항이 생깁니다.
1. Car 의 ID 가 Vehicle 에 동기화 되어서, Vehicle에 Car ID 가 생깁니다.
2. Vehicle에 Car 를 참조하는 컬럼이 추가 됩니다.
Vehicle 개체를 생성하면 참조컬럼은 자신을 참조하게 됩니다.
Car 를 만들면, Vehicle과 Car 에 동일한 ID 로 모두 생성되고, 각 엔티티의 속성이 저장됩니다.
Train 객체를 만들면, 역시 Vehicle 과 Train 에 동일한 ID로 생성되고, 각 고유 엔티티의 속성이 저장됩니다.
즉, 상속을 지정한 엔티티는 부모/자식 두개의 테이블에 저장 됩니다. 두테이블은 동일한 ID를 사용합니다.
런타임 객체는 모든 속성을 포함하는 단일객체 입니다.
* 상속 및 페이지
상속은 두개 이상의 개체 형식이 공통 동작을 공유하고, 동일한 프로세스를 처리하게 할 수 있습니다.
샘플 앱에서 Adrian은 이 기능을 모든 팀선수와 스탭에게 이메일을 통한 알람을 보낼때 이용하려고 합니다.
상속을 이용하면, 부모의 목록을 표시할 수 있습니다. 그리고 자식 엔티티의 특수한 사항은 별도 세부보기를 통해서 확인이 가능하게 됩니다.
Car 엔티티 예시를 살펴보겠습니다. 탈것으로 기본뷰를 만들고 Car, Train 으로 별도 목록 표기가 가능합니다.
** 실습하기 **
1. Person_Overview 페이지를 엽니다.
2. List View 의 데이터 소스로 Person 을 설정합니다.
3. List View 의 내용을 삭제 하고 빌딩블록 List 2 항목을 추가합니다.
4. 텍스트 2개를 각각 Person/FullName, Person/EmailAddress 로 설정합니다.
5. List View 속성에서 Templates 탭을 엽니다.
6. Player, Staff 2개의 템플릿을 추가 합니다.
7. List View 를 오른쪽 클릭해서 Templates > Template for 'Player' 를 선택하고, 내용을 모두 지운 후, 빌딩 블록 List 2 Item 을 추가합니다.
8. 첫번째 텍스트 위젯은 Player/ShirtNumber - Player/Name 으로 설정 하고, 두번째는 Player/EmailAddressOld 로 설정합니다.
9. 7과 같이 해서 Staff 템플릿을 선택하고, 내용 지우고, 빌딩 목록 List 2 Item 으로 합니다.
10. 첫번째 텍스트 위젯은 Staff/FullName - Staff/Function 으로 하고, 두번째는 Staff/EmailAddress 로 표시하도록 합니다.
11. Deploy 후 실행합니다.
12. Adrian/Mendix123 으로 로그인 합니다.
13. 수정한 Person 페이지가 정상인지 확인합니다.
* Object Type decision 사용하기
자식 엔티티를 구별하고 사용하는 방법에 대해 설명합니다. 이렇게 하면 다양한 자식 엔티티와 일치하는 마이크로 플로우를 생성할 수 있습니다.
* Object Type Decision
다음 Microflow 를 검토해 보겠습니다. Vehicle 객체로 시작해서 하위 객체의 편집 페이지를 열어야 합니다.
Vehicle 개체가 상속 대상인지 확인하려면 Object Type decision을 사용할 수 있습니다. Object Type decision 은 녹색 다이아몬드 모양입니다.
- 결정순서
Object Type decision 에는 두개이상의 시퀀스 흐름, 즉 부모 엔티티( Vehicle )와 empty 가 필요 합니다. 모든 자식 엔티티를 쓸 필요는 없습니다.
상속에 따른 결정이니, 자식이 없는 경우 부모의 흐름에 따릅니다. 즉, Car와 Train 은 모두 Vechicle 입니다. Train 이 없다면, Vehicle 로 처리되는 식입니다.
- 모범사례
오류 방지를 위해서 empty 를 항상 선언하세요!
예를 들어, Vehicle 을 검색 했는데, 아무것도 반환되지 않았을 경우 비어있는지 확인하지 않고 Object Type decision을 실행합니다. 따라서 empty 를 확인하고, 오류를 기록해야 합니다.
* Object Casting
자식 엔티티에 접속을 하기 위해서는 엑세스 권한 관련으로 캐스팅을 해야 합니다. 즉 Vehicle 부모 엔티티를 Car 또는 Train 으로 캐스팅을 해야 Car 또는 Traion 의 속성에 접근이 가능합니다.
- 모범 사례
상속을 사용하면, 재사용 가능한 함수를 쉽게 만들 수 있습니다. 자식 엔티티가 새로 생겼을 경우 마이크로 플로우에 쉽게 해당 자식 엔티티의 특수 처리를 추가 할 수 있습니다.
예을 들어, 커밋 후 이벤트를 자식 엔티티 마다 구성할 수 있습니다. 또한 모든 부모 엔티티에 대한 처리를 추가 해서 공통 흐름을 만들 수도 있어, 일관성과 유지 관리 용이성이 크게 향상됩니다.
*** 실습 ***
* Object Type Decision 을 사용하여 다른 편집 페이지를 열기
List View 에서 행을 클릭하면, 자식 엔티티에 따라 해당 하는 편집페이지가 열리도록 구현합니다.
1. Person_Overview 를 오픈합니다.
2. List View 를 더블클릭 하여, on click 에 call micro flow 를 선택합니다. 그리고 신규로 ACT_Person_OpenEditPage 를 만듭니다.
3. ACT_Person_OpenEditPage 를 오픈합니다.
4. Object Type decision 을 추가합니다. ( 녹색 다이아몬드 ) 그리고 입력객체로 Person 을 선택합니다.
5. 처음 하나의 빨간색 시퀀스 흐름에 오른쪽 클릭하고 SoccerSquad.Person 을 선택합니다.
6. 두개의 end event(빨간동그라미) 를 추가해서, 각각 SoccerSquad.Player, SoccerSuad.Stff 로 설정합니다.
7. Object Type decision 아래쪽에 end event 를 추가합니다. 자동으로 empty 로 됩니다.
아래 모양과 같아야 합니다.
8. SoccerSquad.Person 시퀀스 flow 에 activity 를 추가합니다.
Show Page Activity 를 추가하고 전달할 객체로 Person 을 선택합니다.
9. Page 에 신규로 해서 Person_NewEdit, PopupLayout , Form Horizontal 을 선택합니다.
10. SoccerSquad.Player 시퀀스 flow activity를 추가합니다.
Cast 를 추가하고 객체 이름을 Player 로 합니다. Show Page 를 추가하고 페이지는 Player_NewEdit를 설정합니다.
11. SoccerSquad.Staff 시퀀스 flow에 activity 를 추가합니다.
10과 동일하게 하면됩니다. Staff 으로만 바꿉니다.
12. 권한으로 Administrator 와 TeamMember 를 추가합니다.
최종 마이크로플로우 모습입니다.
13. deploy 해서 앱실행을 합니다.
14. Adrian/Mendix123 로 로그인합니다.
15. 편집 테스트를 해봅니다!
* 상속 vs 로직에서 1-1 사용
상속보다 1-1 관계가 더 나은 경우를 알아봅시다.
상속은 다른 개체의 자식을때 사용됩니다. 그리고 항상 단일 객체로 사용되고 처리됩니다. Vehicle 과 Car 그리고 Person 과 Player, Staff 에 대해서 구현했습니다.
Adrian이 팀별로 로고를 추가해서 확장하는 경우를 생각해보겠습니다. Team 엔티티가 Image 엔티티를 상속하도록 설정하는 것과 별도의 이미지 엔티티를 만들어 이미지를 업로드 하는 방법입니다.
* "is" vs "has"
-. 자식 엔티티가 부모의 엔티티의 전문화 버전이 맞습니까?
-. 전문화된, 즉 자신 엔티티가 부모의 속성, 연결, 동작을 항상 사용해야만 합니까?
이것을 Vehicle 과 Person 상황에서는 '예'가 될것입니다. Vehicle 의 무게와 색상도 Car 의 속성이며, 무게와 색상이 없는 Car는 없습니다. 또는 Person 전체이름과 이메일주소도 Player와 Staff 의 속성이고 전체이름이 없는 Player는 없습니다.
하지만, 이것을 Team 과 Logo 의 경우에 적용하면 '아니오' 가 됩니다. Logo 가 모든 경우에 Team이 필요한 것은 아닙니다. Team 데이터를 사요할때 Logo가 필요하지 않은 경우가 많습니다. Team은 항상 Logo로 표시되어야 한다고는 말할 수 있습니다. Team 성과에 대한 보고서를 실행하고 마이크로플로우를 통해 Team 데이터를 가져오기 시작할때 Logo는 필요하지 않습니다. 따라서 Team 은 Logo 를 가지지만(has) Team이 Logo 이다(is)는 맞지 않습니다.
따라서 가장 좋은 방법은 이미지를 업로드하고 저장하기 위해 Logo 엔티티가 System.Image를 상속하는 것입니다. 그런 다음 Team과 Logo 엔티티 사이에 1-1 연결을 추가하여 각 Team이 Logo를 가질 수 있도록 합니다.
* 영향
상속과 1-1 연결 사이에는 큰 차이가 있습니다. 주요 차이점은 상속은 "is" 관계인 반면 1-1 연결은 "might have" 관계라는 것입니다. "is" 관계는 Car 가 Vehicle의 한 유형임을 의미하고, "might have" 관계는 Team이 Logo를 가질 수 있지만 필수는 아님을 의미 합니다.
- 데이터 베이스
상속을 처리할 때 두 엔티티는 데이터베이스에 두개의 테이블이 있는 단일 엔티티를 나타냅니다. 두 테이블은 부모 엔티티와 자식 엔티티 입니다.
이에 비해 1-1 관계는 하나로 사용할 수 있는 두개의 엔티티 입니다. 1-1 관계의 경우 3개의 테이블이 있습니다. ( 2개의 엔티티 및 개체ID를 사용하는 연결을 포함하는 조인 테이블 ). 엔티티는 서로 관계를 가질 수 있습니다.
-. 성능
테이블의 갯수와 관계가 다르기 때문에, 두 옵션이 성능에 미치는 영향이 다릅니다.
상속을 처리 할 때, 자식 엔티티를 검색하면 모든 데이터는 두개의 테이블에서 검색 됩니다.
1-1 연결된 엔티티를 검색 할때는 검색데이터만 검색합니다. 연결된 데이터는 기본적으로 검색 되지 않으므로 두 엔티티 중 하나만 검색할때 데이터 전송에 미치는 영향이 적습니다. 그러나 두 엔티티가 항상 검색 된다고 하면 세개의 테이블을 모두 검색해야 하며, 이는 상속관련 2개의 테이블 검색 보다 느립니다.
엔티티를 별도로 변경하거나 사용한다면 1-1 연결이 가장 좋습니다. 1-1 연결을 사용하면 필요한 것만 검색/변경할 수 있어서, 개별적으로 관리할때 상속 시나리오보다 빠릅니다. 상속은 항상 두 엔티티 모두에서 검색/변경 됩니다.
항상 두 엔티티가 모두 필요하다면, 상속의 최상의 방법입니다. 상속은 최적화 되어 있어어 2개의 엔티티를 검색한다면 1-1 연결보다 빠릅니다.
-. 동작
또한 Object Type decision 을 이용한다면 상속이 좋습니다.
1-1 관계인 경우, 논리를 재사용하려면 개발자가 더 많은 생각과 작업을 수행해야 하며, 연결 검사 또는 추가 열거형 값을 기반으로 decision 을 추가 해야 합니다.
-. 객체의 라이프사이클
상속은 부모/자식 엔티티가 모두 자동으로 생성/검색/삭제 그리고 커밋 됩니다.
1-1 연결은 수동으로 처리해야 합니다.
여기까지 완성한 버전 입니다.