这是我的实体框架linq请求(用户已经存在且我的纬度和经度是十进制的):
IQueryable<Event> dbQuery = context.Set<Event>()
.Where(e => e.GeoLat != null && e.GeoLong != null && user.Latitude != null && user.Longitude != null)
.Where(e => DbGeography.PointFromText("POINT("+e.GeoLong+" "+ e.GeoLat+")", 4326)
.Distance(DbGeography.PointFromText("POINT(" + user.Longitude + " " + user.Latitude + ")", 4326)) < distanceKM*1000);
以下是生成的SQL请求的相关部分:
AND
(
[Extent1].[GeoLat] IS NOT NULL
)
AND
(
[Extent1].[GeoLong] IS NOT NULL
)
AND
(
48,697161
/* @p__linq__1 */
IS NOT NULL
)
AND
(
2,189617
/* @p__linq__2 */
IS NOT NULL
)
AND
(
(
geography::stpointfromtext(N'POINT(' +
CASE
WHEN (
[Extent1].[GeoLong] IS NULL
)
THEN
N''
ELSE cast( [Extent1].[GeoLong] AS nvarchar(max))
END
+ N' ' +
CASE
WHEN (
[Extent1].[GeoLat] IS NULL
)
THEN
N''
ELSE cast( [Extent1].[GeoLat] AS nvarchar(max))
END
+ N')', 4326).stdistance(geography::stpointfromtext(N'POINT(' + cast( 2.189617 AS nvarchar(max)) + N' ' + cast( 48.697161 AS nvarchar(max)) + N')', 4326))
)
< cast( 50
/* @p__linq__3 */
* 1000 AS float)
)
这是我得到的错误:
在执行用户定义的例程或聚合&#34; geography&#34;期间发生.NET Framework错误: System.FormatException:24141:输入的第7位需要一个数字。输入有)。
错误似乎告诉我POINT()中的经度和纬度值实际上是空字符串(&#39;)&#39;在位置7 =&gt;空值)。 我不明白为什么我会收到此错误,因为我告诉SQl只接受值为NOT NULL的行。看起来SQL甚至在值为NULL的行上也会执行地理操作。
你能帮我理解原因吗?
我使用EF6。
答案 0 :(得分:3)
SQL Server不会对AND
操作执行短路评估。您可以使用IFNULL
运算符生成??
语句来解决您的问题:
IQueryable<Event> dbQuery = context.Set<Event>()
.Where(e => e.GeoLat != null && e.GeoLong != null &&
user.Latitude != null && user.Longitude != null)
.Where(e =>
DbGeography.PointFromText(
"POINT(" + (e.GeoLong ?? "1") + " " + (e.GeoLat ?? "1") + ")", 4326)
.Distance(DbGeography.PointFromText(
"POINT(" + (user.Longitude ?? "1") + " " + (user.Latitude ?? "1") + ")", 4326)
) < distanceKM * 1000)
编辑:如果由于NULL
值转换为空字符串而出现问题,您可以尝试将它们转换为任意整数值,例如1.自另一个Where
子句将过滤掉这些行,只要它不会引发任何错误,它们的计算无关紧要。
我理解,理想情况下,这些行首先会从geography
操作中排除,但令人惊讶的是,这并不是那么简单。最简单的方法是允许geography
操作继续进行,然后丢弃其结果。
要真正阻止它被执行,您需要弄清楚如何让LINQ查询发出CASE WHEN
子句。