“其中xxx不为空且xxx / 2< 4”:“is not null”似乎在我的操作后执行

时间:2015-03-04 20:48:51

标签: c# sql-server linq entity-framework-6

这是我的实体框架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。

1 个答案:

答案 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子句。