Overview

As you now Grid.Mvc uses IQueryable<T> interface to construct query expressions to your data collection.
When you go to some page the grid invokes .Skip(N).Take(N) methods and when you sort data the grid invokes OrderBy or OrderByDescending methods etc.
If you pass IQueryable collection produced by ORM (like Entity Framework), in this case the ORM will generate query to database. In this case Grid.Mvc queries only one page of data, that currently displayed.
If you want to see how it works, you can download the source code and learn it.

The problem

This mechanism works fine with large amount of data in the table, because Grid.Mvc loads items, that need to be displayed. But in real projects may exist there following moment:
The model item, displayed in the grid is different from data, stored in the table, and some properties need to be instantiated by other services.
I try to explain on the following example: we have some FooDto items, stored in the database, and querying it, using ORM:

    public class FooDto
    {
        public int Id { get; set; }
        public string Title { get; set; }
    }

And structure, that we want to display in the grid:

    public class FooGridItem
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public bool CanEdit { get; set; }
    }

Property CanEdit tells that current user can edit this foo item, and we need to show edit button. This property should be initialized from IPermissionManager class:

    public interface IPermissionManager
    {
        bool DoesCurrentUserCanEditFoo(int id);
    }

Controller:

        public ActionResult List()
        {
            var items = _fooRepository.GetAll() /*returns IQueryable<T>*/
                                      .Select(fooDto => new FooGridItem
                                          {
                                              Id = fooDto.Id,
                                              Title = fooDto.Title
                                          });
            return View(items);
        }

View:

@Html.Grid(Model).Columns(columns =>
      {
          columns.Add(f => f.CanEdit)
              .RenderValueAs(f => f.CanEdit ? Html.ActionLink("Edit", "Edit") : MvcHtmlString.Create(string.Empty));
          
          columns.Add(f => f.Title);
      }).Sortable().WithPaging(20)

But how we can initialize CanEdit property? We don’t know which items will be displayed on the page, because the source collection can be filtered, sorted and paged by Grid.Mvc infrastructure.
You can do like this:

            //_permissionManager injected via ctor DI
     foreach (var fooGridItem in items) //Query all from DB!!!
            {
                fooGridItem.CanEdit = _permissionManager.DoesCurrentUserCanEditFoo(fooGridItem.Id);
            }

But, in this case you query all items from database. If you have many items in the Foo table it can produce large latency lag. Also method DoesCurrentUserCanEditFoo may take large amount of time. Ok, we need to initialize this property only for displayed items.

Solution

There are several ways to solve this problem. But the best way is to override GetItemsToDisplay method of Grid<T> class (option available since Grid.Mvc 2.3.0). This method returns items, that need to be displayed on the page.
At first create class that derived from Grid<T>:

    public class FooGrid : Grid<FooGridItem>
    {
        private readonly IPermissionManager _permissionManager;
        private IEnumerable<FooGridItem> _displayingItems;

        public FooGrid(IQueryable<FooGridItem> items, IPermissionManager permissionManager) 
            : base(items)
        {
            _permissionManager = permissionManager;
        }

        /// <summary>
        /// Grid.Mvc invokes this method when wants to retrive items, which to be displayed
        /// </summary>
        protected override IEnumerable<FooGridItem> GetItemsToDisplay()
        {
            // Grid.Mvc may call this methods multiple times. You may cache process result in the field;
            if (_displayingItems != null)
                return _displayingItems;

            // Get items that Grid.Mvc wants to display
            _displayingItems = base.GetItemsToDisplay().ToList();

            // Initialize fields only for displaying items via service reference:
            foreach (var displayedItem in _displayingItems)
            {
                displayedItem.CanEdit = _permissionManager.DoesCurrentUserCanEditFoo(displayedItem.Id);
            }

            return _displayingItems;
        }
    }

Now you can create the FooGrid instance and render it the view, the same way as at the top of this article:

        public ActionResult List()
        {
            var items = _fooRepository.GetAll() /*returns IQueryable<T>*/
                                      .Select(fooDto => new FooGridItem
                                          {
                                              Id = fooDto.Id,
                                              Title = fooDto.Title
                                          });
            return View(new FooGrid(items, _permissionManager));
        }

Last edited Mar 17, 2013 at 10:48 AM by Bukharin, version 1