创建动态LINQ查询使用表达式树

问题描述 投票:-1回答:2

我有麻烦,能够使用表达式树复制多个.Wheres在我的LINQ查询,我需要这个查询是动态的,因为它的搜索feature.The数据库中,我将最终被查询将获得大量,所以我需要的效率和斜面筛选客户端。我至少想通过过滤这些列3开始。下面我添加了三个id的即时通讯试图通过筛选。我有很多读入表达式树,但可以使用某人的帮助,把它们真正应用到什么即时通讯做,因为他们混淆了我。

    public int? heightId { get; set; }
    public int? ageId { get; set; }
    public int? genderId { get; set; }
c# sql linq
2个回答
1
投票

这不是动态的,因为你事先知道的列。你并不需要使用表达式目录树为好。你可以只应用过滤器条件:

public Class[] FindByFilter(int limit, int? heightId = null, int? ageId = null, int? genderId = null)
{
    var classes = databaseContext.Set<Class>();

    if (heightId.HasValue)
        classes = classes.Where(c => c.HeightId == heightId.Value);

    if (ageId.HasValue)
        classes = classes.Where(c => c.AgeId == ageId.Value);

    if (heightId.HasValue)
        classes = classes.Where(c => c.GenderId == genderId.Value);    

    return classes.Take(limit).ToArray();
}

所以,现在FindByFilter(10, 1, null, 2)或同等FindByFilter(10, heightId: 1, genderId: 2)将返回身高1,性别2,但任何年龄TOP 10行。


0
投票

所以,你有一个类(或多个类)与数量有限的属性,可能比100少。

某处在你的代码,这可能是在用户界面,但它也可以是阅读的网络页面,文件,或者在你的代码从数据库中获取信息,地方你有一些输入,从中可以决定之后, Where必须执行。

因此,在你的代码的某个地方,你有一个函数,产生了一些输入的返回你在表达:

Expression<Func<MyTable, bool>> CreateExpression(MyInput input) {...}

问题是,我们不知道你是怎么得到的输入。我们所知道的是,仅仅是有一个有限的(小于前面提到的100)可能的输出。如果有输入错误,不是程序应纠正这一成最佳猜测输出,或拒绝产生输出。

无论如何,这漫长的故事是要告诉你,那应该创建表达式的代码是相对有限的。如果你不让它动,而是创建一个非动态功能,即使你有50例大switch语句这是更好的方式可以理解的,可测试,可维护。

例如:假设操作者必须输入姓名和他要过滤的属性的值。他可能会让这种情况下你警告打字错误操作员输入错误

Expression<Func<MyTable, bool>> CreateExpression(string input, int value)
{
     // TODO: make the procedure case insensitive
    switch (input)
    {
        case "HeightId":
             return myItem => myItem.HeightId == value;
        case "AgeId":
             return myItem => myItem.AgeId == value;
        ...
        default:
            WarnUserIncorrectInput(...)
            return null;
    }
}

多少情况下,你期待什么呢?即使有20个,这些代码会更容易理解,并检查比如果你会用一些神奇的演绎创造你的表达错误输入。毕竟:这个神奇的解释也应该检查错误输入。

如果在未来的某个属性将被添加或删除,那么这将是相当容易保持这种功能。

复杂的表达式

这可能是你想要的操作者使用一些定义的语言来表达结合起来,是这样的:

"HeightId == 4 AND AgeId == 10 OR ..."

如果您会选择这样那样的投入,你让你的生活非常困难。你几乎就必须建立某种形式的编译器这一点,检查各种错误输入。你必须在操作装置的特性进行检测,当他指的操作,或者比较器。这不容易做到。

如果你真的想表达合并的可能性,考虑使用的用户界面元素,如组合框,用户必须选择一个属性,然后键入正确的值类型。

因为属性的数目是有限的,则可以使用一个程序像上面以产生表达。该组合像下面做:

ExpressionFunc<TSource, bool>> CreateAnd<TSource>(
    Expression<Func<TSource, bool>> X,
    Expression<Func<TSource, bool>> Y)
{
     return (sourceElement) => X(sourceElement) && Y(sourceElement);
}

还是那句话:即使你不想让运营商合并报表,如果使用组合框或类似的,你不能得到不正确的输入,以及组合的数量也相当有限。

结论

虽然可以创建一个字符串输入一个表达式,这将意味着你必须创建一个编译器般的东西,检查错误的输入。这不会是容易理解,测试,维护。

作为其中的语句相当有限的请求数,大概不到100,可以考虑使用的功能有一个大的switch-case

© www.soinside.com 2019 - 2024. All rights reserved.