WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

削除の際の @original_xxx はどこから取得?

by WebSurfer 24. June 2012 00:21

楽観的同時実行制御を有効にした時、クエリの WHERE 句には [xxx] = @original_xxx というような条件が設定されます。SqlDataSource と DetailsView などを使った場合の削除操作の際、@original_xxx はどこから取得されるでしょうか?

DetailsView での削除操作

上の画像の例では、ItemTemplate に Label を配置して文字列を表示するようにしていますが、削除操作を行う場合、@original_xxx はどこから取得されるかというと、ItemTemplate に配置した Label の Text プロパティからです。

Label に文字列を表示しているのにブラウザの表示で改行されているのは DetailsView.PreRender イベントのハンドラで Environment.NewLine を "<br />" に置き換えているからです。

従って、このように表示される文字列をプログラムで書き換えてしまうと、DELETE クエリの WHERE 句で [xxx] = @original_xxx が成立しないので、削除に失敗します。(これは DetailsView に限らず、GridView などでも同じです)

ちなみに、Text='<%# Bind("text") %>' の Bind を Eval に変更すると、 DetailsViewDeleteEventArgs.Values["text"] は null になります。その 結果、削除ボタンクリックで InvalidOperationException がスローされます。

というわけで、楽観的同時実行制御を行って、この例のように Environment.NewLine を "<br />" に置き換えて表示するような場合、削除操作直前に、@original_text に代入される文字列を元に戻すしかなさそうです。

それは、以下のコードのように、SqlDataSource.Deleting イベントのハンドラで行うのがよさそうです。

<%@ 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">
  // ウィザードで作っていくと Label も Text='<%# Bind("text") %>' 
  // となる。なぜなら、@original_text に代入される文字列は Text 
  // プロパティから取得するから。それゆえ、以下のようにプログラム
  // で表示する文字列を書き換えると [text] = @original_text が 
  // true にならず、削除に失敗する。
  // Text='<%# Bind("text") %>' の Bind を Eval に変更すると、
  // DetailsViewDeleteEventArgs.Values["text"] は null になる。
  // 結果、[削除]ボタンクリックで InvalidOperationException
  // がスローされる。
  protected void DetailsView1_PreRender(object sender, 
    EventArgs e)
  {
    Control control = 
      ((DetailsView)sender).FindControl("Label1");

    if (control != null)
    {
      Label label = (Label)control;
      label.Text = 
        label.Text.Replace(Environment.NewLine, "<br />");
    }
  }

  // 検証用
  protected void DetailsView1_ItemDeleting(object sender, 
    DetailsViewDeleteEventArgs e)
  {
    // Environment.NewLine が <br /> に変更されて
    // いることが確認できる。
    string text = (string)e.Values["text"];
  }

  protected void SqlDataSource1_Deleting(object sender, 
    SqlDataSourceCommandEventArgs e)
  {
    // 削除を可能するには @original_text に代入される文字
    // 列を元に戻すしかない。
    string text = 
      (string)e.Command.Parameters["@original_text"].Value;
    text = text.Replace("<br />", Environment.NewLine);
    e.Command.Parameters["@original_text"].Value = text;
  }

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
      ConflictDetection="CompareAllValues" 
      ConnectionString="<%$ ConnectionStrings:MyDB %>" 
      DeleteCommand=
        "DELETE FROM [Table3] 
        WHERE [id] = @original_id AND [text] = @original_text" 
      InsertCommand=
        "INSERT INTO [Table3] ([text]) VALUES (@text)" 
      OldValuesParameterFormatString="original_{0}" 
      SelectCommand="SELECT [id], [text] FROM [Table3]" 
      UpdateCommand=
        "UPDATE [Table3] 
        SET [text] = @text 
        WHERE [id] = @original_id AND [text] = @original_text" 
      OnDeleting="SqlDataSource1_Deleting">
      <DeleteParameters>
        <asp:Parameter Name="original_id" Type="Int32" />
        <asp:Parameter Name="original_text" Type="String" />
      </DeleteParameters>
      <InsertParameters>
        <asp:Parameter Name="text" Type="String" />
      </InsertParameters>
      <UpdateParameters>
        <asp:Parameter Name="text" Type="String" />
        <asp:Parameter Name="original_id" Type="Int32" />
        <asp:Parameter Name="original_text" Type="String" />
      </UpdateParameters>
    </asp:SqlDataSource>

    <asp:DetailsView ID="DetailsView1" 
      runat="server" 
      AllowPaging="True" 
      AutoGenerateRows="False" 
      DataKeyNames="id" 
      DataSourceID="SqlDataSource1" 
      Width="550px" 
      OnPreRender="DetailsView1_PreRender" 
      OnItemDeleting="DetailsView1_ItemDeleting">
      <Fields>
        <asp:BoundField DataField="id" 
          HeaderText="id" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="id" />
        <asp:TemplateField HeaderText="text" 
          SortExpression="text">
          <EditItemTemplate>
            <asp:TextBox ID="TextBox1" 
              runat="server" 
              Rows="15" 
              Text='<%# Bind("text") %>' 
              TextMode="MultiLine" 
              Width="500px">
            </asp:TextBox>
          </EditItemTemplate>
          <InsertItemTemplate>
            <asp:TextBox ID="TextBox1" 
              runat="server" 
              Rows="15" 
              Text='<%# Bind("text") %>' 
              TextMode="MultiLine" 
              Width="500px">
            </asp:TextBox>
          </InsertItemTemplate>
          <ItemTemplate>
            <asp:Label ID="Label1" 
              runat="server" 
              Text='<%# Eval("text") %>'>
            </asp:Label>
          </ItemTemplate>
        </asp:TemplateField>
        <asp:CommandField 
          ShowDeleteButton="True" 
          ShowEditButton="True" 
          ShowInsertButton="True" />
      </Fields>
    </asp:DetailsView>
  </div>
  </form>
</body>
</html>

Tags:

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  September 2020  >>
MoTuWeThFrSaSu
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar