使用EFCore在MSSQL varchar字段中搜索多个单词

时间:2017-06-19 00:23:49

标签: c# sql-server asp.net-core entity-framework-core

我的项目使用ASP.Net Core 1.1,EF Core和SQL Server数据库。

我有一个字符串数组,应该在文本字段中搜索(实际上字段是标记列表,数组是标记数组)。

完整方案:

  • 在我的服务器端(.Net Core),我有一系列标签{'tag2','tag4'}。

  • 每个地方都存储在SQL Server中,其中包含用逗号'tag1,tag2,tag3'分隔的标记列表。

  • 我想获得至少匹配至少一个标签的20个最近的地方。

我考虑将数据表作为参数传递给具有自定义类型参数的SQL函数,但是直到v2时,.Net Core中还没有包含数据类型。

实体DbContext类中的C#代码类似于:

decimal lat=2.0, lng=3.0; float maxRadius=50000;
var tags = new Array<string>(){"tag1", "tag2"};

var places = await this.Set<Place>()
               .FromSql("SELECT * FROM GetPlaces(@p0, @p1, @p2, @p3, @p4)", maxResults, lat, lng, maxRadius, tags).ToListAsync();

(当然不幸的是,传递这样的标签不起作用)

SQL函数将是这样的:

WITH Results as (
    SELECT p.Id, p.Name
            , ([geography]::Point(@lat,@lng,(4326))).STDistance(Coordinates)) AS Distance
    FROM Places p
    INNER JOIN ValsToSearch v 
        ON p.Tags LIKE '%'+v.Val+'%'
    WHERE Distance < @distance
)
SELECT DISTINCT TOP(20) * FROM Results 
ORDER BY Distance

这个对我来说似乎不是很有效,因为它将字段与连接相乘然后区分它们,但我不知道是否有可能使它更好。

我想获得最有效的查询来做类似的事情。

任何帮助/想法? :) 将所有内容加载到内存中是不可取的,因为数据库中有200k行(在某些区域可能非常密集)

另一种选择是在c#代码中,但由于NetCore 1.1版中不存在坐标,我不确定它是否会正确转换为SQL(CONTAINSLIKE查询) :

var places = await (from p in this.Set<Place>()
         .FromSql("SELECT * FROM GetClosestPlaces(@p0, @p1, @p2)", lat, lng, maxRadius)
         where (from t in tags where p.Tags.Contains(t) select t).Any()
         select p).Take(maxResults).ToListAsync();

使用SQL函数:

CREATE FUNCTION [dbo].[GetClosestPlaces]
    (@lat decimal,@lng decimal,@maxRadius float=50000)
RETURNS TABLE AS RETURN 
    SELECT * FROM Places 
        WHERE ([geography]::Point(@lat,@lng,(4326)))
            .STDistance(([geography]::Point([Latitude],[Longitude],(4326)))) 
            < @maxDistance

任何建议?

目标是在SQL端,消耗的资源越少,并且在两端,耗时越少(服务应该给出非常快的答案,因为对于同一查询可能会多次调用)。

“此时”我在数据库中找不到任何好的解决方案。所以我用我的其他过滤器(距离)预过滤数据库数据,然后在内存中应用文本过滤器。 效率更高:SQL解决方案为500毫秒,而linq解决方案为100-150毫秒。

0 个答案:

没有答案