How to refactor multiple similar Linq queries?

2019-07-13 02:55发布

问题:

Suppose I have the two following Linq queries I want to refactor:

var someValue1 = 0;
var someValue2= 0;
var query1 = db.TableAs.Where( a => a.TableBs.Count() > someValue1 )
                  .Take( 10 );
var query2 = db.TableAs.Where( a => a.TableBs.First().item1 == someValue2)
                  .Take( 10 );

Note that only the Where parameter changes. There is any way to put the query inside a method and pass the Where parameter as an argument?

回答1:

Of couse there is. The where parameter is just a simple closure of type Func<T, bool> (where T is the type of your DB items - I don't know them out of your code) and you can wrap it into a (anonymous) function.

Func<Func<T, bool>, IEnumerable<T>> MakeQuery = (Func<T, bool> whereParam) => db.TableAs.Where(whereParam).Take(10);

Use it like this

var query1 = MakeQuery(a => a.TableBS.Count() > someValue1);


回答2:

You can using Predicate<T>.

public IQueryable<TableA> Helper(Predicate<TableA> predicate)
{
    return db.TableAs.Where(predicate).Take(10);
}

The just call it like that.

var query1 = Helper(a => a.TableBs.Count() > someValue1);
var query2 = Helper(a => a.TableBs.First().item1 == someValue2);

And give a better namen than Helper.



回答3:

Yeah, the parameter type is a lamba expression Func<TSource, bool>

Func<Person, bool> c1 = p => p.LastName == "1";
Persons.Where(c1);
Func<Person, bool> c2 = p => p.FirstName == "2";
Persons.Where(c2)


回答4:

You can do it the same way you'd refactor any other code:

T MyQuery(U db, Func<TSource, bool> pred) {
  return db.TableAs.Where( pred )
                  .Take( 10 );
}

where T and U are whatever types ar erelevant in your query.