[英]Linq OrderBy calculation of properties (with join)
I have two database tables that map to models in my MVC app: 我有两个数据库表映射到我的MVC应用程序中的模型:
public class BuildingLocation
{
public int id { get; set; }
public double Lat { get; set; }
public double Lng { get; set; }
}
public class Building
{
public int id { get; set; }
public string title { get; set; }
//OTHER STUFF
}
Using Linq / Entities, I'm trying to get a list of Buildings, ordered by distance from a given point on a map. 使用Linq / Entities,我正在尝试获取建筑物列表,按照距地图上给定点的距离排序。
DefaultConnection db = new DefaultConnection();
public IEnumerable<dynamic> GetBuildings(double north, double south, double east, double west)
{
double centreX = (east - west) / 2;
double centreY = (north - south) / 2;
var query = from b in db.Building
join l in db.BuildingLocation on
b.id equals l.id
select new {b.id, b.title, l.Lat, l.Lng,
dist = Math.Sqrt(((centreX - l.Lat) * (centreX - l.Lat)) + ((centreY - l.Lng) * (centreY - l.Lng)))
};
query = query.Where(l => l.Lat > west);
query = query.Where(l => l.Lat < east);
query = query.Where(l => l.Lng > south);
query = query.Where(l => l.Lng < north);
query = query.OrderBy(c => c.dist);
return query.AsEnumerable();
}
So, obviously this doesn't work at all. 所以,显然这根本不起作用。 I've never used Linq before.
我以前从未使用过Linq。 How can I set the OrderBy based on a calculation?
如何根据计算设置OrderBy?
Try this : 尝试这个 :
public IEnumerable<dynamic> GetBuildings(double north, double south, double east, double west)
{
double centreX = (east - west) / 2;
double centreY = (north - south) / 2;
var query = db.Building.Join(db.BuildingLocation.Where(l=>
l.Lat > west && l.Lat < east
&& l.Lng > south && l.Lng < north),
b => b.id , l => l.id,
(b,l) => new {
ID = b.id,
Title = b.title,
Lat = l.lat,
Lng = l.Lng,
dist = Math.Sqrt(((centreX - l.Lat) * (centreX - l.Lat)) + ((centreY - l.Lng) * (centreY - l.Lng)))
}).OrderBy(Q=>Q.dist);
return query;
}
Above query is written in lambda expression. 上面的查询是用lambda表达式编写的。 If you want this in query expression use below code :
如果您想在查询表达式中使用以下代码:
var query = from result in (from b in db.Building
join l in db.BuildingLocation on
b.id equals l.id
where l.Lat > west && l.Lat < east && l.Lng > south && l.Lng < north
select new {b.id, b.title, l.Lat, l.Lng,
dist = Math.Sqrt(((centreX - l.Lat) * (centreX - l.Lat)) + ((centreY - l.Lng) * (centreY - l.Lng))) })
order by result.dist select result;
This will fix your issue. 这将解决您的问题。
If you use Entity framework you probably got the following exception message: 如果您使用Entity框架,您可能会收到以下异常消息:
"LINQ to Entities does not recognize the method 'Double Sqrt(Double)' method, and this method cannot be translated into a store expression." “LINQ to Entities无法识别方法'Double Sqrt(Double)'方法,并且此方法无法转换为商店表达式。”
So i would solve this in two steps, the inner query should only get data from tables, and in the outer (now in-memory query) will do the distance calculation and ordering: 所以我将分两步解决这个问题,内部查询应该只从表中获取数据,而在外部(现在是内存中查询)将进行距离计算和排序:
double centreX = (east - west) / 2;
double centreY = (north - south) / 2;
var query = (from result in
((from b in db.Building
join l in db.BuildingLocation on b.id equals l.id
where l.Lat > west && l.Lat < east && l.Lng > south && l.Lng < north
select new { b.id, b.title, l.Lat, l.Lng }).AsEnumerable()
)
select new
{
id = result.id,
title = result.title,
Lat = result.Lat,
Lng = result.Lng,
dist = Math.Sqrt(((centreX - l.Lat) * (centreX - l.Lat)) + ((centreY - l.Lng) * (centreY - l.Lng)))
}).OrderBy(e => e.dist);
Off the top of my hat, and just for the buildings, I'd do something like this: 在我的帽子顶部,只是为了建筑物,我会做这样的事情:
public IEnumerable<Building> GetBuildings(double north, double south, double east, double west)
{
double centreX = (east - west) / 2;
double centreY = (north - south) / 2;
db.BuildingLocation.Where(l => l.Lat > west && l.Lat < east && l.Lng > south && l.Lng < north)
.Join(
db.Building,
b => b.id,
l => l.id,
(l, b) => new {Building = b, l.Lat, l.Lng })
.AsEnumerable()
.OrderBy(l => Math.Sqrt(((centreX - l.Lat) * (centreX - l.Lat)) + ((centreY - l.Lng) * (centreY - l.Lng))))
.Select(l => l.Building)
}
I'm assuming it doesn't work because the distance calculation can't be translated to SQL, so I've inserted the AsEnumerable call before the OrderBy -- that means the filtering happens on the database side, but the ordering happens in-memory with Linq to Objects. 我假设它不起作用因为距离计算无法转换为SQL,所以我在OrderBy之前插入了AsEnumerable调用 - 这意味着过滤发生在数据库端,但是顺序发生在 - Linq到Objects的内存。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.