I am noticing some strange behavior when working with datatables stored in session variables. Removing a row from a datatable that is created from a session variable appears to also modify the session variable as demonstrated below.
<asp:GridView ID="gvResults" runat="server" DataKeyNames="id">
<Columns>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:Button ID="btnSelectUserToRemove" runat="server" CausesValidation="false" CommandName="Remove" Text="Select" CommandArgument='<%# Eval("id") %>' OnCommand="Command" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataTable dtResults = new DataTable();
dtResults.Columns.Add("id");
dtResults.Rows.Add();
dtResults.Rows[0]["id"] = "1";
dtResults.Rows.Add();
dtResults.Rows[1]["id"] = "2";
Session["id"] = dtResults;
gvResults.DataSource = dtResults;
gvResults.DataBind();
}
}
protected void Command(object sender, CommandEventArgs e)
{
if (e.CommandName == "Remove")
{
DataTable dtTemp = (DataTable)Session["id"];
for (Int32 i = 0; i < dtTemp.Rows.Count; i++)
{
if (e.CommandArgument.ToString() == dtTemp.Rows[i]["id"].ToString())
{
dtTemp.Rows[i].Delete(); //Should just remove the row from the datatable.
}
}
dtTemp.AcceptChanges();
}
DisplayData();
}
protected void DisplayData()
{
gvResults.DataSource = (DataTable)Session["id"];
gvResults.DataBind(); //Should display both rows because I did not save the modified datatable back to this session variable.
}
}
I am not saving the modified dtTemp
datatable back to the Session["id"]
variable. It is my understanding that there should be 1 row in dtTemp
, because one row was deleted, and 2 rows in Session["id"]
when calling DisplayData
. However, only one row is displayed in the gridview after DisplayData
runs.
I am hoping there is someone out there that can shed some light on why this is happening.
It's because
dtTemp
and the session variable are object references that both point to the same object.This line:
Does not do what you think it does. Since the
DataTable
is a reference type, you're just grabbing a pointer to that object's location in memory (which happens to be in the SessionState variable), not creating a fresh copy of it.If you want to operate on the
DataTable
without modifying the one in Session, you'll need to look into a Clone pattern, like How do you do a deep copy of an object in .NET (C# specifically)?