segunda-feira, 23 de setembro de 2013

Dynamic OrderBy using LINQ

It took me hours to figure out how to make dynamic orderby, using LINQ. It's not easy at all.
There are a lot of abstraction which almost fried my brain.

So let's do it step by step.

As schema of database I'm using northwind.
The table I'm using is Territory.
But like me, you probably came to the conclusion that using the model created by LINQ through database bind is not a good idea. So, I created a class called TerritoryModel. This class is in the folder RAZOR. That's why you're seeing  RAZOR.Models.TerritoryModel as the type of the IOrderedEnumerable result.

Notice that the result of the method getAll is a IOrderedEnumerable and not a IQueryable, which would be expected.

1 -  Variables to define.

            //The LINQ context
            NorthwindDataContext lObjDC = new NorthwindDataContext();


           
            //The function you'll need to dynamically change the field by which you're going to order your result.
            Func<TerritoryModel, object> selector = null;



           
            //The variable which will receive the result of the ordered result.
            IOrderedEnumerable<TerritoryModel> lMT = null;

2 - Swtich

            //I wrote a very simple switch. This is the part of the program that does the trick of dynamically change the column which will order the table Territory.

            #region Selector
            switch (pIntSortBy)
            {
                case 1:
                        selector = a => a.TerritoryID;
                    break;
                case 2:
                        selector = a => a.TerritoryDescription;
                    break;
                case 3:
                        selector = a => a.RegionDescription;
                    break;
            }


3 - The IQueryable select

            var myTerritories = (from te in lObjDC.Territories
                                 join re in lObjDC.Regions
                                     on te.RegionID equals re.RegionID
                                 select new
                                 {
                                     TerritoryID = te.TerritoryID,
                                     TerritoryDescription = te.TerritoryDescription,
                                     RegionDescription = re.RegionDescription
                                 });

4 -The orderBy. An IOrderedEnumerable result.

            if (pBlnIsAsc)
            {
                lMT = myTerritories.Select(p => new TerritoryModel(p.TerritoryID, p.TerritoryDescription, p.RegionDescription)).OrderBy(selector);
            }
            else
            {
                lMT = myTerritories.Select(p => new TerritoryModel(p.TerritoryID, p.TerritoryDescription, p.RegionDescription)).OrderByDescending(selector);
            }

 Why am'I working with IOrderedEnumerable? Well, in the moment you type OrderBy or OrderByDescending, it stops to be IQueryable and starts to be IOrderedEnumerable.

In the end, we'll have a function like that:

 
        public IOrderedEnumerable<RAZOR.Models.TerritoryModel> getAll(int pIntSortBy, bool pBlnIsAsc)
        {
            NorthwindDataContext lObjDC = new NorthwindDataContext();

            Func<TerritoryModel, object> selector = null;
            IOrderedEnumerable<TerritoryModel> lMT = null;
           
            #region Selector
            switch (pIntSortBy)
            {
                case 1:
                        selector = a => a.TerritoryID;
                    break;
                case 2:
                        selector = a => a.TerritoryDescription;
                    break;
                case 3:
                        selector = a => a.RegionDescription;
                    break;
            }
            #endregion          

            var myTerritories = (from te in lObjDC.Territories
                                 join re in lObjDC.Regions
                                     on te.RegionID equals re.RegionID
                                 select new
                                 {
                                     TerritoryID = te.TerritoryID,
                                     TerritoryDescription = te.TerritoryDescription,
                                     RegionDescription = re.RegionDescription
                                 });

            if (pBlnIsAsc)
            {
                lMT = myTerritories.Select(p => new TerritoryModel(p.TerritoryID, p.TerritoryDescription, p.RegionDescription)).OrderBy(selector);
            }
            else
            {
                lMT = myTerritories.Select(p => new TerritoryModel(p.TerritoryID, p.TerritoryDescription, p.RegionDescription)).OrderByDescending(selector);
            }
           
            return lMT;
        }

Et voilà!

Nenhum comentário:

Postar um comentário