使用'Like'将本地序列与查询进行比较-最有效的方法

本文关键字:比较 方法 有效 Like 使用 查询 | 更新日期: 2023-09-27 18:11:58

我知道这里有几个类似的问题,关于将列表与使用Sql 'Like'操作作为比较器的查询进行比较。

我所知道的是,对于这种类型的比较,使用Linq2Sql没有直接的转换。所提供的方法Contains()在Sql中转换为'IN',并且是一个精确比较器。我也知道非精确比较方法(SqlMethods.Like(), String.Contains(), StartsWith()和EndsWith())都在单个项目上工作,而不是列表。

目前,我的查询在foreach循环中提供所需的功能,但是,我担心网络上的带宽以及大循环对DB服务器的压力。

我的问题是:在最小化网络/服务器负载的同时,执行此操作的最有效方法是什么?

当前实现的代码片段:

using (var context = new GeoDataContext())
{
    var originalSuggestions = new List<SuggestItem>();
    foreach (var suggestItem in suggestionList)
    {
        var item = suggestItem;
        var placeNameList = context.tl_2014_39_places.Where(placeName =>
                       placeName.NAME.Contains(item.Term)).Select(
                           place => place.NAME).ToList();
   }
}

使用'Like'将本地序列与查询进行比较-最有效的方法

如果您确实需要性能,那么在这种情况下应该使用原始sql查询。即便如此,它也不会非常容易(同样,如果你需要性能的话)。您必须创建这样的自定义类型:

CREATE TYPE dbo.StringList AS TABLE (value NVARCHAR(MAX));

然后在c#代码中将这种类型的变量(即@terms)声明为DataTable,然后执行如下操作

select NAME from tl_2014_39_places pl where exists (select 1 from @terms where pl.NAME like '%' + value + '%') 

或使用@terms变量连接表。然后执行SqlCommand,您将在一个查询中获得结果。如果你决定遵循原始sql查询的路线,我可以帮助你找到正确有效的查询(上面的查询只是一个例子)。

更新:这里是完整的工作示例。它假设存在列NAME的表tl_2014_39_places,并且您使用上面的查询创建了自定义类型StringList:

private static void Main(string[] args) {
        var termsTable = new DataTable();
        var suggestionList = new List<string>() {"one", "two", "three"};
        termsTable.Columns.Add(new DataColumn("value", typeof (string)));
        foreach (var term in suggestionList) {
            termsTable.Rows.Add(term);
        }
        using (var conn = new SqlConnection(@"data source=(LocalDb)'v11.0;initial catalog=TestDB;integrated security=True;")) {
            conn.Open();
            using (var cmd = new SqlCommand("select NAME from tl_2014_39_places pl where exists (select 1 from @terms where pl.NAME like '%' + value + '%') ", conn)) {
                cmd.Parameters.Add(new SqlParameter("terms", SqlDbType.Structured) {
                    Value = termsTable,                        
                    TypeName = "dbo.StringList"
                });
                using (var reader = cmd.ExecuteReader()) {
                    while (reader.Read()) {
                        Console.WriteLine(reader[0]);
                    }
                }
            }
        }
        Console.ReadKey();
    }

请注意,一般情况下,喜欢以"%"开头(即:(以"结束"查询)是低效的,因为需要扫描整个表才能获得结果。但这与问题本身无关,当然它仍然比循环和多个数据库查询更有效。您还可以使用以下等效查询来代替where exists:

select NAME from tl_2014_39_places pl inner join @terms t on pl.NAME like '%' + t.value + '%'

试试这个,

如果您想检查Term是否有placeName.NAME

var placeNameList  = context.tl_2014_39_places
                     .Where(placeName => suggestionList
                                         .Select(x => x.Term)
                                         .Contains(placeName.NAME))
                     .Select(place => place.NAME).ToList();

如果您想检查placeName.NAME是否有Term

var placeNameList  = context.tl_2014_39_places.AsEnumerable()
                     .Where(placeName => suggestionList.Any(x => placeName.Conaints(x.Term))
                     .Select(place => place.NAME).ToList();

为了避免区分大小写的搜索,您可以对两个比较字符串使用ToLower()方法,例如:placeName.ToLower().Conaints(x.Term.ToLower())