C# 在LINQ Where子句中使用NaturalSortComparer

C# 在LINQ Where子句中使用NaturalSortComparer,c#,linq,C#,Linq,假设我有一个表Table1,其中有一个字符串字段[ProductString],其中包含以下值: 字母、字母数字或数字:例如ABC、B4、U2、C5、100、U1、U5、U6、U11 我希望能够获取像“ProductString>=U5”这样的where子句,并将其作为字符串传递给LINQ语句,以便它进行计算 Table1.Where(t=> t.ProductString >= 'U5'); 通常,这将返回结果U5和U6 但是,我希望能够以某种方式使用,以便返回的结果是U5、U6

假设我有一个表Table1,其中有一个字符串字段[ProductString],其中包含以下值: 字母、字母数字或数字:例如ABC、B4、U2、C5、100、U1、U5、U6、U11

我希望能够获取像“ProductString>=U5”这样的where子句,并将其作为字符串传递给LINQ语句,以便它进行计算

Table1.Where(t=> t.ProductString >= 'U5');
通常,这将返回结果U5和U6

但是,我希望能够以某种方式使用,以便返回的结果是U5、U6和U11


我知道如何在OrderBy中使用比较器,因为我希望能够在Where阶段使用它。

使用自然排序比较器:

var comparer = new NaturalComparer();
Table1.Where(t=> 
    comparer.Compare(t.ProductString, "U5") >= 0);
假设您所有的产品字符串都是U%number%格式,那么为什么不滥用这个事实呢

Table1.Where(t=> int.Parse(t.ProductString.Replace("U","")) >= 5);

如果您使用LINQ to Entities,我不确定这是否会编译为存储表达式(即SQL知道如何处理它,我想应该是这样)。

如果您经常进行类似的搜索,那么最好的做法是在表中添加两个新字段,[ProductCode]&[ProductNumber]将[ProductString]的两个部分分开

然后你会变成:

 Table1.Where(t=> t.ProductCode == "U" && t.ProductNumer > 5);

考虑到公认的答案,我有点困惑,这个问题是否与LINQ和实体相关。接受的答案似乎不是一个在LINQtoEntities上下文中工作的解决方案,但OP对该问题的评论似乎证实了这是在数据库上下文中执行的。无论如何,这个答案专门针对LINQ to实体

我认为在SQLServer中这样做很难,但并非不可能。问题是.NET知道什么是
NaturalSortComparer
,但SQL Server(您希望查询最终发生的地方)没有这样的概念。我能想到的最好的主意包括两个部分:

  • 在SQL server中创建一个UDF(用户定义函数),该UDF将提供可通过自然排序订购的产品:
    创建函数Naturalize(@val as nvarchar(max))返回nvarchar(1000)
    。有一个非常酷的答案,就是围绕CLR函数创建一个UDF包装器来实现这一点
  • 接下来,为您的
    DbContext
    创建一个函数映射,该映射将上面的UDF映射到一个可以在EF查询中针对
    DbContext
    调用的函数。大概是这样的:

    [DbFunction("MyContext", "Naturalize")]
    public static string Naturalize(this string value)
    {
        throw new NotSupportedException("This function can only be invoked from LINQ to Entities.");
    }
    
  • 一旦这两部分就绪,就可以在实体查询中使用这个新函数,使用比较中的
    归化值来比较字符串:

    Table1.Where(t=> t.ProductString.Naturalize() >= "U5".Naturalize());
    

    请记住,UDF将针对查询中包含的每一行执行,这是上例中的整个表。在将函数作为子查询应用之前,您需要确保将查询缩减到可管理的程度。或者,您可能希望尝试对相关表应用某种类型的基于UDF的索引。

    创建比较器实例,然后使用它…@JeffMercado,但谓词将应用于服务器端。整张桌子都会被取走,我想OP会按照这种方式来做。恐怕存储过程是必要的。@pwas:不清楚源是什么。如果他在之前的查询中使用了这个比较器,那么它可能不是一个数据库。我们可以猜出我们想要的一切,但最终,在他澄清之前,这并不重要。如果这是一个由数据库服务器执行的查询,你不能。这是一个由SQL server数据库执行的查询,它将被合并到ExpressionTree中,但是EF将无法使用
    NotSupportedException
    将其转换为SQL。不能假定字符串是这种格式。它可能只是字母、字母数字或数字:例如ABC、B4、U2、C5、100。我将更新问题使用
    NaturalComparer
    的解决方案是否符合您的要求?实际上需要这样,因为LINQ to Entities不知道比较方法是什么:Table1.AsEnumerable()。其中(t=>comparer.Compare(t.PriorityString,“U5”)>=0);真正的查询远比这更通用:它都是用户驱动的。根据用户选择的过滤器,ProductCode甚至可能不在查询中。和。。它是由用户选择的任意格式。查询可以是((ProductCode>'U5'或类似'%k'的标记)和日期<现在)或(Message='text'和日期<昨天)或其他字符串='100'或优先级