WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

Eval, Bind の正体

by WebSurfer 2010年8月18日 16:17

データバインド式と Eval メソッドの話が出てきたので、ついでに Eval, Bind メソッドとは一体何かについて調べたことを書いておきます。

前に書いたことのおさらいですが、データバインド式は <%# デリミタと %> デリミタの間に記述され、Eval メソッドと Bind メソッドを使用します。

Eval メソッドは、一方向 (読み取り専用) バインディングを定義するために使用します。Bind メソッドは、双方向 (更新可能) バインディングに使用します。

Eval メソッド

以下は、MSDN ライブラリの「データ バインド式の概要」からの抜粋です。

"Eval メソッドは、名前付けコンテナの現在のデータ項目を参照する DataBinder オブジェクトの Eval メソッドを実行時に呼び出します。"

上記を、自分の理解(独断と偏見?)に基づき、具体的に書いてみます。

例えば以下のように、GirdView の ItemTemplate に配置した Label の Text プロパティにデータバインド式が設定してあったとします。

Text='<%# Eval("Price") %>'

これは DataBinder.Eval 静的メソッドを以下のように呼び出します。

Text='<%# DataBinder.Eval(Container.DataItem, "Price") %>'

第 1 引数に使われている Container は ASP.NET によって自動的に定義され初期化されます。使用されているデータバインドコントロールによって異なりますが、たとえば GridView を使用した場合、Container は GridViewRow になります(詳細後述)。

第 2 引数は、第 1 引数の Container.DataItem オブジェクトから値を取得するプロパティ名またはインデクサ名の文字列となります。例えば、DictionaryEntry.Key の Key などのプロパティ名、または DataRowView["Price"] の Price などのインデクサ名から成る文字列である必要があります。(2010/8/20 一部修正)

DataBinder.Eval メソッドは、第 1 引数で指定したオブジェクトに対して、第 2 引数で指定した名前を持つプロパティの値またはインデクサが指す値を取得して、Object 型として返します。先の DictionaryEntry および DataRowView を例にとると、下記のようになります。(2010/8/20 一部修正)

((DictionaryEntry)Container.DataItem).Key
((DataRowView)Container.DataItem)["Price"]

Eval メソッドで、プログラマが明示的にキャストを書かなくてもよいのはリフレクション機能を利用しているからだそうです。

Bind メソッド

DataBinder クラスには Bind というメソッドはありません。Bind メソッドの詳細が書いてあるドキュメントも見つかりませんでしたが、以下の点以外は Eval と同じと思われます。

GridView、DetailsView、FormView などのデータバインドコントロールのテンプレートに配置した TextBox や CheckBox で Bind を使用すると、それらへの入力値を抽出して、編集モードでは NewValues コレクション経由、挿入モードでは Values コレクション経由で、データソースコントロール(SqlDataSource など)に渡すことができます。

Container.DataItem

DataBinder.Evalメソッドの第 1 引数のオブジェクト Container.DataItem とは何でしょう?

例えばデータバインドコントロールに GridView を使用すると、ASP.NET が自動生成するコードで Container は以下のように定義され、自動的に初期化されるようになっています。

GridViewRow Container;

その他、Repeater, DataGrid, DataList, DetailsView, FormView, ListView などのデータバインドコントロールを用いると、適宜 RepeaterItem, DataGridItem, DataListItem, DetailsView, FormView, ListViewDataItem などが Container として定義され、初期化されるようになっています。

詳しくは、@IT のサイトの Container.DataItemの正体は? を参照してください。

------------ 2010/8/20 追記 ------------

DataBinder.Eval メソッドの第 2 引数は、MSDN ライブラリには "プロパティ名またはフィールド名から成る文字列" と書いてありましたが、インデクサの場合もありますので修正しました。

@IT のサイトの Webフォームにおけるデータ連結 を参照してください。

Tags: ,

ASP.NET

データバインド式

by WebSurfer 2010年8月17日 23:44

<%# 文字と %> 文字で囲んで用いるデータバインド式を使用すると、ページで DataBind メソッドが呼び出されたときに、サーバーコントロールプロパティとデータソースの間にバインディングが作成されます。

Eval や Bind メソッドを TextBox や Label コントロールの Text プロパティに以下のように設定して使うことが多いと思います。

Text='<%# Eval("Name") %>'

上記のような単純な使い方なら間違うことはなさそうですが、複雑な文字列を組み立てる場合は、別にそのためのメソッドを定義して用いるのがよさそうです。

例えば、以下のようにメソッドで文字列を組み立てて、

string Description(string s, int n)
{
  return String.Format("項目 {0} の数量は {1} です。", s, n);
}

それを以下のように設定できます。

Text='<%# Description((string)Eval("Name"), (int)Eval("Qty")) %>'

ただし、メソッドを使うまでもない簡単な文字列なら、例えば以下のようにする方がよいと思います。

Text='<%# "Name:" + Eval("Name") %>'

なお、以下のようにするのは、データバインド式を含めた全体が文字列として解釈されてしまうので、うまくいきません。

Text='Name:<%# Eval("Name") %>'

ありそうな間違いは、ImageUrl や NavigateUrl に、例えば、以下のように設定するケースでしょうか。

ImageUrl='~/Images/<%# Eval("Name") %>'

この結果は以下のようになってしまいます。

src="Images/%3C%25#%20Eval(%22Name%22)%20%25%3E"

(注)ImageUrl の場合は UrlEncode されるので、< や % などが %3C と %25 になります。一方、NavigateUrl の方は何故か UrlEncode されません。

Tags: ,

ASP.NET

PIVOT の使用

by WebSurfer 2010年8月7日 18:18

SQL Server の PIVOT 関係演算子を利用してデータをまとめ、クロス集計レポートを生成し、GridView に表示する例です。

ほとんどの処置はストアドプロシージャで行うので、ASP.NET というよりは SQL Server の機能になりますが。

ここの例では、Microsoft が提供しているサンプルデータベース Northwind の Orders テーブル使用しました。

Orders テーブルは、個々の注文の ID (OrderID, int)、注文した顧客の ID (CustomerID, nchar(5))、注文を取り扱った従業員の ID (EmployeeID, int)、注文を受けた年月日 (OrderDate, datetime) などのデータを約 800 レコード持っています。

DropDownList に顧客名一覧を表示し、その中から顧客を選択すると、その注文を取り扱った従業員と取り扱った注文数を、注文年月ごとに表示するようにしました。以下のような感じです。

PIVOT によるクロス集計レポート

上記のクロス集計を行うためのストアドプロシージャは以下の通りです。

ALTER PROCEDURE dbo.StoredProcedure1
(
@CustomerID nchar(5)
)
AS
DECLARE @sqlstr nvarchar(max), @sqldata nvarchar(max), @employee nvarchar(50); 
DECLARE cur CURSOR FOR 

SELECT DISTINCT EmployeeID 
  FROM Orders 
  WHERE EmployeeID IS NOT NULL AND [CustomerID]=@CustomerID 
  ORDER BY EmployeeID; 

SET @sqldata = N''; 
SET @sqlstr = N'SELECT Year, Month '; 

OPEN cur; 
FETCH NEXT FROM cur INTO @employee; 
WHILE (@@FETCH_STATUS <> - 1) 
  BEGIN 
    IF LEN(@sqldata) > 0 
      BEGIN
        SET @sqldata = @sqldata + N',' 
      END; 
    SET @sqldata = @sqldata + N'[' + @employee + N']'
    SET @sqlstr = @sqlstr + N',[' + @employee + N'] AS [Emp-' + @employee + N']'; 
    FETCH NEXT FROM cur INTO @employee; 
  END; 
CLOSE cur;
DEALLOCATE cur; 

SET @sqlstr = @sqlstr +
  N' FROM 
     (
       SELECT DATEPART(mm, OrderDate) AS Month, DATEPART(yyyy, OrderDate) AS Year, EmployeeID 
       FROM Orders 
       WHERE CustomerID=@ID
     ) AS p 
     PIVOT 
     (
       COUNT(EmployeeID) 
       FOR EmployeeID 
       IN '; 
SET @sqlstr = @sqlstr + N'(' + @sqldata + N')) AS pvt'; 
EXECUTE sp_executesql @sqlstr, N'@ID nchar(5)', @CustomerID

顧客一覧を DropDownList に、クロス集計結果を GridView に表示するための ASP.NET のコードは以下の通りです。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>無題のページ</title>
</head>
<body>
  <form id="form2" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>"             
      SelectCommand="
        SELECT DISTINCT Orders.CustomerID, Customers.CompanyName 
        FROM Orders 
        INNER JOIN Customers 
        ON Orders.CustomerID = Customers.CustomerID">
    </asp:SqlDataSource>

    <asp:DropDownList ID="DropDownList1" 
      runat="server" 
      DataSourceID="SqlDataSource1" 
      DataTextField="CompanyName" 
      DataValueField="CustomerID" 
      AutoPostBack="True">
    </asp:DropDownList>
        
    <asp:SqlDataSource ID="SqlDataSource2" runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand="StoredProcedure1"
      SelectCommandType="StoredProcedure">
      <SelectParameters>
        <asp:ControlParameter 
          ControlID="DropDownList1" 
          Name="CustomerID" 
          PropertyName="SelectedValue" 
          Type="String" />
      </SelectParameters>        
    </asp:SqlDataSource>

    <asp:GridView ID="GridView1" 
      runat="server" 
      DataSourceID="SqlDataSource2">
    </asp:GridView>
  </div>
  </form>
</body>
</html>

Tags: ,

SQL Server

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar