如何使 LINQ 执行(SQL)LIKE 范围搜索
Posted
技术标签:
【中文标题】如何使 LINQ 执行(SQL)LIKE 范围搜索【英文标题】:How to make LINQ execute a (SQL) LIKE range search 【发布时间】:2018-04-07 17:53:26 【问题描述】:我非常需要帮助,我已经尝试了一段时间了。
所以我有这个查询:
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 类中实现它到域项目,所以它将是一个 OrderType 过滤器,用于某些功能......
现在我有这个:
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<T, bool>>(startsWithDigit,
param);
return namesList.OrderBy(lambda)
.ThenBy(BlaBla1())
.ThenByDescending(BlaBla2())
.ThenByDescending(BlaBla3())
.ThenBy(BlaBla4());
但它告诉我,Expression 不包含“IsMatch”方法。
你能帮帮我吗? 谢谢!!!
【问题讨论】:
看起来您正在使用一些支持 LINQ 的 ORM。哪一个?另外,为什么要手动构造表达式而不是使用 LINQ 语法? 您希望在数据库中使用一些 ORM 还是在内存中执行此排序? 嗯,这里使用的ORM,是Linq to Sql 问题是:我有一个名称列表,其中一些以数字开头,我想在从 0 到 9 排序的列表末尾过滤它们(以数字开头的那些) ...而且我希望所有这些都发生在 Linq 中,ORM 使用 ENTITY 或 ADO(没关系)。 【参考方案1】:这里的问题是包含Regex
的表达式无法转换为SQL,因此即使您成功构建了正确的表达式,也无法在LINQ to 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 中使用。在实体框架中有字符串函数可以转换为LIKE
隐式,但它们都没有启用范围通配符([x-y]
)。在 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) ...
...因为SqlFunctions 中的PatIndex
也支持范围模式匹配。
但在实体框架 6.2 中,由于新的 DbFunctions.Like
函数,我们回到了使用 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]%")) ...
【讨论】:
谢谢@Gert。这确实帮助我解决了我的问题,并且现在正在运行 感谢您提供完整而完整的答案。 ef版本之类的细节对我帮助很大。 在 EF 6.4.4 中使用 SqlMethods.Like -> LINQ to Entities 无法识别方法 'Boolean Like(System.String, System.String)' @Omid-RH 这个 SqlMethods 类只能在 LINQ-to-SQL 中使用。 感谢@Gert-Arnold【参考方案2】:您可以在下面看到这种处理订单情况的示例。
static void Main(string[] args)
List<Obvious> list = new List<Obvious>();
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;
【讨论】:
我认为你没有理解这个问题。他想构建一个可以发送到支持 LINQ 的 ORM 的表达式。或者至少,看起来是这样。 你好。很抱歉这么晚才回答。是的,这正是我想要的!因为,这正是其他人的制作方式。我希望以数字开头的名称位于列表的末尾,按 asc 排序 是的,ORM 是 LINQ “你到底想要什么”?我的解决方案还是@TsahiAsher 建议的解决方案? 好吧,@Gert,刚刚为我回答了我的问题,我几乎完成了我的语法(算法)。谢谢@Kadir!【参考方案3】:如果我是你,我不会尝试使用表达式来解决这个问题,因为它会带来很多复杂性。
我看到您希望有一个通用方法,以便它可以与不同的域实体一起使用,但您希望每个实体都有一个 Name
属性。
您可以通过定义包含Name
属性的接口以更简单的方式解决此问题。像这样:
public static void Main()
var test = new List<YourDomainEntity>()
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<T> Foo<T>(IEnumerable<T> list) where T : INameOrderable, IOtherPropertyOrderable
return list.OrderBy(a => a.Name, new NamesDescComparer()).ThenBy(b => b.OtherProperty);
public class NamesDescComparer : IComparer<string>
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
方法正是您要找的。p>
注意where T : INameOrderable
部分。它将此方法的使用限制为实现INameOrderable
接口的实体
【讨论】:
以上是关于如何使 LINQ 执行(SQL)LIKE 范围搜索的主要内容,如果未能解决你的问题,请参考以下文章