# RetrieveHelper, Paging Example

## 정의

* 네임스페이스: GST.PlusWin6.Core.Library
* 어셈블리: GST.PlusWin6.Core.dll

## 설명

* BaseForm.ClickRetrieveButton 메서드에 자주 사용되는 Find Row Pattern 코드와 6버전에 새롭게 추가된 PagingManager 컨트롤을 통한 GridView의 페이징 기능의 Find Row Pattern을 지원
* 데이터를 조회하고 새로 바인딩된 DataSource에 대한 행 번호가 같아 FocusedRowChanged, FocusedNodeChanged 이벤트가 발생하지 않는 케이스에 작성하는 코드 패턴을 지원
* **조회용 저장 프로시저에 찾을 값에 대한 페이지 번호를 구하는 "sys\_find\_page\_by\_value" 프로시저를 사용해야함**



## Method

### AddFindRowInfo

* Find Row 기능을 적용할 개체 정보를 등록
* (※ TreeList 타입은 페이징을 지원하지 않음)
* Parameters
  * `ColumnView view` : RetrieveHelper 기능을 사용할 ColumnView 타입 개체
  * `TreeList tree` : RetrieveHelper 기능을 사용할 TreeList 타입 개체
  * `string fieldName` : Find Row에서 값을 찾을 필드명
  * `PagingManager pagingManager` : ColumnView가 페이징 방식으로 구현된 경우 해당 개체의 PagingManager 개체를 전달 그렇지 않으면 null 값 전달

```csharp
public void AddFindRowInfo(ColumnView view, string fieldName, PagingManager pagingManager);

public void AddFindRowInfo(TreeList tree, string fieldName);
```



### Begin

* 데이터 조회 전 Grid 또는 Tree의 상태 정보를 보관

```csharp
public int Begin(ColumnView view);

public void Begin(TreeList tree);
```



### End

* 데이터 조회 이전의 상태와 새로 바인딩 된 이후의 상태를 비교하여 FocusedRowChanged 또는 FocusedNodeChanged 메서드를 호출

```csharp
public void End(ColumnView view);

public void End(TreeList tree);
```



### GetValueToFindRow

* Grid 또는 Tree 개체에서 인덱스를 값을 반환
* FindRow 메서드가 호출된 이후엔 값이 자동으로 초기화됨
* Returns
  * string: SetValueToFindRow 메서드에 의해 할당된 값

```csharp
public string GetValueToFindRow(object target);
```



### SetValueToFindRow

* Grid 또는 Tree 개체에서 인덱스를 값을 할당

```csharp
public void SetValueToFindRow(ColumnView view, string value);

public void SetValueToFindRow(TreeList tree, string value);
```



### FindRow

* Grid 또는 Tree 개체에서 SetValueToFindRow 메서드에 의해 할당된 값의 인덱스를 찾아 해당 행으로 포커스를 이동

```csharp
public void FindRow(ColumnView view);

public void FindRow(TreeList tree);
```



### IsFindingRowHandle

* 데이터를 새로 조회할 때 Find Row Pattern에 의해 FocusedRowChanged 또는 FocusedNodeChanged 메서드가 두 번 호출되는 것을 제어하기 위한 메서드
* 상태는 Begin 메서드에 의해 `true` 로 설정되며 FindRow 메서드에서 `false`로 변경됨

```csharp
public bool IsFindingRowHandle(ColumnView view);

public bool IsFindingRowHandle(TreeList tree);
```



## 예제 (페이징이 적용된 GridControl) <a href="#example" id="example"></a>

{% hint style="info" %}
예제 코드들은 BaseForm (namespace GST.PlusWin6.Core.Forms)을 상속받은 코드를 기준으로 작성됨
{% endhint %}

### C# Code <a href="#csharp-code" id="csharp-code"></a>

* 변수 타입 정보: gvwList (→ GridViewEx), pmList (→ PagingManager)
* 생성자에서 RetrieveHelper 멤버의 `AddFindRowInfo` 메서드로 'gvwList'에 'pmList'를 등록
* 데이터 조회 메서드(`Retrieve`) 호출 전/후에 각 `RetrieveHelper.Begin`, `RetrieveHelper.End` 코드를 작성하며, 조회에 성공 시 저장했던 데이터를 찾아가기 위한 `RetrieveHelper.FindRow`를 작성
* 저장에 성공 후 데이터를 찾아가는 과정에서 조회된 첫 번째 행(Row)에 대한 FocusedRowChanged 이벤트 로직을 생략하기 위해 `RetrieveHelper.IsFindingRowHandle` 코드를 작성
* 데이터 저장이 완료되면, 조회할 때 데이터를 찾아가기 위한 키 값의 데이터를 저장 프로시저 처리 결과(`ResultSet.ReturnString`)를 참조하여 `RetrieveHelper.SetValueToFindRow` 메서드에 변수로 전달

```csharp
// 생성자
public FormInfo(params object[] args) : base(args)
{
    InitializeComponent();
    
    // ...    
    
    gvwList.FocusedRowChanged += GridView_FocusedRowChanged;
    
    RetrieveHelper.AddFindRowInfo(gvwList, "form_id", pmList);
    pmList.Init(gvwList, 1000);
    pmList.PageChanged += (s, e) => ClickRetrieveButton();
    
    // ...
}

public override void ClickRetrieveButton()
{
    int page = RetrieveHelper.Begin(gvwList);

    if (Retrieve(page, "list"))
    {
        RetrieveHelper.FindRow(gvwList);
    }

    RetrieveHelper.End(gvwList);
}

private void GridView_FocusedRowChanged(object sender, FocusedRowChangedEventArgs e)
{
    if (sender is GridView view)
    {
        FocusedRowChanged(view);
    }
}

public override void FocusedRowChanged(ColumnView view)
{
    if (view.Equals(gvwList))
    {
        if (view.RowCount > 0 && view.FocusedRowHandle >= 0)
        {
            if (!RetrieveHelper.IsFindingRowHandle(view))
            {
                FillValuesFromReferenceControl(grpMaster, grdList);
                Retrieve(0, "detail");
            }
        }
        else
        {
            InitControlsRecursive(grpMaster);
        }
        SetReadOnlyRecursive(txtFormId, true);
    }
}

private bool Retrieve(int page, string workType)
{
    // ...
    
    sel_form_info procInfo = new sel_form_info();

    procInfo.SetParamValues(
        workType,
        formId,
        formName,
        RetrieveHelper.GetValueToFindRow(gvwList),
        page,
        pmList.PageSize);
        
    // ...
}

private bool SaveData(string workType)
{
    if (!ValidateControls(grpMaster))
        return false;

    ParameterBuilder paramBuilder = new ParameterBuilder();
    DataTable source = CopyOfChangedData(grdDetail);
    
    //...
    
    try
    {
        ResultSet result = ExecuteProcedure(procInfo);

        bool isSuccess = result?.IsSuccess ?? false;

        if (isSuccess && !workType.Equals("D"))
        {
            RetrieveHelper.SetValueToFindRow(gvwList, result.ReturnString);
        }

        return isSuccess;
    }
    catch (Exception ex)
    {
        ShowErrorMessageForm(ex);
        return false;
    }
}
```



### 조회용 저장 프로시저 <a href="#stored-procedure" id="stored-procedure"></a>

* 특정 값이 존재하는 페이지 번호와 그 페이지의 쿼리 결과를 반환 받는 방법
* ex) \[품목관리]에서 새로 저장한 품목코드가 존재하는 페이지를 바로 찾아가기 위한 쿼리 작성 규칙
* 페이지 번호를 알기 위한 값을 받아오기 위해 '`@p_find_row_value`' 파라미터 정의. 해당 파라미터의 값 유/무로 페이지 번호(`@p_page_number`)를 재계산할지 결정
* 페이지 번호를 재계산 하기 위해서 '`sys_find_page_by_value`' 저장 프로시저를 사용하며 해당 저장 프로시저의 변수에는 최종 결과가 반환되는 쿼리에 작성된 FROM 절의 테이블(`@p_table_name`), WHERE(`@p_where`), ORDER BY(`@p_order_by`) 구문을 함께 전달해야하며, 찾을 필드명(`@p_field_name`)과 값(`@p_value`)을 전달해서 결과를 OUTPUT 파라미터(`@p_result_page`)를 통해 받아옴
* 조건(WHERE)절에 JOIN 문에서 작성된 요소를 참조할 경우 테이블(`@p_table_name`) 변수에 JOIN문을 함께 작성해서 전달
* `sys_find_page_by_value` 저장 프로시저에 전달하는 값을 작성할 때 작은 따옴표(') 및 별칭(ALIAS) 참조에 주의

{% tabs %}
{% tab title="조회용 저장 프로시저 EX 1" %}
```sql
ALTER PROCEDURE [dbo].[sel_form_info] (
	@p_work_type		varchar(20) = 'Q',

	@p_form_id		varchar(50),
	@p_form_name		nvarchar(100),

	@p_find_row_value	varchar(50),

	@p_page_number		int		= 1  OUTPUT,	-- 페이지 번호 
	@p_page_size		int		= 5  OUTPUT,	-- 한 페이지에 나타낼 행(Row) 수 

	@p_status_code		varchar(100)	= '' OUTPUT,    -- 상태 코드
	@p_result_msg		nvarchar(1000)	= '' OUTPUT,	-- 결과 메세지
	@p_return_str		nvarchar(1000)	= '' OUTPUT,	-- 사용자 지정 반환 문자열
	@p_error_info		varchar(500)	= '' OUTPUT		-- 오류정보
)
/*[!WITH ENCRYPTION]*/
AS 
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

DECLARE @v_where_query	varchar(MAX)	= ''
DECLARE @v_datetime	datetime	= GETDATE()

BEGIN 
    BEGIN TRY
    
        -----------------------------------------------------------------------------------------------------------------------
        IF @p_work_type IN ( 'list' )
        BEGIN
        -----------------------------------------------------------------------------------------------------------------------

		-- @p_find_row_value 변수에 값이 있는 경우 페이지 번호(@p_page_number)를 업데이트
		IF ISNULL(@p_find_row_value,'') <> ''
		BEGIN
			SET @v_where_query = '
			WHERE A.form_id LIKE ''%' + @p_form_id + '%'' '
	
			EXEC sys_find_page_by_value 
				@p_table_name = 'appFormMaster A', 
				@p_where = @v_where_query,
				@p_order_by = 'form_id', 
				@p_field_name = 'form_id',
				@p_value = @p_find_row_value,
				@p_page_size = @p_page_size, 
				@p_result_page = @p_page_number OUTPUT
		END
		
		/* 결과1 */
		SELECT	A.*,
			(CASE WHEN update_time IS NOT NULL THEN update_time ELSE insert_time END) as last_update_time,
			total_row_count = COUNT(*) OVER()
		FROM appFormMaster A
		WHERE form_id LIKE '%' + @p_form_id + '%'
		ORDER BY form_id 
		OFFSET (@p_page_number - 1) * @p_page_size ROWS
		FETCH NEXT @p_page_size ROWS ONLY

            	IF @@ROWCOUNT > 0  
			SET @p_status_code = 'MSG0001'                                -- 정상적으로 조회가 되었습니다  
	        ELSE 
                	SET @p_status_code = 'MSG0006'                                -- 조회된 자료가 없습니다.                 

        END 
        -----------------------------------------------------------------------------------------------------------------------
...	
```
{% endtab %}

{% tab title="조회용 저장 프로시저 EX 2" %}
<pre class="language-sql"><code class="lang-sql">ALTER PROCEDURE [dbo].[sel_data_component] (
	@p_work_type		varchar(20),	-- list / detail

<strong>	@p_dc_code		varchar(50),
</strong>	@p_word_text		nvarchar(100),
	@p_remarks		nvarchar(500),

	@p_culture_name		varchar(10),

	@p_find_row_value	varchar(100)	= '',

	@p_page_number		int		= 1  OUTPUT,	-- 페이지 번호 
	@p_page_size		int		= 5  OUTPUT,	-- 한 페이지에 나타낼 행(Row) 수 

	@p_status_code		varchar(100)	= '' OUTPUT,    -- 상태 코드
	@p_result_msg		nvarchar(1000)	= '' OUTPUT,	-- 결과 메세지
	@p_return_str		nvarchar(1000)	= '' OUTPUT,	-- 사용자 지정 반환 문자열
	@p_error_info		varchar(500)	= '' OUTPUT	-- 오류정보
)
/*[!WITH ENCRYPTION]*/
AS 
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

DECLARE @v_table_query		varchar(MAX)	= ''
DECLARE @v_where_query		varchar(MAX)	= ''
DECLARE @v_datetime		datetime	= GETDATE()
DECLARE @v_default_culture	varchar(50)	= dbo.GetDefaultCulture()

IF @p_page_number &#x3C; 1 SET @p_page_number = 1

BEGIN 
    BEGIN TRY

        -----------------------------------------------------------------------------------------------------------------------
        IF @p_work_type IN ( 'list' )
        BEGIN
        -----------------------------------------------------------------------------------------------------------------------

		-- @p_find_row_value 변수에 값이 있는 경우 페이지 번호(@p_page_number)를 업데이트
		IF ISNULL(@p_find_row_value,'') &#x3C;> ''
		BEGIN
			SET @v_table_query = '
				brpDataComponent A
				LEFT OUTER JOIN (	SELECT dc_code, COUNT(1) as cnt
							FROM brpDataWords C1
								LEFT OUTER JOIN brpWordInfo C2
									ON C2.culture_name = dbo.GetDefaultCulture()
									AND C1.word_id = C2.word_id
							WHERE ISNULL(C2.word_text, '''') LIKE ''%' + @p_word_text + '%'' 
							GROUP BY dc_code ) C
					ON A.dc_code = C.dc_code'

			SET @v_where_query = '
				WHERE A.dc_code LIKE ''%' + @p_dc_code + '%''
				AND A.dc_code LIKE (CASE WHEN ''' + @p_word_text + ''' = '''' THEN ''%'' ELSE ISNULL(C.dc_code,'''') END) '

			EXEC sys_find_page_by_value 
				@p_table_name = @v_table_query,
				@p_where = @v_where_query,
				@p_order_by = 'A.dc_code', 
				@p_field_name = 'A.dc_code',
				@p_value = @p_find_row_value,
				@p_page_size = @p_page_size, 
				@p_result_page = @p_page_number OUTPUT
		END


		/* 결과1 */
		SELECT	A.dc_code,
			A.default_control,
			A.data_type,
			(CASE WHEN A.data_type IN ('decimal','numeric') THEN A.data_precision ELSE A.data_length END) as data_length,
			A.data_scale,
			A.bc_id,
			A.decimal_code,
			A.remarks,

			ISNULL(B.word_text,'') as main_word_text,
			ISNULL(D.bc_name,'') as bc_name,
			(CASE WHEN A.update_time IS NOT NULL THEN A.update_time ELSE A.insert_time END) as last_update_date,
			total_row_count = COUNT(*) OVER()
		FROM brpDataComponent A

				-- 메인용어 참조용
				LEFT OUTER JOIN (	SELECT B1.dc_code, B1.word_id, ISNULL(B2.word_text,'') as word_text
							FROM brpDataWords B1
									LEFT OUTER JOIN brpWordInfo B2
										ON B2.culture_name = dbo.GetDefaultCulture()
										AND B1.word_id = B2.word_id
							WHERE B1.is_main = 'Y' ) B
					ON A.dc_code = B.dc_code

				-- 컴포넌트 용어 검색용
				LEFT OUTER JOIN (	SELECT dc_code, COUNT(1) as cnt
							FROM brpDataWords C1
								LEFT OUTER JOIN brpWordInfo C2
										ON C2.culture_name = dbo.GetDefaultCulture()
										AND C1.word_id = C2.word_id
							WHERE ISNULL(C2.word_text, '') LIKE '%' + @p_word_text + '%' 
							GROUP BY dc_code ) C
						ON A.dc_code = C.dc_code

				LEFT OUTER JOIN dboBizComponent D
						ON A.bc_id = D.bc_id

		WHERE A.dc_code LIKE '%' + @p_dc_code + '%'
		AND A.dc_code LIKE (CASE WHEN @p_word_text = '' THEN '%' ELSE ISNULL(C.dc_code,'') END)

		ORDER BY dc_code
		OFFSET (@p_page_number - 1) * @p_page_size ROWS
		FETCH NEXT @p_page_size ROWS ONLY

            IF @@ROWCOUNT > 0  
		SET @p_status_code = 'MSG0001'	-- 정상적으로 조회가 되었습니다  
            ELSE 
                SET @p_status_code = 'MSG0006'	-- 조회된 자료가 없습니다.                 
        END 
        -----------------------------------------------------------------------------------------------------------------------
...
</code></pre>
{% endtab %}

{% tab title="조회용 저장 프로시저 EX 3" %}
```sql
ALTER PROCEDURE [dbo].[pw6_sel_meeting] (
    @p_work_type	varchar(20), -- list / detail / attendees
    @p_orgdiv		varchar(2),

    @p_from_date	varchar(8),
    @p_to_date		varchar(8),

    @p_custcd		varchar(20),
    @p_custnm		nvarchar(200),
    @p_contents		nvarchar(200),
    @p_meetingnum	varchar(20),
    
    @p_find_row_value	varchar(100)	= '',

    @p_page_number	int		= 1  OUTPUT,	-- 페이지 번호 
    @p_page_size	int		= 5  OUTPUT,	-- 한 페이지에 나타낼 행(Row) 수 

    @p_status_code	varchar(100)	= '' OUTPUT,    -- 상태 코드
    @p_result_msg	nvarchar(1000)	= '' OUTPUT,	-- 결과 메세지
    @p_return_str	nvarchar(1000)	= '' OUTPUT,	-- 사용자 지정 반환 문자열
    @p_error_info	varchar(500)	= '' OUTPUT	-- 오류정보
)
/*[!WITH ENCRYPTION]*/
AS 
SET NOCOUNT ON  
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

DECLARE @v_orgdiv		varchar(2) = '01'
DECLARE @v_table_query		varchar(MAX)	= ''
DECLARE @v_where_query		varchar(MAX)	= ''
DECLARE @v_table_name		varchar(MAX) = ''

IF @p_page_number < 1 SET @p_page_number = 1

BEGIN 
    BEGIN TRY
        ----------------------------------------------------------------------------------------------------------------------- 
        -- 회의록 리스트
        IF @p_work_type IN ( 'list' ) 
        BEGIN
        ----------------------------------------------------------------------------------------------------------------------- 

            -- @p_find_row_value 변수에 값이 있는 경우 페이지 번호(@p_page_number)를 업데이트
            IF ISNULL(@p_find_row_value,'') <> ''
            BEGIN
                SET @v_table_query = '
                    (	SELECT	A.*,
                                ISNULL(B.custnm,'''') as custnm,
                                ISNULL(C.cnt,0) as cnt,
                                A.orgdiv + ''_'' + A.meetingnum as find_key
                        FROM BizGST.dbo.CR080T A
                                LEFT OUTER JOIN (    SELECT custcd, custnm
                                                     FROM BizGST.dbo.BA020T ) B
					    ON A.custcd = B.custcd
										
                                LEFT OUTER JOIN (    SELECT orgdiv, meetingnum, COUNT(1) as cnt
						     FROM BizGST.dbo.CR082T
						     WHERE contents LIKE ''%' + @p_contents + '%''
						     GROUP BY orgdiv, meetingnum ) C
					    ON A.orgdiv = C.orgdiv
					    AND A.meetingnum = C.meetingnum ) AA'

                SET @v_where_query = '
		    WHERE AA.orgdiv = ''' + @v_orgdiv + '''
		    AND AA.recdt BETWEEN ''' + @p_from_date + ''' AND ''' + @p_to_date + '''
		    AND AA.custcd LIKE ''' + @p_custcd + '''
		    AND (CASE WHEN ''' + @p_custcd + ''' = ''%'' THEN ''N'' ELSE AA.unshared END) <> ''Y''
		    AND ISNULL(AA.custnm,'''') LIKE ''%' + @p_custnm + '%''
		    AND (AA.title LIKE ''%' + @p_contents + '%'' OR
		        (CASE WHEN ''' + @p_contents + ''' = '''' THEN 1 ELSE ISNULL(AA.cnt,0) END) > 0 ) '

                EXEC sys_find_page_by_value 
		    @p_table_name = @v_table_query,
		    @p_where = @v_where_query,
		    @p_order_by = 'recdt DESC, meetingnum DESC', 
		    @p_field_name = 'AA.find_key',
		    @p_value = @p_find_row_value,
		    @p_page_size = @p_page_size, 
		    @p_result_page = @p_page_number OUTPUT
            END


            --# 결과1
            SELECT  A.*,
                    '' as chk,
                    A.orgdiv + '_' + A.meetingnum as find_key,
                    ISNULL(B.custnm,'') as custnm,
                    ISNULL(D.project, '') as devproject,
                    BizGST.dbo.GetAttachmentNames(A.attdatnum) as files,
                    BizGST.dbo.GetAttachmentNames(A.attdatnum_private) as files_private,
                    total_row_count = COUNT(*) OVER()
            FROM BizGST.dbo.CR080T A
			LEFT OUTER JOIN (   SELECT custcd, custnm
					    FROM BizGST.dbo.BA020T ) B
				    ON A.custcd = B.custcd

    			LEFT OUTER JOIN (   SELECT orgdiv, meetingnum, COUNT(1) as cnt
					    FROM BizGST.dbo.CR082T
					    WHERE contents LIKE '%' + @p_contents + '%'
					    GROUP BY orgdiv, meetingnum ) C
				    ON A.orgdiv = C.orgdiv
				    AND A.meetingnum = C.meetingnum

			LEFT OUTER JOIN	BizGST.dbo.CR500T D
				    ON A.orgdiv = D.orgdiv
				    AND A.devmngnum = D.devmngnum

            WHERE A.orgdiv = @v_orgdiv
            AND A.recdt BETWEEN @p_from_date AND @p_to_date
            AND A.custcd LIKE @p_custcd
            AND (CASE WHEN @p_custcd = '%' THEN 'N' ELSE A.unshared END) <> 'Y'
            AND ISNULL(B.custnm,'') LIKE '%' + @p_custnm + '%'
            AND (A.title LIKE '%' + @p_contents + '%' OR
                (CASE WHEN @p_contents = '' THEN 1 ELSE ISNULL(C.cnt,0) END) > 0 )
							

            ORDER BY recdt DESC, meetingnum DESC
            OFFSET (@p_page_number - 1) * @p_page_size ROWS
            FETCH NEXT @p_page_size ROWS ONLY

            IF @@ROWCOUNT > 0  
                SET @p_status_code = 'MSG0001'								-- 정상적으로 조회가 되었습니다
            ELSE 
                SET @p_status_code = 'MSG0006'                               -- 조회된 자료가 없습니다.

        END
        ----------------------------------------------------------------------------------------------------------------------- 

```
{% endtab %}
{% endtabs %}

