Comment construire dynamiquement Where Expression dans Entity Framework?

entity-framework expression-trees linq where-clause

Question

J'ai examiné cette réponse sur la création dynamique d'une expression OrderBy dans Entity Framework. Mais j'aimerais aussi construire une expression Where dynamique. Quelque chose dans le sens de ceci:

public IEnumerable<InventoryItem> GetAll(string filterBy, object value)
{
  var results = new List<InventoryItem>();
  using (var db = new InventoryDb())
  {
    if (QueryHelper.PropertyExists<InventoryItem>(filterBy)) 
    {
      var query = db.rri_InventoryItems.WhereByProperty(filterBy, value); 

      foreach(var item in query.Where(expr))
      {
        results.Add(ConvertItem(item));
      }   
    }            
  }
  return results;
}

Passer la propriété à filtrer et une valeur en tant qu’objet ab. Queryable a deux méthodes pour Où deux prennent deux paramètres, donc je ne suis même pas sûr de savoir lequel est le bon.

Et c'est à ce stade que je me perds un peu plus. Je ne suis pas sûr de savoir comment refactoriser la méthode OrderByProerty d' origine pour fournir une propriété WhereByProperty . Je sais que ce que j'ai ici est complètement faux. Je ne sais pas quoi en faire.

Dans l’idéal, j’aimerais étendre encore davantage cette fonctionnalité en fournissant une collection d’objets pouvant être utilisés pour créer une requête avec ands et ou ou des opérateurs.

Réponse acceptée

Queryable a deux méthodes pour Où deux prennent deux paramètres, donc je ne suis même pas sûr de savoir lequel est le bon.

Vous avez besoin de celui qui reçoit le Expression<Func<T, bool>> predicate .

Voici comment vous pouvez construire dynamiquement un prédicat semblable à (T item) => item.Property == value :

public static partial class QueryableExtensions
{
    public static IQueryable<T> WhereEquals<T>(this IQueryable<T> source, string member, object value)
    {
        var item = Expression.Parameter(typeof(T), "item");
        var memberValue = member.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);
        var memberType = memberValue.Type;
        if (value != null && value.GetType() != memberType)
            value = Convert.ChangeType(value, memberType);
        var condition = Expression.Equal(memberValue, Expression.Constant(value, memberType));
        var predicate = Expression.Lambda<Func<T, bool>>(condition, item);
        return source.Where(predicate);
    }
}

J'ai essayé de l'écrire de telle manière que vous puissiez enjamber le code afin de comprendre ce qu'il fait. La seule ligne qui pourrait nécessiter une explication est:

var memberValue = member.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);

C'est un moyen simple de gérer les propriétés imbriquées telles que obj.Prop1.Prop2 etc. Si vous n'avez pas besoin de cette fonctionnalité, vous pouvez simplement l'utiliser à la place:

var memberValue = Expression.PropertyOrField(item, member);

Réponse populaire

Je n'ai pas besoin (encore) de propriétés imbriquées. J'ai légèrement modifié votre code et j'ai ce qui fonctionne:

    public static IQueryable<T> WhereEquals<T>(
       this IQueryable<T> source, string propertyName, object value)
    {
        if (typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase |
            BindingFlags.Public | BindingFlags.Instance) == null)
        {
            return null;
        }

        ParameterExpression parameter = Expression.Parameter(typeof(T), "item");
        Expression whereProperty = Expression.Property(parameter, propertyName);
        Expression constant = Expression.Constant(value);
        Expression condition = Expression.Equal(whereProperty, constant);
        Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(condition,parameter);
        return source.Where(lambda);
    }



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi