开发者

Linq to object dynamic query is it possible?

Wondering if it's possible to create a dynamic linq query using linq to objects.

I have a screen where a user can filter on multiple things. I Need to build an in memory filtering NOT using a database

So lets suppose I have a list of customers in memory and I would like to filter based on some multiselection.

I thought a method that I could pass a predicate would do t开发者_开发技巧he trick ,but obviously not.

How can I do it?

eg

public class Biz
{
    public List<Customer> GetAllByName(string name)
    {
        return Repository.Find(x=> x.Name == name);
    }
}

public class Repository
{
    private List<Customer> internalCustomerList = GetAllCustomers();

    public IEnumerable<Customer> Find(Expression<Func<T, bool>> predicate)
    {
        //How do I make below work in linq to object
        return  internalCustomerList.Where(predicate);//error here
    }
}


An alternate approach would be to pass a string filter rather than a predicate. The Dynamic LINQ Library makes this possible.

public IEnumerable<Customer> Find(string filter)
{
    //filter would be something like "Age >= 20"
    return internalCustomerList.Where(filter);
}


You can do:

public class Biz
{
    public List<Customer> GetAllByName(string name)
    {
        return Repository.Find(x=>x.Name == name);
    }
}

public class Repository
{
    private List<Customer> internalCustomerList = GetAllCustomers();

    public static IEnumerable<Customer> Find(Func<T, bool> predicate)
    {
        return internalCustomerList.Where(predicate);
    }
}

Please note that List<T> does not have an overload for Expression<Func<T, bool>>. Only IQueryable<T> has. See more at http://msdn.microsoft.com/en-us/library/bb882637.aspx


IEnumerable<T> only has extension methods with delegates, aka .Where(Func<T, bool> predicate)

Use .AsQueryable() to get a IQueryable<T> which supports .Where(Expression<Func<T, bool>>)


I use a predicate builder class for my LINQ queries:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

public static class PredicateBuilder
{
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                        Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>
              (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    }

    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                         Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>
              (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }
}

code sample:

private static IQueryable<AppointmentDTO> FilterAppointmentData(IEnumerable<AppointmentDTO> data, AppointmentSearchDTO searchData)
        {
            var predicate = PredicateBuilder.True<AppointmentDTO>();
            if (searchData.Status != null)
                predicate = predicate.And(p => p.Status.Equals(Convert.ToInt32(searchData.Status)));
            if (searchData.LastName != null)
                predicate = predicate.And(p => p.LastName.ToLower().Contains(searchData.LastName.ToLower()));
            if (searchData.File != null)
                predicate = predicate.And(p => p.File.ToLower().Contains(searchData.File.ToLower()));
            if (searchData.Doctor != null)
                predicate = predicate.And(p => p.Doctor.ToLower().Contains(searchData.Doctor.ToLower()));
            return data.AsQueryable().Where(predicate);
        }

Got it from here:

http://www.albahari.com/nutshell/predicatebuilder.aspx

Cheers!


It is definitely possible. You need to use a compile method to convert your expression to the callable method. I've not tested the code, but it should be very close to the following:

public IEnumerable<Customer> Find(Expression<Func<Customer, bool>> predicate)
{
    return  internalCustomerList.Where(predicate.compile());
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜