title: C# Generic search in object recursively
body: <p>I am trying to write an universal search to use for all objects.
  I have this code, which is working fine to search in just one object's properties, but I would also like to search also in properties in related objects.</p>
  
  <p>Eg. I have these Models/Objects</p>
  
  <pre><code>public class Customer
  {
      public int Id { get; set; }
      public string Name { get; set; }
      public int Age { get; set; }
      public string Address{ get; set; }
  
      public ICollection&lt;Contract&gt; Contracts { get; set; }
  }
  public class Contract
  {
      public int Id { get; set; }
      public DateTime From{ get; set; }
      public DateTime To{ get; set; }
      public string Comment{ get; set; }
      public int CustomerId { get; set; }
  
      [ForeignKey("CustomerId")]
      public Customer Customer { get; set; }
  }
  </code></pre>
  
  <p>and I want to search if any of properties contains some a string eg. "Peter", I will call it this way:</p>
  
  <pre><code>string searchString = "Peter";
  var customers = db.Customers
      .Include(x =&gt; x.Contracts)
      .WhereAnyPropertiesOfSimilarTypeContains(searchString);
  </code></pre>
  
  <p>this code will check if any properties of 'Customer' contains string "Peter".
  But I would also need to check if the related model 'Contract' contains "Peter.</p>
  
  <pre><code>public static class EntityHelper
      {
          public static IQueryable&lt;TEntity&gt; WhereAnyPropertiesOfSimilarTypeContains&lt;TEntity, TProperty&gt;(this IQueryable&lt;TEntity&gt; query, TProperty value)
          {
              var param = Expression.Parameter(typeof(TEntity));
  
              var predicate = PredicateBuilder.False&lt;TEntity&gt;(); //--- True to equal
              var entityFields = GetEntityFieldsToCompareTo&lt;TEntity, TProperty&gt;();
              foreach (var fieldName in entityFields)
              {
                  MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
  
                  var predicateToAdd = Expression.Lambda&lt;Func&lt;TEntity, bool&gt;&gt;(
                      Expression.Call(
                          Expression.PropertyOrField(param, fieldName), method,
                          Expression.Constant(value)), param);
  
                  predicate = predicate.Or(predicateToAdd);  //--- And to equal
              }
  
              return query.Where(predicate);
          }
  
          // TODO: You'll need to find out what fields are actually ones you would want to compare on.
          //       This might involve stripping out properties marked with [NotMapped] attributes, for
          //       for example.
          public static IEnumerable&lt;string&gt; GetEntityFieldsToCompareTo&lt;TEntity, TProperty&gt;()
          {
              Type entityType = typeof(TEntity);
              Type propertyType = typeof(TProperty);
  
              var fields = entityType.GetFields()
                                  .Where(f =&gt; f.FieldType == propertyType)
                                  .Select(f =&gt; f.Name);
  
              var properties = entityType.GetProperties()
                                      .Where(p =&gt; p.PropertyType == propertyType)
                                      .Select(p =&gt; p.Name);
  
              return fields.Concat(properties);
          }
      }
  </code></pre>
  
  <p>Thanks.</p>