Ortund
Ortund

Reputation: 8245

How to maintain collections of data in session?

For the purposes of invoicing, I'm keeping track of timesheet entries that are associated with an invoice by storing the selected timesheets in the browser Session and adding/removing entries to that list as the user updates:

The GridView loads all timesheets for the selected company and then indicates by changing row style and select button text:

private void HighlightInvoiceTimesheets()
{
    var timesheets = Session["invoiceTimesheets"] as List<Timesheet>;
    var invoiceTotalHours = 0;
    foreach (var timesheet in timesheets)
    {
        var tid = timesheet.Id.ToString();
        foreach (GridViewRow row in ItemsGrid.Rows)
        {
            var btn = row.Cells[ItemsGrid.Columns.Count - 1].Controls[0] as LinkButton;
            if (ItemsGrid.DataKeys[row.RowIndex].Values["Id"].ToString() == tid)
            {
                row.CssClass = "success";
                btn.Text = "Remove";
                int.TryParse(row.Cells[5].Text, out int timesheetHours);
                invoiceTotalHours += timesheetHours;
            }
        }
    }
    Session["invoiceTotalHours"] = invoiceTotalHours;
    BillableHoursLabel.Text = invoiceTotalHours.ToString();
}

When the user "selects" an item in the GridView, it adds or removes the item from the collection in the Session and updates the GridView accordingly:

protected void ItemsGrid_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
{
    // Get the list of timesheets associated with the invoice.
    var list = (Session["invoiceTimesheets"] == null) ? new List<Timesheet>() : Session["invoiceTimesheets"] as List<Timesheet>;

    // Get the selected timesheet.
    int.TryParse(ItemsGrid.DataKeys[e.NewSelectedIndex].Values["Id"].ToString(), out int timesheetId);
    var timesheet = timesheetService.GetClearTimesheet(timesheetId);

    // Get the select button to update its text.
    var btn = ItemsGrid.Rows[e.NewSelectedIndex].Cells[ItemsGrid.Columns.Count - 1].Controls[0] as LinkButton;

    // Get the total hours billable for the invoice based on the total hours of the timesheets.
    var invoiceTotalHours = (Session["invoiceTotalHours"] == null) ? 0 : int.Parse(Session["invoiceTotalHours"].ToString());

    if (list.Find(x => x.Id == timesheetId) != null)
    {
        // The list contains the selected item, remove it and indicate removed.
        list.Remove(timesheet);
        ItemsGrid.Rows[e.NewSelectedIndex].CssClass = "";
        btn.Text = "Select";
        int.TryParse(Session["invoiceTotalHours"].ToString(), out invoiceTotalHours);
        invoiceTotalHours -= timesheet.BillableHours;
    }
    else
    {
        // The list doesn't contain the selected item, add it and indicate added.
        list.Add(timesheet);
        ItemsGrid.Rows[e.NewSelectedIndex].CssClass = "success";
        btn.Text = "Remove";
        int.TryParse(Session["invoiceTotalHours"].ToString(), out invoiceTotalHours);
        invoiceTotalHours += timesheet.BillableHours;
    }

    BillableHoursLabel.Text = invoiceTotalHours.ToString();
    // Update the collection in the session.
    Session["invoiceTimesheets"] = list;
}

This works without any errors but I'm very confused why list.Remove(timesheet); doesn't actually update the list in memory.

As a result of this, the collection in the session doesn't get updated and changes made don't reflect on the database.

Upvotes: 1

Views: 146

Answers (1)

Mackhdo
Mackhdo

Reputation: 110

It's because the timesheet you're trying to remove isn't the same object as the one you get from

var timesheet = timesheetService.GetClearTimesheet(timesheetId);

instead of this:

if (list.Find(x => x.Id == timesheetId) != null)
{
    // The list contains the selected item, remove it and indicate removed.
    list.Remove(timesheet);

Do this:

var timeSheetSession=list.FirstOrDefault(x => x.Id == timesheetId);
if(timeSheetSession!=null)  list.Remove(timeSheetSession);

it's pseudo code, i didn't test it.

Upvotes: 2

Related Questions