tipo - what is a class c#




Costruire dinamicamente la query "o" LIKE in LINQ su SQL (2)

Ci sono due modi possibili:

  1. Costruire Expression , come sottolineato da Coincoin
  2. Mettendo tutti i tuoi parametri in un array e usando Any :

    var parameters = new [] { parameter1, parameter2, /*...*/ }
    reservations = reservations
        .Where(r => 
            parameters.Any(p => r.GuestFirstName.Contains(p)
                                || r.GuestLastName.Contains(p)));

Ho una query LINQ che è composta da un oggetto anonimo.

A un certo punto, voglio limitare i risultati per parametri di ricerca in entrata, ma questo può essere uno o più parametri, e voglio eseguire un "MI PIACE O MI PIACE O LIKE" usando quelli.

Nel codice, sarebbe simile a questo:

reservations = reservations.Where(r =>
  r.GuestLastName.Contains(parameter1) || r.GuestFirstName.Contains(parameter1) || 
  r.GuestLastName.Contains(parameter2) || r.GuestFirstName.Contains(parameter2) || 
  // Parameter 3, 4, 5,..
);

Come potrei costruirlo dinamicamente, sapendo che le reservations sono del tipo IQueryable<'a> (anonymous object) ? Ho dato un'occhiata alle varie risorse e posso solo trovare il modo di farlo quando conosco il tipo, non quando uso i tipi anonimi.

È importante sapere che è Linq to SQL, quindi dovrebbe essere tradotto in una query SQL e non essere filtrato in memoria ...


Vorrei scrivere il mio metodo di estensione generico:

public static class CollectionHelper
{
    public static IQueryable Filter<T>(this IQueryable source, string[] properties, string[] values)
    {
        var lambda = CombineLambdas<T>(properties, values);
        var result = typeof (Queryable).GetMethods().First(
            method => method.Name == "Where"
                      && method.IsGenericMethodDefinition)
                                       .MakeGenericMethod(typeof (T))
                                       .Invoke(null, new object[] {source, lambda});
        return (IQueryable<T>) result;
    }

    // combine lambda expressions using OR operator
    private static LambdaExpression CombineLambdas<T>(string[] properties, string[] values)
    {
        var param = Expression.Parameter(typeof (T));
        LambdaExpression prev = null;
        foreach (var value in values)
        {
            foreach (var property in properties)
            {
                LambdaExpression current = GetContainsExpression<T>(property, value);
                if (prev != null)
                {
                    Expression body = Expression.Or(Expression.Invoke(prev, param),
                                                    Expression.Invoke(current, param));
                    prev = Expression.Lambda(body, param);
                }
                prev = prev ?? current;
            }
        }
        return prev;
    }

    // construct expression tree to represent String.Contains
    private static Expression<Func<T, bool>> GetContainsExpression<T>(string propertyName, string propertyValue)
    {
        var parameterExp = Expression.Parameter(typeof (T), "type");
        var propertyExp = Expression.Property(parameterExp, propertyName);
        var method = typeof (string).GetMethod("Contains", new[] {typeof (string)});
        var someValue = Expression.Constant(propertyValue, typeof (string));
        var containsMethodExp = Expression.Call(propertyExp, method, someValue);

        return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
    }
}

e l'uso:

var reservations = new List<TheType>()  // sample collection
    {
        new TheType {FirstName = "aa", LastName = "bb"},
        new TheType {FirstName = "cc", LastName = "dd"},
        new TheType {FirstName = "ee", LastName = "ff"}
    }.AsQueryable();

var filtered = reservations
    .Filter<TheType>(new[] {"FirstName", "LastName"}, new[] {"d", "e"});
/* returnes 2 elements:
 * {FirstName = "cc", LastName = "dd"} and {FirstName = "ee", LastName = "ff"} */

Non conosco una soluzione generale che vorresti avere - se esiste, ma spero che possa essere un'alternativa accettabile che risolva il tuo caso costruendo il filtro desiderato in modo dinamico.







anonymous