Web Api 2 - 转换值并合并子查询中的值

Web Api 2 - 转换值并合并子查询中的值

问题描述:

在使用EF的Web API 2项目中,我试图让控制器返回数据库中的项目列表。这很简单。 问题来了,当我想要它返回一个单一的坐标值,从一个函数计算,下面,根据位置列表。 所有方法都会根据地理位置值列表计算中心点。该方法按预期工作。什么不起作用,是控制器的行为。Web Api 2 - 转换值并合并子查询中的值

  1. 运行下面的代码,导致

    “LINQ实体不 识别方法‘双ToDouble(System.String)’方法,和 这种方法不能被翻译成存储表达。'

  2. 我目前使用的item.Locations.FirstOrDefault().cX,我知道它不会工作,因为它总是会返回相同的值。但是 item.cX不起作用。那么,我应该如何使用我的陈述 按预期工作?

代码

IdentityModel:

public System.Data.Entity.DbSet<myModel.Item> Items { get; set; } 

型号:

public class Item 
{ 
    public int Id { get; set; } 
     public string Title { get; set; } 
    public virtual ICollection<Location> Locations { get; set; } 
} 

public class ItemDTO 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public IEnumerable<GeoCoordinate> Coordinates { get; set; } 
} 

public class Location 
{ 
    public int Id { get; set; } 
    public string cX { get; set; } 
    public string cY { get; set; } 
    public virtual Item Item { get; set; } 
} 

控制器:

[EnableQuery()] 
    public IQueryable<GeoCoordinate> GetList() 
    { 
     var items = db.Items 
      .Select(item => new ItemDTO() 
      { 
       Id = item.Id, 
     Title = item.Title 
       Coordinates = item.Locations 
        .Select(LocationsItem => new GeoCoordinate() //System.Device.Location 
        { 
         Latitude = Convert.ToDouble(item.Locations.FirstOrDefault().cX), 
         Longitude = Convert.ToDouble(item.Locations.FirstOrDefault().cY) 
        }) 
        .ToList() 
      }) 
      .AsEnumerable() 
      .Select(fetchedItem => GetCentralGeoCoordinate(fetchedItem.Coordinates)); 

     return items.AsQueryable(); 
    } 

GetCentralGeoCoordinate功能:

public static GeoCoordinate GetCentralGeoCoordinate(IEnumerable<GeoCoordinate> geoCoordinates) 
    { 
     if (geoCoordinates.Count() == 1) 
     { 
      return geoCoordinates.Single(); 
     } 

     double x = 0; 
     double y = 0; 
     double z = 0; 

     foreach (var geoCoordinate in geoCoordinates) 
     { 
      var latitude = geoCoordinate.Latitude * Math.PI/180; 
      var longitude = geoCoordinate.Longitude * Math.PI/180; 

      x += Math.Cos(latitude) * Math.Cos(longitude); 
      y += Math.Cos(latitude) * Math.Sin(longitude); 
      z += Math.Sin(latitude); 
     } 

     var total = geoCoordinates.Count(); 

     x = x/total; 
     y = y/total; 
     z = z/total; 

     var centralLongitude = Math.Atan2(y, x); 
     var centralSquareRoot = Math.Sqrt(x * x + y * y); 
     var centralLatitude = Math.Atan2(z, centralSquareRoot); 

     return new GeoCoordinate(centralLatitude * 180/Math.PI, centralLongitude * 180/Math.PI); 
    } 
+0

你试过double.Parse(item.Locations.FirstOrDefault()CX),而不是Convert.Double(item.Locations.FirstOrDefault ().CX)? –

+0

ToDouble无法转换为SQL - EF会尝试将整个IQueryable部分转换为一个SQL查询;那么它就会失败,因为在SQL中转换是不可能的。你将不得不使用db.Items.ToList()...来完成这个任务。 – DevilSuichiro

+0

@ChrisBartlett是的,同样的结果。 – brother

尝试是这样的:

public IQueryable<GeoCoordinate> GetList() 
{ 
    // this ToList fetches the data from the db. 
    // now you don't have to worry about convert inside EF 
    var sourceItems = db.Items.Include(x => x.Locations).ToList(); 

    // Select updated to answer part 2 (I believe). 
    var items = sourceItems.Select(item => new ItemDTO() 
     { 
      Id = item.Id, 
      Title = item.Title 
      Coordinates = item.Locations 
       .Select(itemLocation => new GeoCoordinate() 
       { 
        Latitude = Convert.ToDouble(itemLocation.cX), 
        Longitude = Convert.ToDouble(itemLocation.cY) 
       }) 
     }) 
     .AsEnumerable() 
     .Select(fetchedItem => GetCentralGeoCoordinate(fetchedItem.Coordinates)); 

    return items.AsQueryable(); 
}