title: Translating expression tree from a type to another type with complex mappings
body: <p>inspired by <a href="https://stackoverflow.com/a/6698824/82540">this answer</a> I'm trying to map a property on a model class to an expression based on the actual entity.
  These are the two classes involved:</p>
  
  <pre><code>public class Customer
  {
      public string FirstName { get; set; }
      public string LastName { get; set; }
      public int Id { get; set; }
      public DateTime? BirthDate { get; set; }
      public int CustomerTypeId { get; set; }
  }
  
  public class CustomerModel
  {
      ...
      public bool HasEvenId { get; set; }
  }
  </code></pre>
  
  <p>An example of a possible expression I'd like to convert is:</p>
  
  <pre><code>Expression&lt;Func&lt;CustomerModel, bool&gt;&gt; from = model =&gt; model.HasEvenId;
  Expression&lt;Func&lt;Customer, bool&gt;&gt; to = entity =&gt; ((entity.Id % 2) == 0);
  </code></pre>
  
  <p>The problem is that I have to expose an OData endpoint via ASP.NET WebAPI but I need to make some operations on the entities before I can them, hence the need of a model class and the need to translate the expression based on the model that I could receive as an OData query in an expression based on the entity, that I would use to query EF4.</p>
  
  <p>This is where I got so far:</p>
  
  <pre><code>private static readonly Dictionary&lt;Expression, Expression&gt; Mappings = GetMappings();
  
  private static Dictionary&lt;Expression, Expression&gt; GetMappings()
  {
      var mappings = new Dictionary&lt;Expression, Expression&gt;();
  
      var mapping = GetMappingFor((CustomerModel model) =&gt; model.HasEvenId, (Customer customer) =&gt; (customer.Id%2) == 0);
      mappings.Add(mapping.Item1, mapping.Item2);
  
      return mappings;
  }
  
  private static Tuple&lt;Expression, Expression&gt; GetMappingFor&lt;TFrom, TTo, TValue&gt;(Expression&lt;Func&lt;TFrom, TValue&gt;&gt; fromExpression, Expression&lt;Func&lt;TTo, TValue&gt;&gt; toExpression)
  {
      MemberExpression fromMemberExpression = (MemberExpression) fromExpression.Body;
      return Tuple.Create&lt;Expression, Expression&gt;(fromMemberExpression, toExpression);
  }
  
  public static Expression&lt;Func&lt;TTo, bool&gt;&gt; Translate&lt;TFrom, TTo&gt;(Expression&lt;Func&lt;TFrom, bool&gt;&gt; expression, Dictionary&lt;Expression, Expression&gt; mappings = null)
  {
      if (expression == null)
          return null;
  
      string parameterName = expression.Parameters[0].Name;
  
      parameterName = string.IsNullOrWhiteSpace(parameterName) ? "p" : parameterName;
  
      var param = Expression.Parameter(typeof(TTo), parameterName);
      var subst = new Dictionary&lt;Expression, Expression&gt; { { expression.Parameters[0], param } };
      ParameterChangeVisitor parameterChange = new ParameterChangeVisitor(parameterName);
      if (mappings != null)
          foreach (var mapp in mappings)
              subst.Add(mapp.Key, parameterChange.Visit(mapp.Value));
  
      var visitor = new TypeChangeVisitor(typeof(TFrom), typeof(TTo), subst);
      return Expression.Lambda&lt;Func&lt;TTo, bool&gt;&gt;(visitor.Visit(expression.Body), param);
  }
  
  public IQueryable&lt;CustomerModel&gt; Get()
  {
      var filterExtractor = new ODataFilterExtractor&lt;CustomerModel&gt;();
      Expression&lt;Func&lt;CustomerModel, bool&gt;&gt; expression = filterExtractor.Extract(Request);
      Expression&lt;Func&lt;Customer, bool&gt;&gt; translatedExpression = Translate&lt;CustomerModel, Customer&gt;(expression, Mappings);
  
      IQueryable&lt;Customer&gt; query = _context.Customers;
  
      if (translatedExpression != null)
          query = query.Where(translatedExpression);
  
      var finalQuery = from item in query.AsEnumerable() 
                       select new CustomerModel()
                          {
                              FirstName = item.FirstName, 
                              LastName = item.LastName, 
                              Id = item.Id, 
                              BirthDate = item.BirthDate, 
                              CustomerTypeId = item.CustomerTypeId,
                              HasEvenId = (item.Id % 2 ) == 0
                          };
  
      return finalQuery.AsQueryable();
  }
  </code></pre>
  
  <p>where:</p>
  
  <ul>
  <li>ODataFilterExtractor is a class that extract the $filter expression from the RequestMessage we receive;</li>
  <li>ParameterChangeVisitor just changes all the ParameterExpression to a new one having the provided string as parameter name;</li>
  </ul>
  
  <p>In addition, I changed the VisitMember method of the answer linked above in this way:</p>
  
  <pre><code>protected override Expression VisitMember(MemberExpression node)
  {
      // if we see x.Name on the old type, substitute for new type
      if (node.Member.DeclaringType == _from)
      {
          MemberInfo toMember = _to.GetMember(node.Member.Name, node.Member.MemberType, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SingleOrDefault();
          if (toMember != null)
          {
              return Expression.MakeMemberAccess(Visit(node.Expression), toMember);
          }
          else
          {
              if (_substitutions.Select(kvp =&gt; kvp.Key).OfType&lt;MemberExpression&gt;().Any(me =&gt; me.Member.Equals(node.Member)))
              {
                  MemberExpression key = _substitutions.Select(kvp =&gt; kvp.Key).OfType&lt;MemberExpression&gt;().Single(me =&gt; me.Member.Equals(node.Member));
                  Expression value = _substitutions[key];
  
                  // What to return here?
                  return Expression.Invoke(value);
              }
          }
      }
      return base.VisitMember(node);
  }
  </code></pre>
  
  <p>Thanks for you help.</p>