2012-08-31 63 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); 
相關問題