c# - Build expression tree for LINQ using List<T>.Contains method -


problem

i'm working on refactoring linq queries several reports in our web application, , i'm attempting move duplicate query predicates own iqueryable exension methods can reuse them these reports, , reports in future. can infer, i've refactored predicate groups, predicate codes giving me problems. example of 1 of report methods have far:

dal method:

public list<entities.queryview> getqueryview(filter filter) {     using (var context = createobjectcontext())     {         return (from o in context.queryviews                     (!filter.fromdate.hasvalue || o.repairdate >= entityfunctions.truncatetime(filter.fromdate))                     && (!filter.todate.hasvalue || o.repairdate <= entityfunctions.truncatetime(filter.todate))                     select o)                 .withcode(filter)                 .ingroup(filter)                 .tolist();     } } 

iqueryable extension:

public static iqueryable<t> withcode<t>(this iqueryable<t> query, filter filter) {     list<string> codes = dal.getcodesbycategory(filter.codecategories);      if (codes.count > 0)         return query.where(predicates.filterbycode<t>(codes));      return query; } 

predicate:

public static expression<func<t, list<string>, bool>> filterbycode<t>(list<string> codes) {     // method info list<string>.contains(code).     var methodinfo = typeof(list<string>).getmethod("contains", new type[] { typeof(string) });      // list of codes call .contains() against.     var instance = expression.variable(typeof(list<string>), "codes");      var param = expression.parameter(typeof(t), "j");     var left = expression.property(param, "code");     var expr = expression.call(instance, methodinfo, expression.property(param, "code"));      // j => codes.contains(j.code)     return expression.lambda<func<t, list<string>, bool>>(expr, new parameterexpression[] { param, instance }); } 

the problem i'm having queryable.where doesn't accept type of expression<func<t, list<string>, bool>. way can think of creating predicate dynamically use 2 parameters, part stumping me.

what i'm not comprehending following method works. can pass exact lambda expression trying create dynamically, , correctly filters data.

public list<entities.queryview> getqueryview(filter filter) {     // codes here.     list<string> codes = dal.getcodesbycategory(filter.codecategories);      using (var context = createobjectcontext())     {         return (from o in context.queryviews                     (!filter.fromdate.hasvalue || o.repairdate >= entityfunctions.truncatetime(filter.fromdate))                     && (!filter.todate.hasvalue || o.repairdate <= entityfunctions.truncatetime(filter.todate))                     select o)                 .where(p => codes.contains(p.code)) // works fine.                 //.withcode(filter)                 .ingroup(filter)                 .tolist();          }      } 

questions

  1. can implement own queryable.where overload? if so, feasible?
  2. if overload isn't feasible, there way dynamically construct predicate p => codes.contains(p.code) without using 2 parameters?
  3. is there easier way this? feel i'm missing something.

  1. you can create own extension method, name where, accept iqueryable<t>, return iqueryable<t>, , otherwise make emulate form of linq methods. wouldn't be linq method, one. discourage writing such method because confuse others; if want make new extension method, use name not used in linq avoid confusion. in short, you're doing now, create new extensions without naming them where. if wanted name 1 where though nothing's stopping you.

  2. sure, use lambda:

    public static expression<func<t, bool>> filterbycode<t>(list<string> codes)     t : icoded //some interface `code` field {     return p => codes.contains(p.code); } 

    if cannot have entities implement interface (hint: can), code identical code have, using list pass in constant rather new parameter:

    public static expression<func<t, bool>> filterbycode<t>(list<string> codes) {     var methodinfo = typeof(list<string>).getmethod("contains",          new type[] { typeof(string) });      var list = expression.constant(codes);      var param = expression.parameter(typeof(t), "j");     var value = expression.property(param, "code");     var body = expression.call(list, methodinfo, value);      // j => codes.contains(j.code)     return expression.lambda<func<t, bool>>(body, param); } 

    i encourage use of former method; method loses static type safety, , more complex , such harder maintain.

    another note, comment have in code: // j => codes.contains(j.code) isn't accurate. lambda actually looks is: (j, codes) => codes.contains(j.code); noticeably different.

  3. see first half of #2.


Comments

Popular posts from this blog

android - MPAndroidChart - How to add Annotations or images to the chart -

javascript - Add class to another page attribute using URL id - Jquery -

firefox - Where is 'webgl.osmesalib' parameter? -