3

I have the following expresssion for sorting:

this.Students = this.Students.OrderBy(x => x.ExamData.OrderByDescending(p => p.ExamDate).ThenByDescending(p => p.ExamId).FirstOrDefault().TotalMarks);

While my idea is to abstract the Expression for

x => x.ExamData.OrderByDescending(p => p.ExamDate).ThenByDescending(
                                  p => p.ExamId).FirstOrDefault().TotalMarks

to be made as an lambda Expression so that I can use like

this.Students = this.Students.OrderBy(sortExpression);

It's because I have many sort fields like the TotalMarks defined above, and I want to just create the Expression from the sort field and then call the OrderBy.

I know from this link, we can create an expression where child property is used, but not getting with the inner expressions.

Currently I have given a switch case and written the same stuff in each case like

this.Students = this.Students.OrderBy(x => x.ExamData.OrderByDescending(p => p.ExamDate).ThenByDescending(p => p.ExamId).FirstOrDefault().SubjectName);

So my idea is to create kindof ExpressionBuilder with a static method which builds the expression passing on the fieldName, like

public static Expression BuildSortExpression(string fieldName) {}
Community
  • 1
  • 1
Chinjoo
  • 2,697
  • 6
  • 28
  • 45

3 Answers3

1

You can easily pull most of the logic into a method:

private int sortExpression(Student x) { 
    return x.ExamData.OrderByDescending(p => p.ExamDate).ThenByDescending(p => p.ExamId).FirstOrDefault().TotalMarks;
}

Assuming TotalMarks is an int.

Then you would just need to use:

this.Students.OrderBy(x => sortExpression(x));

or add it as a property of Student.

Warning: If you are using this with an ORM (linq to SQL, Entity framework, etc), this will not execute as efficiently as the previous code!

Ben
  • 1,767
  • 16
  • 32
  • That wouldn't be converted properly by EF though. – Servy Feb 20 '13 at 18:29
  • Good point, although EF wasn't mentioned in the question, so I assumed it was a straight enumerable, but I will update the question. – Ben Feb 20 '13 at 18:32
  • 1
    He's referring to `Expression`, which tells us that this is an IQueryable. It could be some other provider, such as Linq to SQL, which would support this, but EF is at least a likely option. – Servy Feb 20 '13 at 18:34
  • I totally agree, I just didn't think of it! Yours is probably the best answer (I have upvoted it), I will leave mine as it does provide the flexibility to order by desc too if needs be. – Ben Feb 20 '13 at 18:39
  • If you need a descending ordering you could just call `Reverse`, if the query provider supports that operation. If not, you could provide an optional boolean to the helper method of `IsDecending`. – Servy Feb 20 '13 at 18:40
1

Trying to create a reusable expression variable will end up being a lot more work than just creating your own extension method to do the whole ordering:

public static IQueryable<Student> OrderByMarks(this IQueryable<Student> students)
{
    return students.OrderBy(student => student.ExamData
        .OrderByDescending(exam => exam.ExamDate)
        .ThenBy(exam => exam.ExamId)
        .FirstOrDefault().TotalMarks);
}

Then you can use it like so:

this.Students = this.Students.OrderByMarks();
Servy
  • 202,030
  • 26
  • 332
  • 449
  • But its like the same which am doing right now as I will have to create the method for each property (field name), which is least likely an option for me, when going for refactoring. – Chinjoo Feb 20 '13 at 18:45
-1

Got a solution for this using the idea by Ben. Created a

Dictionary<string, Func<Student, Object>>

with the sort fields as key and the func as

new Func<Student, object>((Student student) => { return GetLatestExam(student).TotalMarks; })

And the GetLatestExam static method as

private static Study GetLatestExam(Student student)
{
     return student.ExamData.OrderByDescending(p => p.ExamDate).ThenByDescending(p => p.ExamId).FirstOrDefault();
}

Then in the actual sort, I just have to call like this:

public void Sort(string sortField, bool sortAscending)
{
     // based on the sort field, get the sorting expression and execute.
     if(sortAscending)
     {
          this.Students= this.Students.OrderBy(student=>this._customSortColumns[sortField](student));
     }
     else
     {
          this.Patients = this.Patients.OrderByDescending(student=>this._customSortColumns[sortField](student));
     }
}
Chinjoo
  • 2,697
  • 6
  • 28
  • 45