简体   繁体   中英

C# Generic Linq Query

I need to write some generic Search Method like this:

public List<T> Search<T>(SearchParamsBase searchParams)
{
    using (var context = new TestEntities())
    {
        var dataType = TypeMap.Get(typeof (T));
        var dataSet = context.Set(dataType);

        var searchQuery = CreateQuery((IEnumerable<object>) dataSet), searchParams)

        return searchQuery.ToList()
    }
}

and I have a function CreateQuery() that should filter IEnumerable object. This function will be different for all classes. For example:

CreateQuery(IEnumerable<object> collection, SearchParamsBase searchParams)
{
    var search = (SomeSearchImplementation)searchParams;
    // filter 
    collection = collection.Where(x => x.Name == search.Name);
    // select page
    collection = collection.Skip(search.Page * search.CountPerPage);
    collection = collection.Take(search.CountPerPage);
    // order by and so on
    // ...
    return collection;
}

How can I implement this idea correctly?

What you basically want to do here is construct a LINQ query dynamically. To do this, you need to modify/build the expression tree at runtime. If you are not familiar with expression trees and the Expression<T> type I recommend this article and the referenced pages in the "See also" section:

http://msdn.microsoft.com/en-us/library/bb397951.aspx

Now that you now the basic concept, let's implement dynamic sorting. The method below is an extension to IQueryable<T> which means it does not only apply to lists but to every LINQ datasource, so you could also use it directly against a database (which is more efficient when it comes to paging and sorting than in memory operations). The method takes the property name you want to order by and the sort direction (ascending/descending):

public static IQueryable<T> OrderByDynamic<T>(this IQueryable<T> query, string sortColumn, bool descending) 
{
    // Dynamically creates a call like this: query.OrderBy(p => p.SortColumn)
    var parameter = Expression.Parameter(typeof(T), "p");

    string command = "OrderBy";

    if (descending)
    {
        command = "OrderByDescending";
    }

    Expression resultExpression = null;    

    var property = typeof(T).GetProperty(sortColumn);
    // this is the part p.SortColumn
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);

    // this is the part p => p.SortColumn
    var orderByExpression = Expression.Lambda(propertyAccess, parameter);

    // finally, call the "OrderBy" / "OrderByDescending" method with the order by lamba expression
    resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { typeof(T), property.PropertyType },
       query.Expression, Expression.Quote(orderByExpression));

    return query.Provider.CreateQuery<T>(resultExpression);
}

Now you can write this code to order the dataset by the property Name in ascending order:

dataSet.OrderByDynamic("Name", false)

Creating an extension method for dynamic filtering follows the same pattern. If you understand the code above, it won't be a problem for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM