简体   繁体   中英

Build Dynamic queries with LINQ

I was trying to build a dynamic generic method. To create a advanced search mechanism.

I could achieve something using Dynamic LINQ

IQueryable<Table> query = ObjectContext.Table;
if (parameters != null && parameters.Count > 0)
{
    foreach (KeyValuePair<string, dynamic> keyValuePair in parameters)
    {
        query = query.Where(keyValuePair.Key + " == @0", new object[] { keyValuePair.Value });
    }
}

But doing this, I need to load each field with something like this

ClassTable.Parameters.Add("FKTable.Foo", foo);
ClassTable.Parameters.Add("Bar", bar);

So I'm trying with other approach (This code works)

List<Table> lstTable = new List<Table>();
lstTable.AddRange(tableDAO.SelectWhere(
    u => this.EntityValues.Foo == u.Foo && this.EntityValues.Bar == u.Bar
));
return lstTable;

Now, my problem is, I wanted to do something more like (This code brings the result of the first query only)

List<Table> lstTable = new List<Table>();
lstTable.AddRange(tableDAO.SelectWhere(
    u => !string.IsNullOrEmpty(this.EntityValues.Foo) ? this.EntityValues.Foo == u.Foo : false 
    &&
    this.EntityValues.Bar != 0 ? this.EntityValues.Bar == u.Bar : false
));
return lstTable;

I didn't want to do something like this

IQueryable<Data.Story> query = ctx.DataContext.Stories;

if (criteria.StoryId != null) // StoryId
    query = query.Where(row => row.StoryId == criteria.StoryId);

if (criteria.CustomerId != null) // CustomerId
    query = query.Where(row => row.Project.CustomerId == criteria.CustomerId);

if (criteria.SortBy != null) // SortBy
    query = query.OrderBy(criteria.SortBy + " " + criteria.SortOrder.Value.ToStringForSql());

I know that my question is kinda jumbled, I'll provide edits and comments to fix it. just let me know.


TL;DR; I need help to create a dynamic query, where I only need to pass the parameters that are used in the search. So I can create a advanced search option to the user.

You could write the Expression 's yourself:

public static IQueryable<T> Where<T>(this IQueryable<T> source, string propertyOrFieldName, object value)
{
    var param = Expression.Parameter(typeof(T), "x");
    var prop = Expression.Property(param, name);
    var @const = Expression.Constant(value, prop.Type);
    var equals = Expression.Equal(prop, @const);
    var lambda = Expression.Lambda(equals, param);
    return source.Where(lambda);
}

foreach(var p in parameters)
{
    query = query.Where(p.Key, p.Value);
}

Like pswg suggested in his answer , I had to do it myself, but I did a little different from what he suggested.

I create two methods in my DAO class. The first one, I load a List of expressions, and in the second I read it and execute.

public List<System.Linq.Expressions.Expression<Func<E, bool>>> whereList = new List<Expression<Func<E, bool>>>();
public List<E> ExecuteSelectFilter()
{
    System.Linq.Expressions.Expression<Func<E, bool>> whereFinal = c => true;

    foreach (System.Linq.Expressions.Expression<Func<E, bool>> whereItem in whereList)
    {
        if (whereItem != null)
        {
            var invokedExpr = Expression.Invoke(whereFinal, whereItem.Parameters.Cast<Expression>());

            whereFinal = Expression.Lambda<Func<E, bool>>
                    (Expression.AndAlso(whereItem.Body, invokedExpr), whereItem.Parameters);
        }
    }
    return this.ObjectContext.CreateQuery<E>(EntitySetName).Where(whereFinal.Compile()).ToList();
}

Those methods I call in my DAO, so I can access from any business class I have.

tableDAO.whereList.Clear();

#region Filters
// Foo
if (!String.IsNullOrEmpty(this.entityValues.Foo)) 
    tableDAO.whereList.Add(q => q.Foo.Contains(this.entityValues.Foo));
// Bar
if (this.entityValues.Bar > 0) 
    tableDAO.whereList.Add(q => q.Bar== this.entityValues.Bar);
#endregion

return tableDAO.ExecuteSelectFilter();

hope this help someone, like it helped me.

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