2012-08-31 37 views
3

下面是我写的Linq to Entities Statement。LINQ to Entities无法识别该方法,并且此方法无法转换为商店表达式

public static List<Model.User> GetNearestUsers(int userid,int count,ref Model.HangoutDBEntities context) 
    { 
     Model.Location myLocation=GetCurrentLocation(userid,ref context); 

     return context.Locations.Where(o => EntityFunctions.DiffMinutes(DateTime.Now, o.DateTimeStamp) <= 30).OrderBy(o => Core.Location.Distance.CalculateDistance(myLocation.Latitude, myLocation.Longitude, o.Latitude, o.Longitude)).Select(o => o.User).ToList(); 
    } 

而这里的CalculateDistance方法

public static double CalculateDistance(decimal lat1,decimal lon1,decimal lat2,decimal lon2) 
    { 
     try 
     { 
      var R = 6371; // Radius of the earth in km 
      var dLat = DegreeToRadian((double)(lat2 - lat1)); // Javascript functions in radians 
      var dLon = DegreeToRadian((double)(lon2 - lon1)); 
      var a = Math.Sin(dLat/2) * Math.Sin(dLat/2) + 
        Math.Cos(DegreeToRadian((double)lat1)) * Math.Cos(DegreeToRadian((double)lat2)) * 
        Math.Sin(dLon/2) * Math.Sin(dLon/2); 
      var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); 
      var d = R * c; // Distance in km 

      return (double)d; 
     } 
     catch 
     { 
      return 0.0; 
     } 
    } 

    public static double DegreeToRadian(double angle) 
    { 
     return Math.PI * angle/180.0; 
    } 

请让我知道,如果有这方面的任何变通办法。我得到一个异常

LINQ到实体无法识别方法“双 CalculateDistance(System.Decimal,System.Decimal,System.Decimal, System.Decimal)”的方法,而这种方法不能被翻译成一个 存储表达式。

我知道自定义函数不适用于Linq 2实体,但我不知道这个解决方法。你能帮我解决吗? :)

+2

如果您正在使用sql-server,我强烈建议您查看使用空间数据类型而不是在内存中进行计算。问题是您的计算无法转换为SQL.http://msdn.microsoft.com/en-us/library/bb933876(v = sql.105).aspx – StuartLC

回答

3

将数据加载到一个列表,然后在列表

var origList = context.Locations.Where(o => EntityFunctions.DiffMinutes(DateTime.Now, o.DateTimeStamp) <= 30).ToList() 

var orderedList = origList.OrderBy(o => Core.Location.Distance.CalculateDistance(myLocation.Latitude, myLocation.Longitude, o.Latitude, o.Longitude)).Select(o => o.User).ToList(); 

或执行Caclulation;

context.Locations 
    .Where(o => EntityFunctions.DiffMinutes(DateTime.Now, o.DateTimeStamp) <= 30).ToList() 
     .OrderBy(o => Core.Location.Distance.CalculateDistance(myLocation.Latitude, myLocation.Longitude, o.Latitude, o.Longitude)) 
      .Select(o => o.User).ToList(); 

要注意的是在where子句之后的ToList。

在调用ToList(),将数据加载到内存中,并且排序成为LINQ的一个任务对象

0

我最近不得不解决这个问题。诀窍是使用System.Data.Entity.SqlServer的SqlFunctions而不是System.Math来处理大多数语句(Math.Pow除外)。

备用的LINQ风格(from/where/let/orderby等)很有用,因为let关键字允许您分解问题并保持可读性。

var closestLocation = await (
    from q in qryable 
    where q.LAT.HasValue && q.LONG.HasValue 
    // Convert derees to radians (pi/180 = 0.01745...) 
    let dbLatitudeRadians = q.LAT.Value * 0.0174532925199433 
    let dbLongitudeRadians = q.LONG.Value * 0.0174532925199433 
    let requestLatitudeRadians = requestLatitude * 0.0174532925199433 
    let requestLongitudeRadians = requestLongitude * 0.0174532925199433 
    let deltaLatitudeRadians = requestLatitudeRadians - dbLatitudeRadians 
    let deltaLongitudeRadians = requestLongitudeRadians - dbLongitudeRadians 
    let sinHalfLatitudeDistance = SqlFunctions.Sin(deltaLatitudeRadians/2) ?? 0.0 
    let sinHalfLongitudeDistance = SqlFunctions.Sin(deltaLongitudeRadians/2) ?? 0.0 
    let cosThisLatitude = SqlFunctions.Cos(dbLatitudeRadians) ?? 0.0 
    let cosThatLatitude = SqlFunctions.Cos(requestLatitudeRadians) ?? 0.0 
    let expr = Math.Pow(sinHalfLatitudeDistance, 2) + cosThisLatitude * cosThatLatitude * Math.Pow(sinHalfLongitudeDistance, 2) 
    let sqrtExpr = Math.Pow(expr, 0.5) 
    let sqrt1MinusExpr = Math.Pow(1 - expr, 0.5) 
    let distanceInMeters = 6376500 * 2 * SqlFunctions.Atan2(sqrtExpr, sqrt1MinusExpr) 
    orderby distanceInMeters 
    select q 
).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); 
相关问题