简体   繁体   English

C#LINQ使变量where语句

[英]C# LINQ make variable where statement

I have a filter which applies to my results. 我有一个适用于我的结果的过滤器。

What i have now is the following: 我现在所拥有的是:

Filter 1 = Any
Filter 2 = Atlas
Filter 3 = phoenix

Now when the filter is on any , i run the following query: 现在,当过滤器在any上时 ,我运行以下查询:

foreach (DetectorStatu status in loadOperation.Entities.OrderBy(d => d.Status).Take(25).Reverse())

When the filter is on Atlas : 当过滤器位于Atlas上时

foreach (DetectorStatu status in loadOperation.Entities.OrderBy(d => d.Status).Where(d => ((d as DetectorStatu).Detector as Detector).EnabledDetectorTypes.Count(t => t.DetectorTypeID == 1) > 0).Take(25).Reverse())

When the filter is on Phoenix : 当过滤器在Phoenix上时

foreach (DetectorStatu status in loadOperation.Entities.OrderBy(d => d.Status).Where(d => ((d as DetectorStatu).Detector as Detector).EnabledDetectorTypes.Count(t => t.DetectorTypeID == 2 || t.DetectorTypeID == 3) > 0).Take(25).Reverse())

And the actual query that they are calling: 以及他们正在调用的实际查询:

[Query]
[OutputCache(OutputCacheLocation.Server, 60)]
public IQueryable<DetectorStatu> GetDetectorDatabacklog(int userID)
{
    User user = ObjectContext.Users
    .Include("TeamMemberships")
    .First(u => u.UserID == userID);

    var teamIDs = user.TeamMemberships.Select(t => t.TeamID).ToList();
    var siteIDs = ObjectContext.SiteMemberships.Where(t => teamIDs.Contains(t.TeamID)).Select(t => t.SiteID).ToList();

    var DetectorStatus = ObjectContext.DetectorStatus
        .Include("Detector")
        .Include("Detector.Track")
        .Include("Detector.Site")
        .Include("Detector.EnabledDetectorTypes")
        .Include("Detector.EnabledDetectorTypes.DetectorType")
        .Where(d => siteIDs.Contains(d.Detector.SiteID))
        .OrderBy(d => d.Status);

    return DetectorStatus;
}

Now my question: 现在我的问题是:

Is there a way to make this dynamic/shorter? 有没有办法使这种动态/缩短?

Becuase right now i check the filters via a if statement, and then run all the code. 因为现在我通过if语句检查过滤器,然后运行所有代码。 However, i want to add 8 more filter. 但是,我想再添加8个过滤器。 And to add 8 more if statements will make the code really big and very unclear. 再加上8条if语句会使代码变得很大且非常不清楚。
And i'm basically adding 50 lines of code, while i just need to change 1 line of the query. 我基本上是添加50行代码,而我只需要更改查询的1行。

You can build a query in multiple steps: 您可以分多个步骤构建查询:

IQueryable<DetectorStatu> query = loadOperation.Entities.OrderBy(d => d.Status);

Then you add the filter, depending on your settings: 然后根据您的设置添加过滤器:

if (<filter is Atlas>)
{
  query = query.Where(d => ((d as DetectorStatu).Detector as Detector).EnabledDetectorTypes.Count(t => t.DetectorTypeID == 1) > 0);
}
else if (<filter is Phoenix>)
{
  query = query.Where(d => ((d as DetectorStatu).Detector as Detector).EnabledDetectorTypes.Count(t => t.DetectorTypeID == 2 || t.DetectorTypeID == 3) > 0);
}

etcetera. 等。 Of course you must substitute the correct code for <filter is ...> . 当然,您必须用正确的代码替换<filter is ...>

and finally you have only one foreach statement: 最后,您只有一个 foreach语句:

query = query.Take(25).Reverse();
foreach (DetectorStatu status in query) { ... }

Just one query will be sent to the database, at the moment you enter the foreach . 在您输入foreach的那一刻,仅一个查询将被发送到数据库。 This will take into account all steps from the "OrderBy" until the "Reverse". 这将考虑从“ OrderBy”到“ Reverse”的所有步骤。

It's possible to define a System.Linq.Expression: 可以定义System.Linq.Expression:

Expression<Func<DetectorStatu, bool>> filter = null;

if(any){
   filter = x => true;
}

if(Atlas){
   filter = d => ((d as DetectorStatu).Detector as Detector).EnabledDetectorTypes.Count(t => t.DetectorTypeID == 1) > 0
}

if(Phoenix){
   filter = d => ((d as DetectorStatu).Detector as Detector).EnabledDetectorTypes.Count(t => t.DetectorTypeID == 2 || t.DetectorTypeID == 3) > 0;
}

In the end: 到底:

foreach (DetectorStatu status in loadOperation.Entities.OrderBy(d => d.Status)
   .Where(filter)
   .Take(25).Reverse())

Where clause simply expects a predicate (a Func that returns bool), which you can pass as an argument to your function. Where子句只需要一个谓词(一个返回bool的Func),您可以将其作为参数传递给函数。 So basically you just can pass different predicate for each of your "Filter" option and apply it on your IQueryable for Where clause 因此,基本上,您可以为每个“ Filter”选项传递不同的谓词,并将其应用于IQueryable for Where子句

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

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