【问题标题】:Build where clause body构建 where 子句主体
【发布时间】:2015-06-22 23:01:49
【问题描述】:

我正在尝试找到一种方法来构建 where 子句并将其传递给存储库 Get() 方法。它应该过滤名称以特定字母开头的项目。我能够构建此 Where 子句正文的一部分,但找不到如何处理项目名称不以字母开头的场景的方法。例如:_ItemName97_SomeName

所以,这是我的方法:

protected override Expression<Func<DataSetSettings, bool>> GetWhereClause()
{
    //The user has selected FilterLetter, for example: "A"
    // return all items which name starts with "A"
    if (!string.IsNullOrWhiteSpace(FilterLetter) && !FilterLetter.Equals("All"))
        return (x => x.Name.StartsWith(FilterLetter) && x.Type == Type);

    if (FilterLetter.Equals("Other"))
    {
        //Here i need to extract all items which name does not start with letter
    }

    //return All items of the current type
    return x => x.Type == Type;
}

如果有任何帮助,我将不胜感激!谢谢!

【问题讨论】:

  • 您是使用 Linq to SQL 还是实体框架,还是用于内存收集?
  • 我正在使用实体框架。
  • 你是不是先尝试了一些东西并得到了错误?我认为 Entity 没有 StartsWith 等价物。
  • 我环顾了一圈,找不到任何关于 EF 中复杂模式匹配的有用信息。我在下面发布了一个建议的答案。

标签: c# linq entity-framework collections


【解决方案1】:

现在我了解了您的需求,我环顾四周,并没有找到一个优雅的解决方案。似乎复杂的字符串模式匹配是 EF 的一个弱点。

我能看到的唯一方法是与每个字母进行比较,即:

!x.Name.StartsWith("A") && !x.Name.StartsWith("B") && //on and on to Z

或者确保将整个列表加载到内存中,然后使用正则表达式进行过滤:

protected override Expression<Func<DataSetSettings, bool>> GetWhereClause()
{
    var noletter = new Regex("^[^a-z].*", RegexOptions.IgnoreCase);

    return (
        x => x.Type == Type && (
            string.IsNullOrWhiteSpace(FilterLetter) || 
            FilterLetter == "All" || 
            (FilterType == "Other" && noletter.IsMatch(x.Name)) ||
            x.Name.StartsWith(FilterType)
        )
    );
}

如果您最终选择将所有内容加载到内存中,您至少可以先根据x.Type 进行过滤。这似乎是过滤中的共同点。至少这样您就不必将整个表加载到内存中。

【讨论】:

  • 感谢您的回答。我已经解决了内存中集合过滤的问题。我希望找到一种在数据库级别执行此操作的方法。
  • @vortex SQL Server 支持正则表达式,但 Entity Framework 和 Linq to SQL 没有它们的翻译。您能做的最好的事情就是模拟 LIKE 运算符,这是 ContainsStartsWith 在后台使用的。
  • 现在我将使用您的解决方案与正则表达式匹配。再次感谢。
【解决方案2】:

你可以在 StartsWith 上做 equals false

像这样:

return (x =&gt; x.Name.StartsWith(FilterLetter) == false &amp;&amp; x.Type == Type);

【讨论】:

  • 这行不通。如果用户选择“其他”进行过滤,那么我需要带上所有名称不以字母开头的项目。示例:_Asd, 12Name, *1OtherName
  • @vortex 您说的是“字母”,但您的示例是字符串。是单个字符还是多个字符不能在值的开头?
  • @vortex 没关系。我现在明白了。你的意思是非字母字符。所以不是 A - Z,而是数字和字符。
  • @jwatts1980,它是带有字符串的字母过滤器:A、B、C.....、其他、全部。如果用户单击“A”,我会过滤项目并仅显示名称以 A 开头的项目。如果他单击“其他”,我需要显示我在之前的评论中提到的项目 - _Asd, 12Name, *1OtherName
【解决方案3】:

我的建议是将所有类型的 1 个 db 调用放入一个列表中,然后使用 linq 查询该列表。您的示例将进行两次 db 调用。

List<Type> allTypes = new List<Type>();
List<Type> typesWithA = new List<Type>();
List<Type> typesWOA = new List<Type>();

// make one db call
allTypes = entities.Types.ToList();

typesWithA = allTypes.Where(x => x.Name.StartsWith(FilterLetter)).ToList();
typesWOA = allTypes.Where(x => !x.Name.StartsWith(FilterLetter)).ToList();

【讨论】:

  • 如果Types 是一个大表,这可能会对性能造成重大影响。
  • 是的。他必须想出另一种过滤器,这样他就不会拉成吨的行。
猜你喜欢
  • 1970-01-01
  • 2011-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-28
相关资源
最近更新 更多