본문 바로가기

SW/ASP.NET

[ASP.NET] 중첩 Repeater (Nested Repeater)

WebForms 개발시 Repeater를 자주 사용하게 된다. (회사마다 다르겠지만)
Repeater 사용시 중첩으로 사용하고 싶은 경우들이 있다.

예를들어.

A사 (Key: A)  
  A-1 계열사 (FKey: A)
B사 (Key: B)  
  B-1 계열사 (FKey: B)
  B-2 계열사 (FKey: B)

위와 같은 테이블을 만들기 위해 중첩 Repeater를 사용할 수 있다. (물론 DB조회를 잘 해와서 하나의 Repeater로도 충분히 표현 가능하다. 예시일뿐.)

사용하려는 방법은 DataSet의 Relations를 활용한 방법이다.
* MS Docs DataRelation 참고
Relations를 활용하면 키값으로 두개의 DataTable을 묶어서 사용할 수 있다.
구글링을 하여 찾아보면, OnItemDataBound에서 한번 더 쿼리를 실행해 바인딩(부모의 매 Row마다 실행)하는 방법을 많이 볼 수 있다.
하지만 DataRelation을 사용하면 한번의 쿼리 실행으로 원하는 결과를 만들 수 있다.

코드를 확인하며 이해해보자

[aspx]
Repeater 두개를 중첩하여 작성하였다.
OnItemDataBound에서 Relation정보를 찾아와 SubCompanyList에 바인딩 한다.
    * MS Docs DataBinder.Eval 참고

<table>

    <tbody>

        <asp:Repeater ID="CompanyList" runat="server" OnItemDataBound="CompanyList_ItemDataBound">

            <ItemTemplate>

                <tr>

                    <td><%# Eval("Name") %> (Key: <%# Eval("Key") %>)</td>

                    <td>&nbsp;</td>

                </tr>

                <asp:Repeater ID="SubCompanyList" runat="server">

                    <ItemTemplate>

                        <tr>

                            <td>&nbsp;</td>

                            <td><%# DataBinder.Eval(Container.DataItem, "[\"Name\"]") %> (FKey: <%# DataBinder.Eval(Container.DataItem, "[\"FKey\"]") %>)</td>

                        </tr>

                    </ItemTemplate>

                </asp:Repeater>

            </ItemTemplate>

        </asp:Repeater>

    </tbody>

</table>

 

 

[aspx.cs]
1. Page_Load에서 dtCompany, dtSubCompany(임시로 만든 정보입니다. 현업에서는 DB를 읽어와 사용하겠죠?)를 불러와 DataSet을 생성한다.
2. DataSet.Relations를 추가 하여 관계를 생성한다. (관계의 이름은 "CompanyKey"이다.)
    * Relations의 파라미터로 "관계의 이름", "부모 키 컬럼", "자식 키 컬럼"을 넣어준다.

3. 최상단 Repeater에 부모 Table을 바인딩한다.
4. OnItemDataBound Event에서 자식 Table을 찾아 Sub Repeater에 바인딩한다. (GetChildRows 함수 사용)

protected void Page_Load(object sender, EventArgs e)

{

    var dtCompany = InitCompanyData();

    var dtSubCompany = InitSubCompanyData();

    // 데이터셋 생성

    var ds = new DataSet();

    ds.Tables.Add(dtCompany);

    ds.Tables.Add(dtSubCompany);

    // 관계 설정

// DB 조회시에는 SP에서 테이블을 여러개 읽어와 Fill로 DataSet을 만든 후 Relation만 잡아주면 된다.

    ds.Relations.Add("CompanyKey", ds.Tables["CompanyTable"].Columns["Key"], ds.Tables["SubCompanyTable"].Columns["FKey"]);

    // 부모 테이블 바인딩

    CompanyList.DataSource = ds.Tables["CompanyTable"];

    CompanyList.DataBind();

}

 

private DataTable InitCompanyData()

{

    var dtCompany = new DataTable();

    dtCompany.TableName = "CompanyTable";

    dtCompany.Columns.Add("Key"typeof(string));

    dtCompany.Columns.Add("Name"typeof(string));

    var newRow = dtCompany.NewRow();

    newRow["Key"= "A";

    newRow["Name"= "A사";

    dtCompany.Rows.Add(newRow);

    newRow = dtCompany.NewRow();

    newRow["Key"= "B";

    newRow["Name"= "B사";

    dtCompany.Rows.Add(newRow);

    return dtCompany;

}

 

private DataTable InitSubCompanyData()

{

    var dtSubCompany = new DataTable();

    dtSubCompany.TableName = "SubCompanyTable";

    dtSubCompany.Columns.Add("FKey"typeof(string));

    dtSubCompany.Columns.Add("Name"typeof(string));

    var newRow = dtSubCompany.NewRow();

    newRow["FKey"= "A";

    newRow["Name"= "A-1 계열사";

    dtSubCompany.Rows.Add(newRow);

    newRow = dtSubCompany.NewRow();

    newRow["FKey"= "B";

    newRow["Name"= "B-1 계열사";

    dtSubCompany.Rows.Add(newRow);

    newRow = dtSubCompany.NewRow();

    newRow["FKey"= "B";

    newRow["Name"= "B-2 계열사";

    dtSubCompany.Rows.Add(newRow);

    return dtSubCompany;

}

 

protected void CompanyList_ItemDataBound(object sender, RepeaterItemEventArgs e)

{

    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)

    {

        Repeater SubCompanyList = e.Item.FindControl("SubCompanyList"as Repeater;

        // 관계가 설정된 자식 테이블 얻어오기

// 이 부분에서 한번 더 쿼리를 실행할 필요 없이, 관계가 맺어진 정보를 읽어올 수 있다.

        var childRows = ((DataRowView)e.Item.DataItem).Row.GetChildRows("CompanyKey");

        SubCompanyList.DataSource = childRows;

        SubCompanyList.DataBind();

    }

}

 

 

[결과]

직접 디버깅을 해보면 알겠지만 OnItemDataBound Event에서 부모 Table의 Row에 자식 테이블이 엮여 있는것을 볼 수 있다.

 

* DB조회시 까다로운 쿼리 혹은 전혀 관계 없는 데이터를 코드딴에서 묶어서 사용하고 싶을때도 유용하게 사용가능하다. 일자별로 묶어서 데이터를 처리한다던가 하는 그런것들 말이다.

 

다음번 글은 MS사의 Bot Framework와 Language Understanding(LUIS:루이스)을 작성해볼까 한다. (텔레그램, 스카이프 등등 연동도 간편하고 좋다. 단지 LUIS가 유료)

 

끗.