How do I persist checked rows on a grid that is populated from Cache instead of Session?

Go To StackoverFlow.com

0

I get a large list of data to populate into a jqGrid on my clientside.

List<MyData> lotsOfRecords = getData();

Which I then store in cache, since a lot of people will be using it:

Cache["SharedData"].Add(lotsOfRecords);

This grid allows users to check records for processing. I want to persist which records are checked as a user sorts, filters, pages, etc.

My first thought was to add a property bool Selected { get; set; } to the MyData object, and toggle it whenever someone checks a field. Obviously, that won't work since this is a shared cache. I don't want Joe User checking things that Bill User didn't want checked.

Next idea was to store a Dictionary<int, bool> in session, that maps the id of a record to the checked status. This wasn't bad, but since there is no easy way to combine objects in .NET, I don't see a clean way to send that down to my grid without a clunky anonymous object:

return lotsOfRecords.Select(record => {
     record.Id,
     record.Name,
     ...
     myDictionary[record.Id] // true/false for checked
};

That would be a solution, but I'm hoping there is a cleaner design pattern considering I have a lot of fields in my object and use it in a similar way across a few pages. Any suggestions are welcome. Thanks in advance!

Btw, my current environment is ASP.NET MVC 3 with jQuery/UI and jqGrid.

2012-04-04 21:02
by IronicMuffin


1

You may be caching the list, but the selections will need to be user-specific. I would suggest building a list of the selected indices each time the page is posted back, and store the list session.

Here's a function that we're using to remember selections as the user pages through results:

/// <summary>
/// Iterates through items in the grid and updates the selected vendor 
/// list with any selections or deselections on the current page
/// </summary>
private void UpdateSelectedItems()
{
    var selectedVendors = new List<int>();

    foreach (GridItem Item in grdVendors.Items)
    {
        if (Item is GridDataItem)
        {
            int VendorID = (int)((GridDataItem)Item).GetDataKeyValue("SupplierID");
            if (Item.Selected)
            {
                if (!selectedVendors.Contains(VendorID))
                    selectedVendors.Add(VendorID);
                continue;
            }

            selectedVendors.Remove(VendorID);
        }
    }            
}
2012-04-04 21:54
by James Johnson


1

I'm not sure why you think "combining" objects is tough. You can simply do this:

public class SelectableDataObject
{

   public SelectableDataObject(MyDataObject obj)
   {
      this.DataObject = obj;
   }

   public MyDataObject DataObject { get; private set; }
   public bool Selected {get;set;}

}

Then you can just do this:

return lotsOfRecords.Select(record => {
     return new SelectableDataObject(record){Selected = myDictionary.ContainsKey(record.Id)}
};

Alternatively, in your view model you can have the list of objects and the dictionary as two separate properties, and when you iterate the list of objects in your view to populate your grid, you can check the dictionary if the Id exists and check/uncheck based on that. This way is a bit more clunky, but should work.

Either way, I think your dictionary idea is perfectly fine, the only thing I'd do different is just store the Id's of the ones that are selected, that way you only store a subset for each user.

2012-04-04 21:29
by BFree
Right, I could combine it like that, but it adds a layer. Perhaps I'm spoiled by jquery's $.extend() method. I wanted the props all at the same nesting level - IronicMuffin 2012-04-05 12:42
@IronicMuffin Well obviously that's not possible in a static language like C#, however if you really want "one layer" (which I honestly don't think is necessary) you can create a new class that has all the properties from your original class, plus the one boolean property. You can then use AutoMapper to build up the new object from the old one. Overkill if you ask me, but that's the closest you can get - BFree 2012-04-05 15:04
Right...so not possible/no easy solution. Thank you for the insight on it - IronicMuffin 2012-04-05 17:19
Ads