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

C# 使用表达式树创建动态LINQ查询,c#,sql,linq,C#,Sql,Linq,我无法复制多个。在我的使用表达式树的linq查询中,我需要此查询是动态的,因为它是一个搜索功能。我最终要查询的数据库将变大,因此我需要高效且无法筛选客户端。我至少试着从其中3列开始过滤。下面我添加了三个我试图过滤的ID。我已经阅读了很多关于表达式树的内容,但是我需要一些人的帮助来将它们应用到我所做的事情中,因为它们让我感到困惑 public int? heightId { get; set; } public int? ageId { get; set; } public

我无法复制多个。在我的使用表达式树的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();
}
public类[]FindByFilter(int-limit,int-heightId=null,int-ageId=null,int-genderId=null)
{
var classes=databaseContext.Set();
if(heightId.HasValue)
class=classes.Where(c=>c.HeightId==HeightId.Value);
if(ageId.HasValue)
class=classes.Where(c=>c.AgeId==AgeId.Value);
if(heightId.HasValue)
class=classes.Where(c=>c.GenderId==GenderId.Value);
返回类.Take(limit).ToArray();
}
因此,现在
FindByFilter(10,1,null,2)
或等效的
FindByFilter(10,heightId:1,genderId:2)
将返回前10行,高度为1,性别为2,但不包括任何年龄

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

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

因此,在代码中的某个地方,有一个函数,它接受一些输入并返回表达式,其中:

Expression<Func<MyTable, bool>> CreateExpression(MyInput input) {...}
如果你选择这样的投入,你的生活会变得非常困难。您几乎必须为此构建某种编译器,检查各种错误输入。您必须检测运算符何时表示属性,何时表示操作或比较器。不容易做到

如果您真的希望有可能组合表达式,请考虑使用用户界面元素,如组合框,用户必须选择一个属性,并键入正确的值类型。p> 因为属性的数量是有限的,所以可以使用上面的过程来创建表达式。组合如下所示:

ExpressionFunc<TSource, bool>> CreateAnd<TSource>(
    Expression<Func<TSource, bool>> X,
    Expression<Func<TSource, bool>> Y)
{
     return (sourceElement) => X(sourceElement) && Y(sourceElement);
}
ExpressionFunc>CreateAnd(
表达式X,
表达式(Y)
{
返回(sourceElement)=>X(sourceElement)和&Y(sourceElement);
}
再次强调:即使你想让操作符组合语句,如果你使用组合框或类似的,你也不能得到错误的输入,而且组合的数量也是相当有限的

结论

虽然可以从字符串输入创建表达式,但这意味着您必须创建一个类似于编译器的东西来检查错误的输入。这不容易理解、测试和维护


作为请求的数量,其中语句是相当有限的,可能小于100,考虑使用具有大切换情况的函数

为什么需要表达式树?如果您在设计时知道这三列是什么,为什么不能在这三列上使用
Where
。@YeldarKurmangaliyev因为用户可以选择是否使用该功能进行搜索,所以并非所有三列都会被选作搜索选项。我希望第一次这样做是有意义的。但是从数据库中点击pull的Where()呢?我想先构建查询,然后再查询database@Yaboy93否,查询将仅作为单个查询在
.ToArray()
上编译和执行,并应用所有指定的
。其中
条件。您可能想阅读更多关于thank You@YeldarKurmangaliyev的信息,所以请确保在阅读本文后,查询实际上只在您实际请求正确数据时执行,因此点击.ToArray()或ToList()会触发db检索?因此,理想情况下,在调用db correct之前,您可以有20个位置来尽可能多地过滤数据?@Yaboy93:)只有在您枚举查询时,才会构建和执行查询。它可以
.ToArray()
.ToList()
甚至
foreach
"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);
}