あるテーブルを表示している GridView に 1 列追加し、そこに別テーブルからその行に関連する複数のレコード/フィールドを取得して表示するという話です。
結果は以下のような画面になります。MaterialDetails が追加した列です。
以下に具体的な例を説明します。
データベースで、「製品」は Products テーブルにて、「原料」は Materials テーブルにて管理されているとします。「製品」に使用されている「原料」の情報は Products や Materials テーブルには埋め込まず、関連を Relations という別テーブルで管理するとします。以下のような感じです。
製品テーブル (Products)
ProductID int
ProductName nvarchar(50)
UnitPrice money
関連テーブル (Relations)
ProductID int
MaterialID int
原料テーブル (Materials)
MaterialID int
MaterialName nvarchar(50)
SupplierID int
Products テーブルをベースに作った「製品」一覧の GridView に 1 列追加して、その列に、「製品」に使われている「原料」を表示します。
Materials テーブルから、関連するレコードの MaterialID, MaterialName, SupplierID をRelations テーブルを基に抽出し、追加した列に表示します。
製品 X には原料 a, b が、製品 Y には原料 a, e, f, h が使われているというように、追加した列に表示する Materials テーブルのレコード数は各行で一定ではありません。それに対応するための工夫が必要です。
具体的な手順は、以下のようになります。「原料」で表示するのが 1 フィールドだけでよいということであれば、もう少し簡単にできますが、基本的には以下の手順と同様です。
(1) Products の 型付 DataSet + TableAdapter
ソリューションにデータセット(xsd ファイル)を追加します。それにツールボックスから TableAdapter をドラッグ&ドロップします。
自動的に「TableAdapter 構成ウィザード」が起動しますので、そのウィザードを利用して Products テーブル用の型付 DataSet + TableAdapter を作成します。
基になる SELECT クエリは下記のようにします。
SELECT ProductID, ProductName, UnitPrice
FROM Products
ウィザードが完了したら xsd ファイルを保存してください。その後、デザイナ画面のテーブル部分を右クリックして、[追加]→[列]で MaterialDetails 列を追加します。型はデフォルトで String になるはずです。
(2) Materials の型付 DataSet + TableAdapter
上記と同じ xsd ファイルの画面にツールボックスからもう一つ TableAdapter をドラッグ&ドロップし、クエリビルダで Materials テーブルと Relations テーブルの二つを追加します。
基になる SELECT クエリは下記のようにし、ウィザードを完了させます。
SELECT m.MaterialID, m.MaterialName, m.SupplierID
FROM Materials AS m
INNER JOIN Relations AS r
ON m.MaterialID = r.MaterialID
WHERE (r.ProductID = @ProductID)
上記 (1), (2) の結果は、以下の画面のようになります。
(3) GetProductsWithMaterials メソッド
ソリューションにクラスファイルを追加します。Products, Materials テーブルから必要なデータを抽出し、上記 (1) で作った型付 DataTable を初期化して返すメソッドを作成し、クラスファイルに実装します。
Products テーブルの TableAdapter を拡張する形で partial class にしてください。以下のような感じです。
using System;
using System.IO;
using System.ComponentModel;
namespace ProductsDataSetTableAdapters
{
public partial class ProductsTableAdapter
{
[DataObjectMethod(DataObjectMethodType.Select, true)]
public ProductsDataSet.ProductsDataTable GetProductsWithMaterials()
{
ProductsDataSet.ProductsDataTable prodTable = this.GetData();
MaterialsTableAdapter adapter = new MaterialsTableAdapter();
foreach (ProductsDataSet.ProductsRow row in prodTable.Rows)
{
ProductsDataSet.MaterialsDataTable mtrlTable =
adapter.GetData(row.ProductID);
StringWriter writer = new StringWriter();
mtrlTable.WriteXml(writer);
row.MaterialDetails = writer.ToString();
}
return prodTable;
}
}
}
(4) aspx ファイル
データを表示する Web ページ(aspx ファイル)を作成します。ObjectDataSource と GridView を利用した例は下記の通りです。MaterialDetails 列の xml データは GridView の RowDataBound イベントで適宜書き換えます。
この例では、xml データを DataTable に戻して、GridView の中にもう一つ GridView を作って表示しています。GridView を使わず、文字列で表示するなど、別の方法も検討してみてください。
<%@ Page Language="C#" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string xmlMaterialDetails =
(string)((DataRowView)e.Row.DataItem)["MaterialDetails"];
StringReader reader = new StringReader(xmlMaterialDetails);
ProductsDataSet.MaterialsDataTable table =
new ProductsDataSet.MaterialsDataTable();
table.ReadXml(reader);
GridView gv = new GridView();
gv.DataSource = table;
e.Row.Cells[3].Controls.Clear();
e.Row.Cells[3].Controls.Add(gv);
gv.DataBind();
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ObjectDataSource ID="ObjectDataSource1"
runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductsWithMaterials"
TypeName="ProductsDataSetTableAdapters.ProductsTableAdapter">
</asp:ObjectDataSource>
<asp:GridView ID="GridView1"
runat="server"
AutoGenerateColumns="False"
DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1"
OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="ProductID"
HeaderText="ProductID"
InsertVisible="False"
ReadOnly="True"
SortExpression="ProductID" />
<asp:BoundField DataField="ProductName"
HeaderText="ProductName"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice"
HeaderText="UnitPrice"
SortExpression="UnitPrice" />
<asp:BoundField DataField="MaterialDetails"
HeaderText="MaterialDetails"
SortExpression="MaterialDetails" />
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>
以上、ちょっと凝ったことをしましたが、「製品」:「原料」の関係が 1:1 もしくは 1:n (n=一定) の関係なら、3 つのテーブルを INNER JOIN した SELECT クエリをベースに、SqlDataSource と ListView で表示した方が簡単だと思います。