【问题标题】:How to select/filter against substring in a list of strings?如何选择/过滤字符串列表中的子字符串?
【发布时间】:2009-11-05 05:43:46
【问题描述】:

我有一个 LINQ 结果集,我正试图以一种奇怪而奇特的方式进行过滤。

List<string> MyDomains = [Code to get list];

var x = (from a in dc.Activities
    where a.Referrer != null
        && a.Referrer.Trim().Length > 0
        && !a.Referrer.Contains("localhost")
        && a.SearchResults.Count() == 0
    orderby a.ID descending
    select a)
    .Take(20);

既然我已经解决了这个问题,让我更好地解释一下。 MyDomains 是一个字符串列表;每一个都是我拥有的一个根域。

a.Referrer 是一个字符串,其中包含从 GET 到我的一个网站的引荐来源网址。请注意,此字符串将包含子域、文件夹、文件和查询字符串。

我想通过 a.Referrer 的根域在 MyDomains 列表中过滤 x。也就是说,我想用这种方式返回所有不匹配的记录。结果集最终应该包含其 Referrer 不是我的域之一的活动。

我一直在学习 Lambda 表达式,但到目前为止还无法制作一个来实现这个目标,因为它实际上需要一个 where 子句,其中包含逻辑(可能是循环、子字符串等)。

目前我正在考虑将 X 转换为列表,手动过滤它们,然后将列表绑定到目标控件而不是绑定 X。我有一个扩展方法来获取 Uri 的根域和另一个来确定是否这是我的域,但不能将它们放在此处的 Lambda 中,因为它们“不支持对 SQL 的翻译”。

除了架构上的分歧,我如何在我的 LINQ 查询中实现这一点?


编辑:注意我想在查询中执行此操作,因此在添加 .Take(20) 之前删除匹配的记录。我希望每次都获得相同数量的结果,而无需调用数据库以获得更多结果。

【问题讨论】:

    标签: linq expression-trees


    【解决方案1】:

    如果我理解正确,您想获取前 20 个活动,按 ID 排序,其 Referrer 字段不包含 MyDomains 中的任何项目作为子字符串。

    以下或类似的东西应该可以工作:

    var theActivities = (from a in dc.Activities
        where a.Referrer != null
            && a.Referrer.Trim().Length > 0
            && a.SearchResults.Count() == 0
        select a);
    
    foreach(var domain in MyDomains) {
        theActivities = theActivities.Except(dc.Activities.Where(a => a.Referrer.Contains(domain)));
    }
    
    theActivities = theActivities.OrderBy(a => a.Id).Take(20);
    
    //Now you can query theActivities
    

    但是请注意,您最终会得到一个相当长的 SQL 查询,因为将为 MyDomains 中的每个项目添加一个 WHERE 子句。

    更新:确实,这行不通。由于查询表达式是在实际查询时计算的,所以所有Except 子句对domain 变量使用相同的值(这是最后一个值集)。

    我能想到的唯一解决方案是动态生成一个 SQL 命令来获取数据。我现在无法验证代码,但大概是这样的:

    var whereClauses=new List<string>();
    
    for(int i=0; i<MyDomains.Length; i++) {
        whereClauses.Add(string.Format("(Referrer like {{{0}}})", i));
    }
    
    var sqlFormattedDomains=MyDomains.Select(d => string.Format("%{0}%", d)).ToArray();
    
    var sqlCommand=string.Format(
        "select top 20 * from Activities where (not Referrer is null) and (not ({0})) order by Id",
        sqlFormattedDomains.Join(" or "));
    
    var x=dc.ExecuteQuery<Activities>(sqlCommand, sqlFormattedDomains);
    

    您将不得不为SearchResults.Count() == 0condition 扩展SQL 命令,我猜这与将连接子句添加到另一个表有关。

    【讨论】:

    • 不,foreach 的每次迭代最终都会覆盖前一个而不是补充它,所以我最终只计算了列表中的最后一项。 +1 一个好主意。
    • 我提出的替代方案可以吗?
    【解决方案2】:

    我认为添加

    && !MyDomains.Contains(a.Referrer)
    

    应该做的伎俩

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-10
    • 2013-09-24
    • 1970-01-01
    • 2021-08-07
    • 2014-07-15
    • 2022-01-16
    • 2020-07-30
    • 1970-01-01
    相关资源
    最近更新 更多