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 참고

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<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>
cs

 

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
 
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();
    }
}
cs

 

 

[결과]

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

 

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

 

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

 

끗.

Index라는 컬럼을 가진 DataTable이 있을때 Index로 Sorting을 하고싶다면 다음과 같이 사용하면 된다.

DataTable dt;
//Columns add ... 
//Rows add ...
dt.DefaultView.Sort = "index desc";

desc : 내림차순

asc : 올림차순


* Sotring 후 그냥 dt를 사용 할경우 Sorting된 값을 사용할 수 없다. dt.DefaultView를 사용 해야 Sorting된 값을 확인 할 수 있다.


tip

Sorting 후 key값의 index를 알고싶을때는 find 함수를 사용하면 된다.

예를 들어 Index라는 컬럼이 Datatable의 key값일 경우

dt.DefaultView.Sort = "index desc";
//20이라는 index의 Row를 알고싶을 경우
int nRow = dt.DefaultView.find(20);
//nRow를 사용하면 된다.
//find에서 찾는 값이 없을 경우 -1을 리턴하니 참고하길
//Row를 찾았으니 이제 해당 row의 값을 가져오는 방법을 알아보자
//Datatable에 Name이라는 컬럼이 있다고 한다면 아래와 같은 방법으로 사용가능하다.
string Student_Name = dt.DefaultView[nRow]["Name"].ToString();
//....


'Programming > C#' 카테고리의 다른 글

[C#] 네이버 자동 로그인 / 카페 글쓰기 API  (899) 2019.11.01
[C#]ini file 사용법 & 소스 공유  (540) 2017.01.03
[C#]Log4Net 사용법  (587) 2017.01.03
[C#]Snappy 사용법  (143) 2016.12.30

+ Recent posts