Linq - Dynamic grouping

I'm creating several linq-query's that always return a list<GroupedInfo>.
Depending of the search-criteria, I need to add more or less grouping-fields.
Right now I perform this by using several procedures which contain a linq-query with the correct fields and mapping.

    public class GroupedInfo
    {
        public decimal DossierManagerId { get; set; }
        public string DossierManagerName { get; set; }
        public int MonthTransferDate { get; set; }
        public string QuestionType { get; set; }
        public int Counter { get; set; }
        public string QuestionStatus { get; set; }
    }

Open in new window

Is there any way to create a general method to pass fe a class as grouping-class and another item that tells how to map), so that I just need 1 method ?

Suppose I have the following linq-query's:

var query = (from table in managementInfoListDataTable.AsEnumerable()
                    group table by
                        new
                            {
                                mgrId = table.DossierManagerId,
                                mgrName = table.DossierManagerName,
                                MonthTransferDate = table.TransferDate.Month,
                                QuestionType = table.QuestionTypeCv,
                                QuestionStatus = table.StatusCv
                            }
                    into groupedTable
                    select new GroupedInfo
                               {
                                   DossierManagerId = groupedTable.Key.mgrId,
                                   DossierManagerName = groupedTable.Key.mgrName,
                                   MonthTransferDate = groupedTable.Key.MonthTransferDate,
                                   Counter = groupedTable.Count(),
                                   QuestionType = groupedTable.Key.QuestionType,
                                   QuestionStatus = groupedTable.Key.QuestionStatus
                        }).OrderBy(obj => obj.DossierManagerId).ThenBy(
                                                          obj => obj.DossierManagerName).ToList();

var query2 =             return (from table in managementInfoListDataTable.AsEnumerable()
                    group table by
                        new
                        {
                            MonthTransferDate =  table.TransferDate.Month
                        }
                        into groupedTable
                        select new GroupedInfo
                        {
                            MonthTransferDate = groupedTable.Key.MonthTransferDate,
                            Counter = groupedTable.Count(),
                        }).OrderBy(obj => obj.MonthTransferDate).ToList();

Open in new window



Can it become something like:

var query = (from table in managementInfoListDataTable.AsEnumerable()
                    group table by
                        GROUPINGCLASS
                    into groupedTable
                    select new GroupedInfo
                               {
                         MAPPING
                        }).OrderBy(obj => obj.DossierManagerId).ThenBy(
                                                          obj => obj.DossierManagerName).ToList();

Open in new window

Eventually a dynamic orderby off course
LVL 53
DhaestAsked:
Who is Participating?
 
DhaestAuthor Commented:
I finally solved it by using the following extension-method and by using reflection to fill the correct properties of the object


       public static Collection<GroupedInfo> ReturnAsGroupedInfo<TKey, TElement>(this
IEnumerable<IGrouping<TKey, TElement>> elements, string groupByProperty)
        {
            Collection<GroupedInfo> groupedInfoList = new Collection<GroupedInfo>();
            string[] propertyNames = groupByProperty.Split(',');            
            PropertyInfo prop = null;

            foreach (var element in elements)
            {
                GroupedInfo groupedInfo = new GroupedInfo();
                string[] keys = element.Key.ToString().Split(',');
                for (int counter = 0; counter <= keys.GetUpperBound(0); counter++)
                {
                    prop = groupedInfo.GetType().GetProperty(propertyNames[counter], BindingFlags.Public | BindingFlags.Instance);
                    if (null != prop && prop.CanWrite)
                    {
                        prop.SetValue(groupedInfo, Convert.ChangeType(keys[counter], Type.GetType(prop.PropertyType.FullName)), null);
                    }
                }

                prop = groupedInfo.GetType().GetProperty("Counter", BindingFlags.Public | BindingFlags.Instance);
                prop.SetValue(groupedInfo, element.Count(), null);

                groupedInfoList.Add(groupedInfo);
            }


            return groupedInfoList;
        }

Open in new window


Using the following code to call it:

 string mapToKeyProperty = "...";
groupedInfoList = managementInfoListDataTable.GroupBy(groupingFunction).ReturnAsGroupedInfo(mapToKeyProperty)

Open in new window

0
 
Bob LearnedCommented:
There is a concept with LINQ that is useful when building dynamic queries.  It is called Composition, and it uses the nature of LINQ where execution is delayed.

Here is an article that talks about building composable queries:

Composable LINQ to SQL query with dynamic OrderBy
http://blogs.msdn.com/b/swiss_dpe_team/archive/2008/06/05/composable-linq-to-sql-query-with-dynamic-orderby.aspx

The trick is to be careful, and not do something that causes the query to execute (such as ToList)
0
 
DhaestAuthor Commented:
I'm not using linq-to-sql. I need to query a datatable.

The main part I'm looking for is the dynamic part of the grouping
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

 
Bob LearnedCommented:
Aah, yes, the reference threw you off.  That was meant to show how LINQ is composable, not LINQ-to-SQL.  That was the first article that I could find that explained that concept.  I am trying to find a previous reference article that would explain this a lot better than that article does, but I am not having a lot of luck.

If you build the pieces one step at a time, you can combine the results of one query with another, and it won't be executed until you need it to be.  This concept is best for a dynamic where clause, and I haven't seen it done with grouping, but I don't see why it can't work if you careful construct the different parts.
0
 
Bob LearnedCommented:
In the meantime, here are some reading materials:

1) LINQ queries are composable
http://www.careerride.com/LINQ-queries-are-composable.aspx

2) Composable and Efficient LINQ Queries
http://destructothedevilcat.wordpress.com/2009/02/15/composable-and-efficient-linq-queries/
0
 
DhaestAuthor Commented:
No alternatives found
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.