Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework generic

I have code like following:

switch(sort.Column)
{
  case "code":
    model = (sort.Direction == SortDirection.Ascending)
            ? model.OrderBy(x => x.code)
            : model.OrderByDescending(x => x.code);
    break;
  case "name":
    model = (sort.Direction == SortDirection.Ascending)
            ? model.OrderBy(x => x.name)
            : model.OrderByDescending(x => x.name);
    break;
..............
}

I have about 10-15 fields (like 'code' and 'name') and I do not want to copy and paste similar code with only one difference - field name.

Is there method to generalize query somehow?

like image 958
Alex G.P. Avatar asked Mar 30 '12 21:03

Alex G.P.


2 Answers

You can use reflection (this assumes code and name are properties; if they are public variables, you'll have to modify accordingly):

model = (sort.Direction == SortDirection.Ascending)
  ? model.OrderBy( x => x.GetType()
      .GetProperty( sort.Column ).GetValue( x, null ) ) :
  : model.OrderByDescending( x => x.GetType()
      .GetProperty( sort.Column ).GetValue( x, null ) );

As Dunc points out in the comments below, this approach forces reflection at each step of the enumeration, and reflection is expensive as operations go. If your collection is homogeneous, you can achieve better performance by moving the reflection out of the enumeration. If your model contains only elements of type Foo, you can do the following instead:

var prop = typeof( Foo ).GetProperty( sort.Column );

model = (sort.Direction == SortDirection.Ascending)
  ? model.OrderBy( x => prop.GetValue( x, null ) ) :
  : model.OrderByDescending( x => prop.GetValue( x, null ) );

Please not that this will throw a TargetException if your collection is not homogeneous.

like image 121
Ethan Brown Avatar answered Oct 23 '22 08:10

Ethan Brown


This would get you started, but you could also use reflection to get the property name via the Column, if the property and column match exactly.

// inline function
Func<Func<Model, TResult>, Model> Order = criteria => 
{
    return (sort.Direction == SortDirection.Ascending)
            ? model.OrderBy(criteria)
            : model.OrderByDescending(criteria);
}

... code down to switch ...

This would shorten your name case to:

model = Order(x => x.name);

But with reflection, you could do it without the switch, but I'm a little weak on reflection, so I'll leave it to someone else if they want.

like image 29
Chuck Savage Avatar answered Oct 23 '22 10:10

Chuck Savage