使用LINQ构建动态查询

本文关键字:查询 动态 构建 LINQ 使用 | 更新日期: 2023-09-27 18:06:46

我试图建立一个动态的泛型方法。创建高级搜索机制。

我可以用动态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 });
    }
}

我需要这样加载每个字段

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

所以我尝试用其他方法(此代码有效)

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

现在,我的问题是,我想做一些更像(这段代码只带来第一个查询的结果)

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;

我不想做这样的事情

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());
我知道我的问题有点混乱,我会提供编辑和评论来修复它。让我知道。

TL;DR;我需要帮助来创建一个动态查询,其中我只需要传递在搜索中使用的参数。所以我可以为用户创建一个高级搜索选项

使用LINQ构建动态查询

您可以自己编写Expression:

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);
}

就像p.s.w.g在他的回答中建议的那样,我必须自己做,但我做的和他建议的有点不同。

我在DAO类中创建了两个方法。在第一个程序中,我加载了一个表达式列表,在第二个程序中,我读取它并执行。

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();
}

这些方法我在我的DAO中调用,所以我可以从任何业务类访问。

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();

希望这篇文章能帮助到别人,就像它曾经帮助过我一样