Visual C# .NETのRepeaterの入れ子について

以前、Repeaterについて書きましたが、
今回は、RepeaterのRepeater、、、Repeaterの入れ子について書きたいと思います。

2つのテーブルをJOINして取得するには、構造が複雑だったり、データ量が多い事によりJOINが不可能な場合があります。
そこで、2つのテーブルを別々で取得した場合の、Repeater用のデータ取得方法と、画面側の実装方法をご説明します。

サンプルデータ

以下のように2つのテーブルがあったとします。
とてもシンプルなデータなので、JOINして取ればいいですが、
このデータをRepeaterの入れ子用にデータを取得したいと思います。

■ユーザー情報(DB名:User)
UserID            Name
-----------------------------------
1                 Kobayashi
2                 Tanaka
3                 Yamada

■好きなフルーツ(DB名:Favorite)
UserID            Fruits
-----------------------------------
1                 パイナップル
1                 バナナ
1                 りんご
2                 いちご
2                 キュウイ
3                 レモン

Repeaterの入れ子用にデータを取得

(1)ユーザー情報を取得して、画面側の実装のRepeaterタグ、id=userListにDataBind()します。
(2)DB:Userと、DB:Favoriteの構造を作成し、どのカラムでリレーションさせるかを設定します。
   ここでは以下のように設定します。
   リレーションさせるカラム ⇒ 『UserID』
   リレーション名       ⇒ 『UserFavorite』
(3)ユーザー情報を取得し、DataSetへセットします。
(4)(3)で取得したユーザーIDを元に、Favorite情報を取得し、DataSetへセットします。

※データベースは、Microsoft SQL Serverへの接続で説明しています。
※エラーが発生した場合は、ログ出力するようにしています。

// ---(1)DataSet作成-------------------------------------
protected void Page_Load(object sender, EventArgs e)
{
	// ユーザー情報と、好きなフルーツを取得
	userList.DataSource = GetUser(tableDataGeteway);
	userList.DataBind();
}
// ---(1)---END------------------------------------------

/// <summary>
/// ユーザー情報と、好きなフルーツを取得
/// </summary>
/// <returns>ユーザー情報、好きな食べ物を1つにまとめたDataSet</returns>
public DataSet GetUser()
{
	// DataSetの初期化
	DataSet dataSet = new DataSet();

	//コネクション取得
	SqlConnection cnn =
		new SqlConnection("server=(local);database=pubs; Integrated Security=SSPI");

	try
	{
		cnn.Open();

		// ---(2)DataSet作成--------------------------------------
		// DataTable(User)の作成
		DataTable table = new DataTable("User");
		dataSet.Tables.Add(table);
		table.Columns.Add("UserID", typeof(string));
		table.Columns.Add("Name", typeof(string));
		table.PrimaryKey = new DataColumn[] { table.Columns["UserID"] };

		// DataTable(Favorite)の作成
		table = new DataTable("Favorite");
		dataSet.Tables.Add(table);
		table.Columns.Add("UserID", typeof(string));
		table.Columns.Add("Fruits", typeof(string));

		// リレーション
		dataSet.Relations.Add("UserFavorite", dataSet.Tables["User"].Columns["UserID"],
			dataSet.Tables["Favorite"].Columns["UserID"]);
		// ---(2)---END------------------------------------------

		// ---(3)ユーザー情報取得してDataSetに入れ直し-----------
		SqlDataAdapter sqlUser = new SqlDataAdapter("SELECT UserID, Name from User ", cnn);
		DataTable dtUser = new DataTable();
		int recordsUser = sqlUser.Fill(dtUser);

		if (recordsUser > 0)
		{
			for (int i = 0; i < dtUser.Rows.Count; i++)
			{
				// 1レコード取得
				DataRow rowUser = dtUser.Rows[i];

				// 取得したユーザー情報をセット
				dataSet.Tables["User"].Rows.Add(
							new object[] { 
							rowUser["UserID"].ToString(),
							rowUser["Name"].ToString(),
							});
		// ---(3)---END------------------------------------------

				// ---(4)ユーザーIDから好きな食べ物情報取得してDataSetに入れ直し---
				// 好きな食べ物を取得
				SqlDataAdapter sqlFav = new SqlDataAdapter(
				"SELECT UserID, Fruits from Favorite where UserID = " + rowUser["UserID"].ToString(), cnn);
				DataTable dtFav = new DataTable();
				int recordsFav = sqlFav.Fill(dtFav);

				if (recordsFav > 0)
				{
					// 取得した好きな食べ物情報をセット
					foreach (DataRow rowFav in dtFav.Rows)
					{

						dataSet.Tables["Favorite"].Rows.Add(
									new object[] { 
									rowFav["UserID"].ToString(),
									rowFav["Fruits"].ToString(),
									});
					}
				}
				// ---(4)---END--------------------------------------------------------
			}
		}

	}
	catch (SqlException e)
	{
		string msg = "";
		for (int i = 0; i < e.Errors.Count; i++)
		{
			msg += "Error #" + i + " Message: " + e.Errors[i].Message + "\n";
		}
		System.Console.WriteLine(msg);
	}
	finally
	{
		if (cnn.State != ConnectionState.Closed)
		{
			cnn.Close();
		}
	}

	return dataSet;

}

画面側の実装

入れ子にしている部分のRepeaterの記述は、上記で設定したリレーション名を設定します。『UserFavorite』
また、カラムを取得する場合、入れ子の部分のみ、"[\"Fruits\"]" の様な記述になることに注意してください。

<table class="p" border="1" cellspacing="0" cellpadding="3" width="100%">
<!-- 項目表示 -->
<tr align="center">
    <th>ユーザーID</th>
    <th>名前</th>
    <th>好きな食べ物</th>
</tr>
<!-- 繰り返し処理部分 start -->
<asp:Repeater id="userList" runat="server">
<ItemTemplate>
<tr align="center">
    <td>
       <!-- ユーザID -->
       <%# DataBinder.Eval(Container.DataItem, "UserID") %>
    </td>
    <td>
       <!-- ユーザ名 -->
       <%# DataBinder.Eval(Container.DataItem, "Name") %>
    </td>
    <td>
        <asp:Repeater id="userFavoriteList" datasource='<%# ((DataRowView)Container.DataItem).Row.GetChildRows("UserFavorite") %>' runat="server">
            <ItemTemplate>
               <li>
               <div class="user">
                   <!-- 好きなフルーツ -->
                   <%# DataBinder.Eval(Container.DataItem, "[\"Fruits\"]") %>
               </div>
               </li>
        </ItemTemplate>
    </asp:Repeater>
    </td>
</tr>
</ItemTemplate>
</asp:Repeater>
<!-- 繰り返し処理部分 end -->
</table>

データ表示

以下のようにデータが表示されます。


画面側の実装がとてもシンプルに記述出来るようになるので、是非試してみてください。