简体   繁体   中英

Does converting an IEnumerable to IQueryable enumerate the query

I am using JQuery widgets's datatable to have a table control in an MVC application with server-side paging, sorting and filtering. When doing the filtering, I have the following method:

private IQueryable<ImportRfqViewModel> BuildLinqQuery(System.Collections.Specialized.NameValueCollection query)
{
    var result = query.GetValues("filterslength");
    var filtersCount = int.Parse(query.GetValues("filterslength")[0]);
    if (result == null || filtersCount == 0)
    {
        return AllImportRfq();
    }

    Predicate<ImportRfqViewModel> orResultPredicate = PredicateExtensions.False<ImportRfqViewModel>();
    for (var i = 0; i < filtersCount; i += 1)
    {
        var filterValue = query.GetValues("filtervalue" + i)[0].ToUpper();
        var filterCondition = query.GetValues("filtercondition" + i)[0];
        var filterDataField = query.GetValues("filterdatafield" + i)[0];
        var filterOperator = query.GetValues("filteroperator" + i)[0];

        if (filterDataField == "ImportRfqId")
        {
            Predicate<ImportRfqViewModel> predicate = p => p.ImportRfqId.ToString().Contains(filterValue);
            orResultPredicate = orResultPredicate.Or(predicate);
        }
        else if (filterDataField == "DateCreated")
        {
            Predicate<ImportRfqViewModel> predicate = p => p.DateCreated.ToString("yyyy/MM/dd hh:mm:ss").Contains(filterValue);
            orResultPredicate = orResultPredicate.Or(predicate);
        }
        ...
    }

    Func<ImportRfqViewModel, bool> funcOr = l => orResultPredicate(l);

    var allResearch = AllImportRfq().Where(funcOr).AsQueryable();
    return allResearch;
}

I'm using the predicates in order to chain Or conditions. I obviously want to return an IQueryable so that the query is not run before I get to the part:

dbResult = dbResult.Skip(pagesize * pagenum).Take(pagesize);

The result of the predicate though, is an IEnumerable . This is why I call the .AsQueryable();

What I'm concerned about and don't know is whether the thing potentially is enumerating the query and then returning a IQueryable afterwards and throwing away the enumeration, if I'm making sense.

In all this I'm assuming that if I return an IEnumerable , it would execute the query.

Returning an IEnumerable by itself does not mean you are actually executing the query. It depends on the IEnumerable 's creator, but normally IEnumerable is considered lazy and the underlying data source is touched only when enumerating an IEnumerator . Linq operators and extension methods behave nicely, so your AsQueryable() call does not enumerate the target, and you should be safe.

BTW, did you try changing your code from this:

Func<ImportRfqViewModel, bool> funcOr = l => orResultPredicate(l);

to this (as long as your query provider fully supports Where and the predicate you are building, of course)?

Expression<Func<ImportRfqViewModel, bool>> funcOr = ...;

This way you should be able to avoid going back and forth across IQueryable and IEnumerable , you would not need calling AsQueryable() at all and therefore you'd have no more doubts. If your query provider supports it, it would be much more efficient than what you are doing, which would execute the filtering after querying the underlying data source.

EDIT : just to make it clearer, the move from Func<> to Expression<> is not just a matter of changing the type of your variable, it actually means you'd have to review the whole process of building your predicates so that you always work by composing Expression instances, and not just Func ones, otherwise your resulting expression tree will hardly be understandable to your query provider.

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