当我尝试使用实体框架工作到达最近的地方时,在运行时出现了此错误
注意:我的sql数据库中的纬度和经度数据类型是float,我在实体模型中将其映射为double
public JsonResult GetNearstCity(double latitude,double longitude)
{
db.Configuration.ProxyCreationEnabled = false;
var coord = new GeoCoordinate(latitude, longitude);
var nearest = db.Cities.Select(x => new GeoCoordinate(x.Latitude,x.Longtiude))
.OrderBy(x => x.GetDistanceTo(coord))
.First();
return Json(nearest, JsonRequestBehavior.AllowGet);
}
'Only parameterless constructors and initializers are supported in LINQ to Entities.'
答案 0 :(得分:0)
EF希望将Linq表达式中的所有内容转换或跟踪到SQL。 SQL并不知道什么是GeoCoordinate对象,因此EF无法使用参数构造一个对象。您可以告诉EF使用默认构造函数构造一个对象,因为EF会从适用的表中请求字段,然后在执行查询后设置属性。
例如,这将起作用:
var nearest = db.Cities.Select(x => new GeoCoordinate
{
Latitude = x.Latitude,
Longitude = x.Longitude
});
这要求纬度和经度是GeoCoordinate上的公共属性。
您将面临的下一个问题是,您也将无法在linq表达式内调用GetDistanceTo(coord)
。同样,EF将无法将该方法发送给SQL,因为SQL将不知道该方法是什么。这里有两个选项:
选项1:如果数据量合理,则可以让EF对所有城市执行整体查询,然后从这一点开始处理Linq2Object,而不是Linq2EF,因此可以在GeoCoordinate上调用类函数:>
var nearest = db.Cities.Select(x => new GeoCoordinate
{
Latitude = x.Latitude,
Longitude = x.Longitude
}).ToList()
.OrderBy(x => x.GetDistanceTo(coord))
.First();
通过调用.ToList()
EF,我们将执行查询以返回所有城市。从那里,您可以使用类上的函数进行进一步的计算。这种方法的缺点是您会将所有城市加载到内存中。如果您有大量数据,这将对性能和资源造成不利影响。
选项2:将方法转换为SQL可以理解的内容。此选项使EF可以将您的计算转换为SQL可以执行的内容,这可以在DB端完成工作,然后仅返回所需的单个记录。您无需在GeoCoordinate实体上的方法中包含逻辑,而是在Linq表达式内进行计算。像这样:
var nearest = db.Cities.Select(x => new GeoCoordinate
{
Latitude = x.Latitude,
Longitude = x.Longitude
})
.OrderBy(x => Math.Abs(x.Latitude - coord.Latitude) + Math.Abs(x.Longitude - coord.Longitude))
.First();
这很可能不是您想要应用以找到最接近的2个点的公式,它只是一个类似公式的示例。 Math.Abs()
是一个.Net方法,但是EF确实知道如何将其转换为SQL。采取该实体中该GetDistanceTo(coord)
方法所具有的逻辑,并将其上移到Linq表达式中,您应该就在那里。
答案 1 :(得分:0)
错误正好说明了该错误:您需要创建一个具有无参数构造函数和属性的类GeoCoordinate,以设置纬度和经度:
class GeoCoordinate
{
public int Latitude {get; set;}
public int Longitude {get; set;}
... // other properties and methods
}
var result = dbContext.Cities
.Select(city => new GeoCoordinate
{
Latitude = city.Latitude,
Longitude = city.Longitude
})
.OrderBy(coordinate => coordinate.GetDistanceTo(coord))
.First();
顺便说一句,您的数据库管理系统不知道函数GetDistanceTo,因此,如果要让DBMS执行完整的查询(AsQueryable),请执行以下操作:
GeoCoordinate coord = new GeoCoordinate(latitude, longitude);
var result = dbContext.Cities
.Select(city => new
{
Latitude = city.Latitude,
Longitude = city.Longitude
Distance = sqrt (coord.Latitude * coord.Latitude + coord.Longitude * coord.Longitude),
})
.OrderBy(coordinates => coordinates.Distance)
.Select(coordinates => new GeoCoordinate
{
Latitude = coordinates.Latitude,
Longitude = coordinates.Longitude,
})
.FirstOrDefault();