ObjectDataSource + GridView + Disabled ViewState = Major Concurrency Issues (possible solution)

Rate It (1)

Last post 05-30-2008 1:56 PM by nngco. 13 replies.

Sort Posts:

  • ObjectDataSource + GridView + Disabled ViewState = Major Concurrency Issues (possible solution)

    09-16-2006, 10:53 PM

    DISCLAIMER:  I'm no expert on the GridView lifecycle, but empirical evidence seems to suggest this stuff is correct...  I'm sure if I've gotten anything wrong here an expert will jump in and correct me.

    Issue:

    When you hook up a GridView to an ObjectDataSource when the ViewState is disabled, there is a major concurrency issue.  The issue is that if Bob and Joe are both looking at the same list, and Joe deletes Row #3, then Bob goes to delete Row #5, Bob is really going to delete Row #6 (of the original list they were looking at) because all of the rows have shifted upward after Joe's delete.  This could happen even with the ObjectDataSource's concurrency stuff running because things like Delete are just looking at row number.  Note that this might also happen with ViewState enabled - I'm not really sure because I never enable ViewState for big honking GridViews...

    Root Cause:

    When the GridView fires off a Delete event, it sets the form's __EVENTTARGET variable to the ID of the GridView (like ctl00$ContentPlaceHolder1$GridView1) and the __EVENTARGUMENT to "Delete$x" where the "x" part represents the row of the deleted item.  So, Joe fires off his delete of Row #3 and __EVENTARGUMENT is "Delete$3", and this tells the ObjectDataSource "Delete the thing at Row #3", so it grabs the DataKey and does a delete.  Now Bob fires off his delete before refreshing the display and __EVENTARGUMENT gets set to "Delete$5".  Trouble is, now what was Row #5 is really Row #4 because of Joe's previous delete, so the ObjectDataSource ends up deleting the wrong line.  Another side effect of this is that hitting the browser's refresh button immediately after doing a delete of Row #3 will cause whatever happens to now be on Row #3 to be deleted without error.  Again, this might not be the same if you have concurrency set on the ObjectDataSource and ViewState enabled on your GridView - but who wants all of the data in a huge GridView getting sent to the client anyway?

    A Possible Solution:

    Well, the only way I've found to get around this is to just chuck the ObjectDataSource and go back to manually binding my data.  (That's probably a tiny bit faster anyway since the calls can be early-bound.)  Once that's done, you can hook up to the GridView's OnRowCreated event and do something like this:

    if (e.Row.RowType == DataControlRowType.DataRow)
        e.Row.ID = "ctl" + ((MyNamespace.MyClass)e.Row.DataItem).ID;
    

    Doing this will make the ID of the control represent the unique ID of your object instead of the row number. That way command event gets fired if that unique item still exists in the list, but if it doesn't, the command event is never fired.  Also, if you want to let the user know that their action didn't happen because of a concurrency issue, you can check in OnLoad to see if you're in a postback and if FindControl can't find a control with the ID in  __EVENTTARGET then the item they were going to perform the action on is gone and you can give them a notification.

    This method doesn't work at all with the DataSource controls because the event that gets fired for them always uses the GridView as the sender (as opposed to the LinkButton within it) and so there's no way to use this hackery to change from row number to object ID.  I tried just changing the CommandArgument in the OnDeleting event, but it's readonly and that would confuse the DataSource anyway because it's expecting a row number...

    Drawbacks:

    Well, one obvious drawback is you can't use the ObjectDataSource to automagically update your data.  To me that's a very small issue though since writing a "GV1.DataSource=something; GV1.DataBind();" isn't the hardest thing in the world and I don't like alot of automagical stuff anyway...  There are probably other ones that will pop up as I use this more, but for now it's working great for me.

    As always, there's more than one way to beat a mule, so you could also just use HyperLinks for your actions and add your object ID to the querystring if you don't mind adding junk to your querystring.  That'd work too, but again, you couldn't use the ObjectDataSource to automagically delete your data.

    Bottom Line:

    ObjectDataSource is good for quick prototyping or single-user applications, but not so good for real-world applications that will have multiple users updating the same data.

    jdc

    -- jdc
  • Re: ObjectDataSource + GridView + Disabled ViewState = Major Concurrency Issues (possible solution)

    11-14-2006, 11:07 AM

    I also wanted to share my approach [see http://scottonwriting.net/sowblog/posts/10054.aspx for additional comments]:

    In the Editing, Inserting, and Deleting Data tutorials of my Working with Data in ASP.NET 2.0 tutorial series, I demonstrate how the GridView, DetailsView, and FormView can all support the built-in editing, deleting, and inserting capabilities with view state disabled. The reason is because the key data Web control properties (such as the DataKeys collection), are stored in control state, which is always persisted to view state regardless of the control's EnableViewState property value.

    In my tutorials I don't mention the view state issue, I just silently set the EnableViewState property to false. And this works wonderfully when testing the page. Deletes and edits work exactly as expected, with or without view state enabled. However, a rather insidious behavior can rear its head when there are multiple users visiting the same page. This potential trap was pointed out to me by alert reader Jamie Crutchley, whose observed and shared information about this problem on the ASP.NET Forums in the past. I'll explain the problem (and a potential workaround) in my own words, but you can read Jamie's posts here and here, if you'd rather.

    PROBLEM: Two users - Alice and Bob - visit a page (Products.aspx) that uses a GridView whose to list products; the GridView's view state has been disabled. The GridView uses its DataKeys collection to store the primary key values of the three products. Imagine that the products listed are Pens, Books, and Paper, and their respective primary key values are 1, 2, and 3.

    1. Alice clicks on the Delete button for the first product in the grid (Pens).
    2. A postback occurs. Because the GridView's view state has been disabled, on postback the data is re-read from the GridView's data source. This has the side effect of repopulating the DataKeys collection with the newly read data!
    3. Since the first row index was clicked, the GridView grabs the DataKeys value indexed at 0 and issues a delete based on that primary key value (1).
    4. Bob still sees all three products on the page (since he loaded the page before Alice deleted Pens). Sometime after Alice has made her deletion, Bob, too, decides that Pens must be deleted. He clicks on the Delete button for Pens.
    5. A postback occurs. Because the GridView's view state has been disabled, on postback the data is re-read from the GridView's data source. This has the side effect of repopulating the DataKeys collection with the newly read data!
    6. Since the first row index was clicked, the GridView grabs the DataKeys value indexed at 0. However, since the DataKeys collection has been reloaded in Step 5, the first DataKeys value is the primary key of Books (since Pens has since been deleted). The consequence is that Books is deleted, even though Bob wanted to delete Pens!!

    More generally, if Alice deletes any product whose index preceeds the index of the record Bob deletes, Bob's delete will actually delete a different record. Similarly, if Alice deletes a preceeding record of the one Bob is editing, the edits will be applied to a preceeding row. Eep.

    SHORT AND SIMPLE SOLUTION: Unless you are absolutely, 100%, certifiably, unconditionally certain that there will never, ever, not in a million years be two users concurrently editing/deleting records, then be sure to leave the GridView / DetailsView / FormView's EnableViewState property to True (the default).

    MORE INVOLVED SOLUTION: If you really would like to reduce the page size by disabling view state, you can use the following “hack”... When a Delete (or Edit) button is clicked in the GridView the RowCommand event fires before the DataKeys collection is internally repopulated. Therefore, you can create an event handler that includes code that “saves” the DataKeys value(s) for the record being deleted. Then, in the ObjectDataSource's Deleting event handler you can reassign this value back to the primary key parameter(s).

    Here's some code to implement this approach. First, in the RowCommand event handler the primary key (ProductID) is saved in a page-level variable:

        1 int recordToDelete = -1;

        2 protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)

        3 {

        4     recordToDelete = Convert.ToInt32(GridView1.DataKeys[Convert.ToInt32(e.CommandArgument)].Value);

        5 }

    Then, in the ObjectDataSource's Deleting event, assign the page-level variable to the appropriate parameter:

        1 protected void ObjectDataSource1_Deleting(object sender, ObjectDataSourceMethodEventArgs e)

        2 {

        3     if (recordToDelete > 0)

        4         e.InputParameters["ProductID"] = recordToDelete;

        5 }

     

    The tutorials and code at Working with Data in ASP.NET 2.0 will be updated so that they no longer disable view state and will include a similar warning as to this blog entry, although due to the breadth of material online, it may take several days or weeks to get all the changes made and propagated...

     http://scottonwriting.net/sowblog/posts/10054.aspx

    Happy Programming!


    -- Scott Mitchell
    -- mitchell@4guysfromrolla.com
    -- http://scottonwriting.net/sowblog/
    -- http://www.4GuysFromRolla.com/ScottMitchell.shtml
  • Re: ObjectDataSource + GridView + Disabled ViewState = Major Concurrency Issues (possible solution)

    12-05-2006, 2:25 PM
    • Loading...
    • RichardD
    • Joined on 09-03-2002, 11:43 AM
    • Sussex, UK
    • Posts 91
    This workaround doesn't seem to work for a GridView bound to an ObjectDataSource control:
    • The CommandArgument is not set for the RowCommand event.
    • By the time the RowCommand event is raised, the DataKeys collection has already been updated.

    The only solution I've found is to create a derived control:
    • Override the OnLoad LoadControlState method and take a copy of the DataKeys;
    • Override the OnBubbleEvent, cast the source parameter to a GridViewRow, and use the RowIndex to find the key from the copied list;
    • Finally, override the RowDeleting and RowUpdating methods, and copy the values from the original key to the event arguments.

    1    using System;
    2 using System.Collections;
    3 using System.Web;
    4 using System.Web.UI;
    5 using System.Web.UI.WebControls;
    6
    7 public class ExtendedGridView : GridView
    8 {
    9 private DataKey[] _originalDataKeys;
    10 private DataKey _rowCommandDataKey;
    11
    12 public ExtendedGridView()
    13 {
    14 }
    15
    16 protected override void LoadControlState(object savedState)
    17 {
    18 base.LoadControlState(savedState);
    19
    20 if (!EnableViewState)
    21 {
    22 DataKeyArray keys = this.DataKeys;
    23 if (null != keys && 0 != keys.Count)
    24 {
    25 _originalDataKeys = new DataKey[keys.Count];
    26 keys.CopyTo(_originalDataKeys, 0);
    27 }
    28 }
    29 }
    30
    31 protected override bool OnBubbleEvent(object source, EventArgs e)
    32 {
    33 if (null != _originalDataKeys)
    34 {
    35 GridViewRow row = source as GridViewRow;
    36 GridViewCommandEventArgs args = e as GridViewCommandEventArgs;
    37 if (null != row && null != args)
    38 {
    39 _rowCommandDataKey = _originalDataKeys[row.RowIndex];
    40 }
    41 }
    42
    43 return base.OnBubbleEvent(source, e);
    44 }
    45
    46 protected override void OnRowDeleting(GridViewDeleteEventArgs e)
    47 {
    48 if (null != _rowCommandDataKey)
    49 {
    50 foreach (DictionaryEntry entry in _rowCommandDataKey.Values)
    51 {
    52 e.Keys[entry.Key] = entry.Value;
    53 }
    54
    55 _rowCommandDataKey = null;
    56 _originalDataKeys = null;
    57 }
    58
    59 base.OnRowDeleting(e);
    60 }
    61
    62 protected override void OnRowUpdating(GridViewUpdateEventArgs e)
    63 {
    64 if (null != _rowCommandDataKey)
    65 {
    66 foreach (DictionaryEntry entry in _rowCommandDataKey.Values)
    67 {
    68 e.Keys[entry.Key] = entry.Value;
    69 }
    70
    71 _rowCommandDataKey = null;
    72 _originalDataKeys = null;
    73 }
    74
    75 base.OnRowUpdating(e);
    76 }
    77 }
     
  • Re: ObjectDataSource + GridView + Disabled ViewState = Major Concurrency Issues (possible solution)

    12-05-2006, 2:47 PM
    • Loading...
    • RichardD
    • Joined on 09-03-2002, 11:43 AM
    • Sussex, UK
    • Posts 91
  • Re: ObjectDataSource + GridView + Disabled ViewState = Major Concurrency Issues (possible solution)

    12-05-2006, 11:43 PM

    My workaround works fine in my tests using an ObjectDataSource bound to the GridView. The following works for me:

      

    1    <%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Basics.aspx.cs" Inherits="EditInsertDelete_Basics" Title="Untitled Page" %>
    2    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" Runat="Server">
    3        <h2>
    4            The Basics of Editing, Inserting, and Deleting</h2>
    5            <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DeleteMethod="DeleteProduct"
    6                InsertMethod="AddProduct" SelectMethod="GetProducts"
    7                TypeName="ProductsBLL" UpdateMethod="UpdateProduct" OnDataBinding="ObjectDataSource1_DataBinding" OnDeleting="ObjectDataSource1_Deleting" OnSelecting="ObjectDataSource1_Selecting">
    8                <DeleteParameters>
    9                    <asp:Parameter Name="productID" Type="Int32" />
    10               </DeleteParameters>
    11               <UpdateParameters>
    12                   <asp:Parameter Name="productName" Type="String" />
    13                   <asp:Parameter Name="supplierID" Type="Int32" />
    14                   <asp:Parameter Name="categoryID" Type="Int32" />
    15                   <asp:Parameter Name="quantityPerUnit" Type="String" />
    16                   <asp:Parameter Name="unitPrice" Type="Decimal" />
    17                   <asp:Parameter Name="unitsInStock" Type="Int16" />
    18                   <asp:Parameter Name="unitsOnOrder" Type="Int16" />
    19                   <asp:Parameter Name="reorderLevel" Type="Int16" />
    20                   <asp:Parameter Name="discontinued" Type="Boolean" />
    21                   <asp:Parameter Name="productID" Type="Int32" />
    22               </UpdateParameters>
    23               <InsertParameters>
    24                   <asp:Parameter Name="productName" Type="String" />
    25                   <asp:Parameter Name="supplierID" Type="Int32" />
    26                   <asp:Parameter Name="categoryID" Type="Int32" />
    27                   <asp:Parameter Name="quantityPerUnit" Type="String" />
    28                   <asp:Parameter Name="unitPrice" Type="Decimal" />
    29                   <asp:Parameter Name="unitsInStock" Type="Int16" />
    30                   <asp:Parameter Name="unitsOnOrder" Type="Int16" />
    31                   <asp:Parameter Name="reorderLevel" Type="Int16" />
    32                   <asp:Parameter Name="discontinued" Type="Boolean" />
    33               </InsertParameters>
    34           </asp:ObjectDataSource>
    35       <h3>Editing, Inserting, and Deleting Data from a FormView</h3>
    36       <p>
    37           <asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True" EnableViewState="False">
    38               <EditItemTemplate>
    39                   ProductID:
    40                   <asp:Label ID="ProductIDLabel1" runat="server" Text='<%# Eval("ProductID") %>'></asp:Label><br />
    41                   ProductName:
    42                   <asp:TextBox ID="ProductNameTextBox" runat="server" Text='<%# Bind("ProductName") %>'>
    43                   </asp:TextBox><br />
    44                   SupplierID:
    45                   <asp:TextBox ID="SupplierIDTextBox" runat="server" Text='<%# Bind("SupplierID") %>'>
    46                   </asp:TextBox><br />
    47                   CategoryID:
    48                   <asp:TextBox ID="CategoryIDTextBox" runat="server" Text='<%# Bind("CategoryID") %>'>
    49                   </asp:TextBox><br />
    50                   QuantityPerUnit:
    51                   <asp:TextBox ID="QuantityPerUnitTextBox" runat="server" Text='<%# Bind("QuantityPerUnit") %>'>
    52                   </asp:TextBox><br />
    53                   UnitPrice:
    54                   <asp:TextBox ID="UnitPriceTextBox" runat="server" Text='<%# Bind("UnitPrice") %>'>
    55                   </asp:TextBox><br />
    56                   UnitsInStock:
    57                   <asp:TextBox ID="UnitsInStockTextBox" runat="server" Text='<%# Bind("UnitsInStock") %>'>
    58                   </asp:TextBox><br />
    59                   UnitsOnOrder:
    60                   <asp:TextBox ID="UnitsOnOrderTextBox" runat="server" Text='<%# Bind("UnitsOnOrder") %>'>
    61                   </asp:TextBox><br />
    62                   ReorderLevel:
    63                   <asp:TextBox ID="ReorderLevelTextBox" runat="server" Text='<%# Bind("ReorderLevel") %>'>
    64                   </asp:TextBox><br />
    65                   Discontinued:
    66                   <asp:CheckBox ID="DiscontinuedCheckBox" runat="server" Checked='<%# Bind("Discontinued") %>' />
    67                   <br />
    68                   <asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
    69                       Text="Update">
    70                   </asp:LinkButton>
    71                   <asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False" CommandName="Cancel"
    72                       Text="Cancel">
    73                   </asp:LinkButton>
    74               </EditItemTemplate>
    75               <InsertItemTemplate>
    76                   ProductName:
    77                   <asp:TextBox ID="ProductNameTextBox" runat="server" Text='<%# Bind("ProductName") %>'>
    78                   </asp:TextBox><br />
    79                   SupplierID:
    80                   <asp:TextBox ID="SupplierIDTextBox" runat="server" Text='<%# Bind("SupplierID") %>'>
    81                   </asp:TextBox><br />
    82                   CategoryID:
    83                   <asp:TextBox ID="CategoryIDTextBox" runat="server" Text='<%# Bind("CategoryID") %>'>
    84                   </asp:TextBox><br />
    85                   QuantityPerUnit:
    86                   <asp:TextBox ID="QuantityPerUnitTextBox" runat="server" Text='<%# Bind("QuantityPerUnit") %>'>
    87                   </asp:TextBox><br />
    88                   UnitPrice:
    89                   <asp:TextBox ID="UnitPriceTextBox" runat="server" Text='<%# Bind("UnitPrice") %>'>
    90                   </asp:TextBox><br />
    91                   UnitsInStock:
    92                   <asp:TextBox ID="UnitsInStockTextBox" runat="server" Text='<%# Bind("UnitsInStock") %>'>
    93                   </asp:TextBox><br />
    94                   UnitsOnOrder:
    95                   <asp:TextBox ID="UnitsOnOrderTextBox" runat="server" Text='<%# Bind("UnitsOnOrder") %>'>
    96                   </asp:TextBox><br />
    97                   ReorderLevel:
    98                   <asp:TextBox ID="ReorderLevelTextBox" runat="server" Text='<%# Bind("ReorderLevel") %>'>
    99                   </asp:TextBox><br />
    100                  Discontinued:
    101                  <asp:CheckBox ID="DiscontinuedCheckBox" runat="server" Checked='<%# Bind("Discontinued") %>' /><br />
    102                  <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert"
    103                      Text="Insert">
    104                  </asp:LinkButton>
    105                  <asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False" CommandName="Cancel"
    106                      Text="Cancel">
    107                  </asp:LinkButton>
    108              </InsertItemTemplate>
    109              <ItemTemplate>
    110                  ProductID:
    111                  <asp:Label ID="ProductIDLabel" runat="server" Text='<%# Eval("ProductID") %>'></asp:Label><br />
    112                  ProductName:
    113                  <asp:Label ID="ProductNameLabel" runat="server" Text='<%# Bind("ProductName") %>'>
    114                  </asp:Label><br />
    115                  SupplierID:
    116                  <asp:Label ID="SupplierIDLabel" runat="server" Text='<%# Bind("SupplierID") %>'>
    117                  </asp:Label><br />
    118                  CategoryID:
    119                  <asp:Label ID="CategoryIDLabel" runat="server" Text='<%# Bind("CategoryID") %>'>
    120                  </asp:Label><br />
    121                  QuantityPerUnit:
    122                  <asp:Label ID="QuantityPerUnitLabel" runat="server" Text='<%# Bind("QuantityPerUnit") %>'>
    123                  </asp:Label><br />
    124                  UnitPrice:
    125                  <asp:Label ID="UnitPriceLabel" runat="server" Text='<%# Bind("UnitPrice") %>'></asp:Label><br />
    126                  UnitsInStock:
    127                  <asp:Label ID="UnitsInStockLabel" runat="server" Text='<%# Bind("UnitsInStock") %>'>
    128                  </asp:Label><br />
    129                  UnitsOnOrder:
    130                  <asp:Label ID="UnitsOnOrderLabel" runat="server" Text='<%# Bind("UnitsOnOrder") %>'>
    131                  </asp:Label><br />
    132                  ReorderLevel:
    133                  <asp:Label ID="ReorderLevelLabel" runat="server" Text='<%# Bind("ReorderLevel") %>'>
    134                  </asp:Label><br />
    135                  Discontinued:
    136                  <asp:CheckBox ID="DiscontinuedCheckBox" runat="server" Checked='<%# Bind("Discontinued") %>'
    137                      Enabled="false" /><br />
    138                  CategoryName:
    139                  <asp:Label ID="CategoryNameLabel" runat="server" Text='<%# Bind("CategoryName") %>'>
    140                  </asp:Label><br />
    141                  SupplierName:
    142                  <asp:Label ID="SupplierNameLabel" runat="server" Text='<%# Bind("SupplierName") %>'>
    143                  </asp:Label><br />
    144                  <asp:LinkButton ID="EditButton" runat="server" CausesValidation="False" CommandName="Edit"
    145                      Text="Edit">
    146                  </asp:LinkButton>
    147                  <asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False" CommandName="Delete"
    148                      Text="Delete">
    149                  </asp:LinkButton>
    150                  <asp:LinkButton ID="NewButton" runat="server" CausesValidation="False" CommandName="New"
    151                      Text="New">
    152                  </asp:LinkButton>
    153              </ItemTemplate>
    154          </asp:FormView>
    155           </p>
    156      <h3>
    157          Editing, Inserting, and Deleting Data from a DetailsView</h3>
    158      <p>
    159          <asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False" DataKeyNames="ProductID"
    160              DataSourceID="ObjectDataSource1" AllowPaging="True" EnableViewState="False">
    161              <Fields>
    162                  <asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False"
    163                      ReadOnly="True" SortExpression="ProductID" />
    164                  <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
    165                  <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" SortExpression="SupplierID" />
    166                  <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" />
    167                  <asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" SortExpression="QuantityPerUnit" />
    168                  <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" />
    169                  <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
    170                  <asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" />
    171                  <asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel" SortExpression="ReorderLevel" />
    172                  <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" />
    173                  <asp:BoundField DataField="CategoryName" HeaderText="CategoryName" ReadOnly="True"
    174                      SortExpression="CategoryName" InsertVisible="False" />
    175                  <asp:BoundField DataField="SupplierName" HeaderText="SupplierName" ReadOnly="True"
    176                      SortExpression="SupplierName" InsertVisible="False" />
    177                  <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowInsertButton="True" />
    178              </Fields>
    179          </asp:DetailsView>
    180           </p>
    181      <h3>
    182          Editing and Deleting Data from a GridView</h3>
    183      <p>
    184          <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" EnableViewState="False" OnRowCommand="GridView1_RowCommand">
    185              <Columns>
    186                  <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
    187                  <asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False"
    188                      ReadOnly="True" SortExpression="ProductID" />
    189                  <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
    190                  <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" SortExpression="SupplierID" />
    191                  <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" />
    192                  <asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" SortExpression="QuantityPerUnit" />
    193                  <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" />
    194                  <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
    195                  <asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" />
    196                  <asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel" SortExpression="ReorderLevel" />
    197                  <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" />
    198                  <asp:BoundField DataField="CategoryName" HeaderText="CategoryName" ReadOnly="True"
    199                      SortExpression="CategoryName" />
    200                  <asp:BoundField DataField="SupplierName" HeaderText="SupplierName" ReadOnly="True"
    201                      SortExpression="SupplierName" />
    202              </Columns>
    203          </asp:GridView>
    204            </p>
    205  </asp:Content>
    

     

     

     

    1    using System;
    2    using System.Data;
    3    using System.Configuration;
    4    using System.Collections;
    5    using System.Web;
    6    using System.Web.Security;
    7    using System.Web.UI;
    8    using System.Web.UI.WebControls;
    9    using System.Web.UI.WebControls.WebParts;
    10   using System.Web.UI.HtmlControls;
    11   
    12   public partial class EditInsertDelete_Basics : System.Web.UI.Page
    13   {
    14       
    15   
    16       protected void Page_Load(object sender, EventArgs e)
    17       {
    18           int y = 0;
    19       }
    20       protected void ObjectDataSource1_Deleting(object sender, ObjectDataSourceMethodEventArgs e)
    21       {
    22           if (recordToDelete > 0)
    23               e.InputParameters["ProductID"] = recordToDelete;
    24       }
    25       protected void ObjectDataSource1_DataBinding(object sender, EventArgs e)
    26       {
    27           int x = 0;
    28       }
    29       protected void ObjectDataSource1_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
    30       {
    31           int x = 0;
    32       }
    33   
    34       int recordToDelete = -1;
    35       protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
    36       {
    37           recordToDelete = Convert.ToInt32(GridView1.DataKeys[Convert.ToInt32(e.CommandArgument)].Value);
    38           int x = 0;
    39       }
    40   }
    41   
    
      
    Happy Programming!


    -- Scott Mitchell
    -- mitchell@4guysfromrolla.com
    -- http://scottonwriting.net/sowblog/
    -- http://www.4GuysFromRolla.com/ScottMitchell.shtml
  • Re: ObjectDataSource + GridView + Disabled ViewState = Major Concurrency Issues (possible solution)

    12-06-2006, 6:23 AM
    • Loading...
    • RichardD
    • Joined on 09-03-2002, 11:43 AM
    • Sussex, UK
    • Posts 91

    The workaround works fine if you're using a CommandField, but not if you're using a TemplateField.

    • With a CommandField, the generated postback script looks like:
      __doPostBack('GridView1','Delete$2')
    • With a TemplateField, the script looks like:
      __doPostBack('grdData$ctl04$ctl00','')

    Using a TemplateField, the child controls have to be re-created before the event can be raised, which involves re-binding the grid to the data source. As a result, by the time the RowCommand event is raised, the DataKeys collection has been re-populated.

  • Re: ObjectDataSource + GridView + Disabled ViewState = Major Concurrency Issues (possible solution)

    12-06-2006, 9:27 AM

    Unfortunately I've lost the code, but I experimented once with creating a derived button control that would emit a "doPostBack" script targetted to it's parent when placed in a templated control.  So instead of doing __doPostBack('grdData$ctl04$ctl00','') it would do __doPostBack('grdData','Delete$2').  That way the event could be raised as if it came from the gridview before instantiating the templated controls.  I wish I still had the code so I could show it to you, but essentially I just overrode the Render method.  There's probably a better way to do it, but I was just playing around with alternatives at the time.

     

    -- jdc