Linq OrderBy属性计算(带连接)

时间:2012-08-29 16:27:50

标签: c# asp.net-mvc asp.net-mvc-3 linq

我有两个数据库表映射到我的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
}

使用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();
       }

所以,显然这根本不起作用。我之前从未使用过Linq。如何根据计算设置OrderBy?

3 个答案:

答案 0 :(得分:1)

试试这个:

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;
}

上面的查询是用lambda表达式编写的。如果您想在查询表达式中使用此代码,请使用以下代码:

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;

这将解决您的问题。

答案 1 :(得分:1)

如果您使用Entity框架,您可能会收到以下异常消息:

“LINQ to Entities无法识别方法'Double Sqrt(Double)'方法,并且此方法无法转换为商店表达式。”

所以我会分两步解决这个问题,内部查询应该只从表中获取数据,而在外部(现在是内存中查询)将进行距离计算和排序:

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); 

答案 2 :(得分:0)

离开我的帽子,只为了建筑物,我会做这样的事情:

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)
}

我假设它不起作用,因为距离计算无法转换为SQL,所以我在OrderBy之前插入了A​​sEnumerable调用 - 这意味着过滤发生在数据库端,但是顺序使用Linq to Objects在内存中发生。