如何使LINQ执行(SQL)LIKE范围搜索

我非常需要帮助,我一直试图这样做一段时间。

所以我有这个查询:

Select name from BlaBlaBla order by case when name like '9%' then 1 end, case when name like '8%' then 1 end, case when name like '7%' then 1 end, case when name like '6%' then 1 end, case when name like '5%' then 1 end, case when name like '4%' then 1 end, case when name like '3%' then 1 end, case when name like '2%' then 1 end, case when name like '1%' then 1 end, case when name like '0%' then 1 end, name 

我想在一个新的C#,Asp.Net,类,在我的解决方案中,到域项目中实现它,所以它将是一个OrderTypefilter,对于某些function……

现在我有这个:

 var param = Expression.Parameter(typeof(T), "item"); var paramName = Expression.Property(param, "Name"); var regexMatch = Expression.Constant("^[0-9]"); var startsWithDigit = Expression.Call(typeof(Regex), "IsMatch", null, paramName); var lambda = Expression.Lambda<Func>(startsWithDigit, param); return namesList.OrderBy(lambda) .ThenBy(BlaBla1()) .ThenByDescending(BlaBla2()) .ThenByDescending(BlaBla3()) .ThenBy(BlaBla4()); 

但它告诉我,Expression不包含“IsMatch”方法。

你能帮我么? 谢谢!!!

这里的问题是包含Regex无法转换为SQL,因此即使您成功构建了正确的表达式,也无法在LINQ中将其用于SQL后端。 但是,SQL的LIKE方法也支持范围通配符,如[0-9] ,所以诀窍是让你的LINQ转换为包含LIKE语句的SQL。

LINQ-to-SQL提供了显式使用SQL LIKE语句的可能性:

 return namesList.OrderBy(r => SqlMethods.Like(r.Name, "[0-9]%")) ... 

但是,此SqlMethods类只能在LINQ-to-SQL中使用。 在Entity Framework中,有一些字符串函数隐式转换为LIKE ,但它们都不启用范围通配符( [xy] )。 在EF这样的声明……

 return namesList.OrderBy(r => r.Name.StartsWith("[0-9]")) ... 

……会转化为废话:

 [Name] LIKE '~[0-9]%' ESCAPE '~' 

也就是说它徒劳地寻找以文字字符串“[0-9]”开头的名字。 所以只要你继续使用LINQ-to-SQL SqlMethods.Like就可以了。

在Entity Framework 6.1.3(及更低版本)中,我们必须使用稍微不同的方式来获得相同的结果……

 return namesList.OrderBy(r => SqlFunctions.PatIndex("[0-9]%", c.Name) == 1) ... 

…因为PatIndex中的PatIndex也支持范围模式匹配。

但是在Entity Framwork 6.2中,由于新的DbFunctions.Likefunction,我们又回到了LINQ-to-SQL的轨道上:

 return namesList.OrderBy(r => DbFunctions.Like(r.Name, "[0-9]%")) ... 

最后,Entity Framework核心还有一个Like函数:

 return namesList.OrderBy(r => EF.Functions.Like(r.Name, "[0-9]%")) ... 

您可以在下面看到这种处理订单案例的方法示例。

  static void Main(string[] args) { List list = new List(); for (int i = 0; i < 100; i++) { list.Add(new Obvious(i.ToString(), i)); } string name = list[30].name; switch (name) { case "9": list.OrderBy(o => o.perc) .ThenByDescending(o => o.name); break; default: list.OrderByDescending(o => o.name) .ThenBy(o => o.perc); break; } } public class Obvious { public string name { get; set; } public int perc { get; set; } public Obvious(string _name, int _perc) { this.name = _name; this.perc = _perc; } } 

如果我是你,我不会尝试使用表达式解决这个问题,因为它带来了很多复杂性。

我看到你想要一个通用的方法,所以它可以使用不同的域实体,但你期望每个实体都有一个Name属性。 您可以通过定义包含Name属性的接口以更简单的方式解决此问题。 像这样:

  public static void Main() { var test = new List() { new YourDomainEntity() { Name = "1test", OtherProperty = "1"}, new YourDomainEntity() { Name = "2test", OtherProperty = "2" }, new YourDomainEntity() { Name = "2test", OtherProperty = "1" } }; var k = Foo(test).ToList(); } public interface INameOrderable { string Name { get; set; } } public interface IOtherPropertyOrderable { string OtherProperty { get; set; } } public static IEnumerable Foo(IEnumerable list) where T : INameOrderable, IOtherPropertyOrderable { return list.OrderBy(a => a.Name, new NamesDescComparer()).ThenBy(b => b.OtherProperty); } public class NamesDescComparer : IComparer { public int Compare(string x, string y) => -String.CompareOrdinal(x, y); } class YourDomainEntity : INameOrderable, IOtherPropertyOrderable { public string OtherProperty { get; set; } public string Name { get; set; } } 

我相信方法Foo是你正在寻找的。

注意where T : INameOrderable部分。 它将此方法的使用限制为实现INameOrderable接口的实体