Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I define a SELECT TOP using LINQ with a dynamic query?

Tags:

c#

sql

lambda

linq

I want to pass dynamic lambda expressions to the function below, but I'm not sure how to define the .Take() or .OrderByDescending() on the expression object. If I want to call the function below, then I want to be able to do this:

dbprovider.Query = (x => x.ConfigurationReference == "172.16.59.175")
                   .Take(100)
                   .OrderByDescending(x.Date)
FindEntities(db, dbprovider.Query)

But I can't (this syntax is invalid). Any ideas?

public static List<T> FindEntities<T>(TrackingDataContext dataContext, System.Linq.Expressions.Expression<Func<T, bool>> find) where T : class
{
    try
    {
        var val = dataContext.GetTable<T>().Where(find).ToList<T>();
        return val;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}
like image 382
Daniel Minnaar Avatar asked Dec 03 '12 05:12

Daniel Minnaar


People also ask

Can you use LINQ on dynamic?

The Dynamic source file includes a helper library that allows you to express LINQ queries using extension methods that take string arguments instead of type safe operators. To use the Dynamic Expression API, you could simply copy/paste the Dynamic source file in your project.

What is LINQ dynamic?

The Dynamic LINQ library exposes a set of extension methods on IQueryable corresponding to the standard LINQ methods at Queryable, and which accept strings in a special syntax instead of expression trees.


1 Answers

The parameter is of type:

System.Linq.Expressions.Expression<Func<T, bool>> find

That means it can take a predicate (the "where" clause), and only a predicate. Thus the only bit you can pass in there is the filter:

x => x.ConfigurationReference == "172.16.59.175"

To do what you want, you would need to add the rest of the code in FindEntities, so that it becomes:

var val = dataContext.GetTable<T>().Where(find)
              .OrderByDescending(x => x.Date).Take(100).ToList<T>();

(note also that the Take should really be after the OrderByDescending)

One way you could do that would be:

public static List<T> FindEntities<T>(TrackingDataContext dataContext,
    System.Linq.Expressions.Expression<Func<T, bool>> find,
    Func<IQueryable<T>, IQueryable<T>> additonalProcessing = null
) where T : class
{
    var query = dataContext.GetTable<T>().Where(find);
    if(additonalProcessing != null) query = additonalProcessing(query);
    return query.ToList<T>();
}

and call:

var data = FindEntities(db, x => x.ConfigurationReference == "172.16.58.175",
    q => q.OrderByDescending(x => x.Date).Take(100));

However, frankly I'm not sure what the point of this would be... the caller could do all of that themselves locally more conveniently, without using FindEntities at all. Just:

var data = db.GetTable<T>()
             .Where(x => x.ConfigurationReference == "172.16.58.175")
             .OrderByDescending(x => x.Date).Take(100).ToList(); 

or even:

var data = db.SomeTable
             .Where(x => x.ConfigurationReference == "172.16.58.175")
             .OrderByDescending(x => x.Date).Take(100).ToList();

or just:

var data = (from row in db.SomeTable
            where row.ConfigurationReference == "172.16.58.175"
            orderby row.Date descending
            select row).Take(100).ToList();
like image 119
Marc Gravell Avatar answered Sep 28 '22 00:09

Marc Gravell