DevExpress QuantumGrid 사용법 007 ( Master-Detail 구성하기 )

요즘 필자가 갑자기 백수가 되었습니다. 뭐 예상은 했지만 경기가 정말 안 좋군요.
작년에 비해 일거리도 반 이상 줄었고, 나이도 있고 경력도 있는지라 섣불리 뽑아 주질 않네요.

이번 내용도 역시 본 제작자가 이동 또는 게시하지 않는 경우를 제외하고는 이곳 외에 다른 곳에서 볼 수 없습니다. 이를 어 길시 정말 법적 제제가 가해질 수 있습니다.

Master Detail구조는 일반 업무에서도 많이 사용합니다.( 자재 관리용 BOM등을 구성할 때는 DBTreeView등을 사용 하시면 됩니다. )

퀀텀으로 Master-Detail을 표현 하는 방법은 여러 가지가 있지만, 가장 많이 사용하는 몇 가지만 알아 보도록 하겠습니다.

-. QuantumGrid의 기본적인 구성 방법.
우선 가장 쉬운 방법으로 퀀텀의 기본기능을 이용하는 방법입니다. 가장 무식한 방법이지만 따로 신경쓸일이 없어 편리 합니다.

이제 기존에 사용하셨던 FRM_Simple폼을 변경하여 Master-Detail구분으로 바꾸어 보도록 하겠습니다.

예제 : Master는 Customer로 하고 Detail은 Orders로 하여 Customer별 Order내용을 Master-Detail구조로 표현해보도록 하겠습니다. 

첫번째로 기본의 Table을 수정하거나 지우셔서 2개의 Table과 2개의 DataSource를 구성합니다.( 업무에 따라 Query를 사용하시면 됩니다. )
첫2개의 Table중 하나는 TBL_Customer로 하나는 TBL_Orders로 이름을 바꾸거나 새로 구성하고, DBDEMOS의 Customer와 Orders를 DB로 설정합니다.
여기서 중요한것은 Orders 테이블에서  IndexFieldNames = ‘CustNo’ 설정입니다.
Quantum의 기본적인 Master-Detail방법은 Master인 Customer의 내용을 클릭할때 Detial의 Orders에서 Master의 CustNo를 찾아 같은 CustNo가 아닌 넘까지 출력하는 방식입니다.
따라서 Orders가 CustNo순으로 Sort되어 있지 않다면, 첫번째 검색된 CustNo하나만 나올 가능성이 많습니다.
따라서 반드시 검새되어지는 MasterKeyFields의 인덱스로 Sorting이 되어 있어야 한다는 것입니다.

  object DS_Customer: TDataSource
DataSet = TBL_Customer
Left = 348
Top = 2
end
object TBL_Customer: TTable
Active = True
DatabaseName = ‘DBDEMOS’
TableName = ‘customer.db’
Left = 384
end

 object DS_Orders: TDataSource
DataSet = TBL_Orders
Left = 282
Top = 4
end
object TBL_Orders: TTable
Active = True
DatabaseName = ‘DBDEMOS’
IndexFieldNames = ‘CustNo’
TableName = ‘orders.db’
Left = 312
Top = 4
end

이제 그리드를 설정해 보겠습니다.
기존의 그리드를 그대로 쓸것이므로 아래처럼 구성합니다.

그림이 조금 작아 내용확인이 어려울지 모르겠습니다.

Hierarchy구조로 표현을 하려면, Grid Level에 Grid Level를 포함 하는 방법을 사용합니다.
위 그림 처럼 GRD_SimpleLevel1 밑에 GRD_SimpleLevel2를 배치 하면 됩니다.
배치를 하자 마자 표시가 나타나고 Hierarchy구조가 펼쳐 집니다.

참고 : QuantumGrid는 BandedTableView등과 같은 View가 그리드 모양을 꾸미고, Level은 Hierarchy구조를 표현 합니다. 하지만, Level이라고 모두가 다 화면에 표시 되지는 않으며, 사용자의 선택에 따라 여러 의미를 가진 용도로 사용할수 있습니다.( 예: LooupCombo에서 ▼ 를 눌렀을때 나타나는 용도로도 사용 가능 ).

다시 예제로 돌아와서  기존 BandTV_Simple을 그대로 사용할 것이므로 GRD_SimpleLevel2에 BandTV_Simple을 설정하고 GRD_SimpleLevel1에 새로운 DBBandedTableView를 설정합니다. 필자는 개인적으로 banded를 좋아해서 BandedTablView를 사용하지만, 독자들 께서는 일반 TableView를 사용하셔도 무방합니다.

일단 그리드를 구성하고 GIF처럼 Properties를 구성하면 작업이 완료 됩니다.
Properties의 내용중 아래 내용을 확인하셔야 합니다.
1. 상위레벨이 Master가 됩니다.
2. 하위 레벨의 DetailKeyFieldNames와 상위 레벨의MasterKeyFieldNames의 내용은 동일한 값이어야만 합니다.
( FieldName이 동일한것이 아니라 서로 검색되어지는 “키의 값”이 동일해야 한다는 것입니다. )
참고 : Names처럼 복수형이므로 여러 FieldName을 복수로 연결이 가능 합니다.( ‘;’으로 구분합니다. )
예> ‘CustomerNo;Counry’ <– 고객번호와 나라로 검색.
물론 Master와 Detail모두 같은 키값으로 처리되어야 합니다.

3. Detail의 KeyFieldNames의 내용은 Master-Detail과 관계없이 동작합니다. 많은 분들이 도대체 KeyFieldNames의 용도가 뭐냐고 묻습니다.
설명을 간단히 드리자면, 퀀텀에서 단순 Display용도 외에 크게는 수정, 삭제등의 작업을 할경우 이들작업의 기준이 되어지는 퀀텀 내부의 키를 지정하는 것입니다.
따라서, Master-Detail에서 Detial의 DetailKeyFieldNames와 동일하게 KeyFieldNames를 정의하면, 커서의 이동이나 그런것에 제한이 될 수 있습니다.
대부분은 아무것도 쓰지 않습니다. 그게 편하거든요. 아님 진정으로 Master-Detail관계와는 별도로 Detail 고유의 키들을 정의하시면 됩니다.

실행을 하시면. 간단히 마스터 디테일 관계나 나타나게 됩니다.

-. Table DB를 이용하거나 Query를 이용하여 구성하는 방법.
두번째는 Detail의 내용이 너무 많거나 조건이 너무 많거나, 한번에 하나의 Detail만 표시하고자 하는 경우에 대해 알아보도록 하겠습니다.
이경우는 이미 DB를 통해 Master-Detail을 구성하였거나, Master의 레코드의 값에 따라 쿼리를 이용하여 Detail을 구성하려 하는 경우 사용합니다.

우선 Table을 이용하여 Detail DB에 Master를 연결 하신 경우 입니다.

위 그림처럼 이미 DB상으로 Master-Detail을 구성하신경우 아시겠지만 Master 데이타의 Focus가 이동해야 ( Record가 이동해야 ) Master 데이타의 키값( 여기서는 CustNo )에 해당하는 Detial값을 Detail DB에서 읽어 옵니다.
때문에 DB에 이렇게 구성을 하시고 위 방법대로 퀀텀을 실행하시면 현재 Focus가 있는 넘들의 데이타만 나올뿐 다른 넘들의 데이타는 나오지 않습니다. ( 당연한 결과 이겠지만요 )

Detail 데이타의 양이 많거나 반드시 Table의 Master-Detail관계를 사용해야 한다면, 지금처럼 약간의 편법을 사용할수 밖에 없습니다.
편법은 우선 키를 누를때( TableView–>DataController–>DetailExpanding 이벤트) 열려 있는 모든 하위 view를 닫습니다.
그리고, 쿼리인 경우  쿼리를 하시고 , Table의 경우 RecordIndex로 Focus를 옮기면 됩니다.

procedure TALL_Misu_F.GRID_MISUDBTV1DataControllerDetailExpanding(
ADataController: TcxCustomDataController; ARecordIndex: Integer;
var AAllow: Boolean);
begin
GRID_TableView1.ViewData.Collapse( True ); // 열린것 모두 닫는다.
  // 방법 1. 쿼리로 Detail내용을 읽어오는 경우.
  SQL_Detail.Close;
SQL_Detail.SQL.Text := Detail_Query_Text;
  //                                                                                                                              키값이 0번째
  SQL_Detail.ParamByName( ‘CustNo’ ).AsInteger := ADataController.Values[ ARecordIndex, 0 ];
SQL_Detail.Open;

// 방법 2. Table의  Master-Detail을 설정한 경우 .
  ADataController.FocusedRecordIndex := ARecordIndex ;

AAllow := True; // 펼칩니다.
end;

간단하지요?
설명만 딥따리 길뿐 내용은 간단합니다.

다음장은 Grid Level에 따른 몇가지 기능에 대해 알아 보도록 하겠습니다.

Author: yyjksw