我正在尝试构建一个通用查询机制来访问我的存储库。我希望使用Lambda表达式来过滤和排序查询。我正在努力寻找一种方法来传递一般的Lambda表达式列表,特别是对于order-by,并且非常感谢帮助。
编辑:我想要满足的2个要求是,不要将IQueryable暴露在存储库之外,但仍然能够在数据库级别进行一些过滤和排序。
为了更好地说明这一点,让我向您展示代码
public class Query<T>
{
public class OrderBy<T>
{
public Expression<Func<T, **int**>> Clause { set; get; } // Order By clause
public bool Descending = true;
}
public Expression<Func<T, bool>> Where { set; get; } // Where clause
public IList<OrderBy<T>> OrderBys { set; get; } // Where clause
public Query()
{
OrderBys = new List<OrderBy<T>>();
}
}
public IEnumerable<Person> FindBy(Query<Person> query)
{
IQueryable<Person> Temp = GetObjectSet();
if (query.Where != null)
Temp = Temp.Where(query.Where);
foreach (var OrderByThis in query.OrderBys)
{
if (OrderByThis.Descending)
Temp = Temp.OrderByDescending(OrderByThis.Clause);
else
Temp = Temp.OrderBy(OrderByThis.Clause);
}
return Temp.ToList<Person>();
}
这一切都非常好,但表达&lt; FUNC&LT; T, int &gt;&gt;不是通用的。我需要能够做到这样的事情:
Query<Person> query = new Query<Person>();
Query<Person>.OrderBy<Person> clause1 = new Query<Person>.OrderBy<Person>();
clause1.Clause = m => m.Username;
Query<Person>.OrderBy<Person> clause2 = new Query<Person>.OrderBy<Person>();
clause2.Clause = m => m.DateOfBirth;
query.OrderBys.Add(clause1);
query.OrderBys.Add(clause2);
即。添加了许多不同类型的不同字段。
我想必须有一种方法可以将这些存储为通用Lambda函数,然后在存储库中将其转换为所需的强类型Lambda函数。
我该怎么做?
答案 0 :(得分:1)
阐述我的评论,我不明白为什么你需要从Expressions中构建自己的中间查询对象,然后从那个中间对象重构表达式,当你完全跳过那个翻译时。
给出您的示例查询:
repository.FindBy(people => people.OrderBy(p => p.Username).ThenBy(p => p.DateOfBirth));
请注意,例如,如果基于用户选择完成查询,您仍然可以逐步构建查询。以下查询等同于上述内容:
Func<IEnumerable<Person>, IEnumerable<Person>> query = people => people.OrderBy(p => p.Username);
query = query.ThenBy(p => p.DateOfBirth);
我知道您不希望在存储库之外公开IQueryable
,但您仍然可以使用带有以下签名的LINQ:
public IEnumerable<Person> FindBy(Func<IEnumerable<Person>, IEnumerable<Person>> query)
{
return query(GetObjectSet()).ToList();
}
但是,根据您的实际问题,您可以使用OrderBy
Expression<Func<T, object>>
属性类型来实现Clause
任务,或者如果这让您感到不安,您可以稍微限制一下更多的是使用IComparable
而不是对象,因为它实际上只需要排序,字符串和数字类型都可以实现它。
答案 1 :(得分:1)
正如我在回答your other question时所说,我总体上不鼓励这种做法。公开IQueryable<T>
/ IOrderedQueryable<T>
。
话虽如此,但在How to pass multiple Expressions to OrderBy for EF?的选定答案中,您可以根据自己的意图找到解决方案。
它允许您使用如下语法:
var query = context.Users ... ;
var queryWithOrderBy = ApplyOrderBy(query,
new OrderByExpression<User, string>(expression: u => u.UserName, descending: false), // a string, asc
new OrderByExpression<User, int>(expression: u => u.UserId, descending: true)); // an int, desc
var result = queryWithOrderBy.ToList(); // didn't throw an exception for me