Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The best way to build Dynamic LINQ query

Tags:

asp.net

linq

Hi I am looking for best method for writing Dynamic LINQ query.

I have a function like

public IQueryable<Student> FindByAllStudents(int? id, string Name, int? CourseID, bool? IsActive) // like this way, all field values are passed
    {    
        // code for compairision
        return db.Student;
    }

we can also write db.Students.where(predicate)

or

a query like

var students = from s in db.students where s.Name.Contains(Name)
                s.ID.Equals(id)
                //and so on....

So will this method works if i don't pass ID (i.e. Null)? is proper way for all the datatypes?

The point is function can have all null values as a parameter for equivalence of select * from statement.

can any one help me to build best query with sample code?

like image 835
Vikas Avatar asked Apr 10 '09 07:04

Vikas


People also ask

What is Dynamic LINQ?

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.

Is Dynamic LINQ safe?

And Dynamic Linq is actually composed from strings, therefore it is potentially prone to attack by injection. Obviously, the attacker will have to be aware of the fact that you are using DynamicLinq and could attack only preparing the data so it results in valid malicious Dynamic Linq query.


1 Answers

Okay, it's not entirely clear what you want, but if you're trying to only add where clauses for the parameters which are non-null, you could do:

public IQueryable<Student> FindByAllStudents
    (int? id, string name, int? courseID, bool? isActive)
{    
    IQueryable<Student> query = db.Student;
    if (id != null)
    {
        query = query.Where(student => student.ID == id.Value);
    }
    if (name != null)
    {
        query = query.Where(student => student.Name.Contains(name));
    }
    if (courseID != null)
    {
        query = query.Where(student => student.CourseID == courseID.Value);
    }
    if (isActive != null)
    {
        query = query.Where(student => student.IsActive == isActive.Value);
    }
    return query;
}

I haven't tried that, and it's possible that LINQ to SQL would get confused by the code to find the value of the nullable value types. You may need to write code like this:

    if (courseID != null)
    {
        int queryCourseID = courseID.Value;
        query = query.Where(student => student.CourseID == queryCourseID);
    }

It's worth trying the simpler form first though :)

Of course, all this gets a bit irritating. A helpful extension method could make life more concise:

public static IQueryable<TSource> OptionalWhere<TSource, TParameter>
    (IQueryable<TSource> source,
     TParameter? parameter, 
     Func<TParameter, Expression<Func<TSource,bool>>> whereClause)
    where TParameter : struct
{
    IQueryable<TSource> ret = source;
    if (parameter != null)
    {
        ret = ret.Where(whereClause(parameter.Value));
    }
    return ret;
}

You'd then use it like this:

public IQueryable<Student> FindByAllStudents
    (int? id, string name, int? courseID, bool? isActive)
{    
    IQueryable<Student> query = db.Student
        .OptionalWhere(id, x => (student => student.ID == x))
        .OptionalWhere(courseID, x => (student => student.CourseID == x))
        .OptionalWhere(isActive, x => (student => student.IsActive == x));
    if (name != null)
    {
        query = query.Where(student => student.Name.Contains(name));
    }
    return query;
}

Using a higher order function like this could get confusing if you're not really comfortable with it though, so if you're not doing very many queries like this you might want to stick with the longer but simpler code.

like image 137
Jon Skeet Avatar answered Sep 24 '22 08:09

Jon Skeet