繁体   English   中英

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

[英]Creating Dynamic LINQ Queries using Expression Trees

我无法复制多个。在使用表达式树的linq查询中,由于该查询具有搜索功能,因此我需要此查询是动态的。我将要查询的数据库最终会变得很大,所以我需要高效且不能过滤客户端。 我至少尝试从这些列中的3个开始过滤。 在下面,我添加了三个我试图过滤的ID。 我已经读了很多表达式树,但是可以使用某人的帮助将它们实际应用到即时通讯中,因为它们使我感到困惑。

    public int? heightId { get; set; }
    public int? ageId { get; set; }
    public int? genderId { get; set; }

它不是动态的,因为您事先知道各列。 您也不需要使用表达式树。 您可以有条件地应用过滤器:

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)将返回前10行,其高度为1,性别为2,但年龄FindByFilter(10, heightId: 1, genderId: 2)

因此,您有一类(或几个类)的属性数量有限,可能少于100。

在代码中的某个位置,这可能在用户界面中,但是也可能是在读取互联网页面,文件或从数据库中获取信息之后,在代码中的某个地方,您将有一些输入,可以从中确定哪些输入必须在Where执行。

因此,在代码中的某个地方,您有一个函数,该函数接受一些输入并返回where的Expression:

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

再说一次:即使您想让运算符组合语句,如果使用组合框或类似框,也不会得到错误的输入,并且组合的数量也相当有限。

结论

尽管可以从字符串输入创建表达式,但这意味着您必须创建类似编译器的工具来检查错误的输入。 这将不容易理解,测试和维护。

由于请求的Where语句的数量相当有限(可能少于100个),因此请考虑使用一个开关大小的函数

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM