当前位置: 移动技术网 > IT编程>开发语言>.net > entity framework 实现按照距离排序

entity framework 实现按照距离排序

2018年11月01日  | 移动技术网IT编程  | 我要评论

竹塑,长春客车时刻表,下下片

在做项目时,经常会遇到“离我最近”这种需求。顾名思义,它需要根据用户的经纬度和事物的经纬度计算距离,然后进行排序,最后分页(当然这些操作要在数据库中进行,否则就变成假分页了)。

我们通常可以用sql语句来实现

select
    es_name,
    es_lon,
    es_lat,
    round(
        6378.138 * 2 * asin(
            sqrt(
                pow(
                    sin(
                        (
                            30.611842 * pi() / 180 - es_lat * pi() / 180
                        ) / 2
                    ),
                    2
                ) + cos(30.611842 * pi() / 180) * cos(es_lat * pi() / 180) * pow(
                    sin(
                        (
                            104.074666 * pi() / 180 - es_lon * pi() / 180
                        ) / 2
                    ),
                    2
                )
            )
        ) * 1000
    ) as distance_um
from
    c_ershuai
order by
    distance_um asc

但是我比较习惯使用 entity framework,于是我就想着能不能用 entity framework 实现按照距离排序。

 

以下是我采用的方案

首先定义一个接口,用来表示具有经纬度信息的实体。

    /// <summary>
    /// 具有经纬度
    /// </summary>
    public interface ihaslngandlat
    {
        /// <summary>
        /// 经度
        /// </summary>
        double lng { get; set; }
        /// <summary>
        /// 纬度
        /// </summary>
        double lat { get; set; }
    }

然后创建泛型类,用来包装计算的距离。

    /// <summary>
    /// 带距离的数据
    /// </summary>
    /// <typeparam name="tentity"></typeparam>
    public class datawithdistance<tentity>
    {
        /// <summary>
        /// 距离(km)
        /// </summary>
        public double distance { get; set; }
        /// <summary>
        /// 实体数据
        /// </summary>
        public tentity entity { get; set; }
    }

最后编写根据距离排序的扩展方法

注意:这个方法是采用的 sqlfunctions 类,所以仅支持sqlserver数据库,如果是其它数据库,需要将 sqlfunctions 更换成对应的类

    /// <summary>
    /// iqueryable扩展类
    /// </summary>
    public static class queryableextension
    {
        /// <summary>
        /// 根据距离排序
        /// </summary>
        /// <typeparam name="tentity"></typeparam>
        /// <param name="queryable"></param>
        /// <param name="lng">经度</param>
        /// <param name="lat">纬度</param>
        /// <returns></returns>
        public static iqueryable<datawithdistance<tentity>> orderbydistance<tentity>(this iqueryable<tentity> queryable, double lng, double lat) where tentity : class, ihaslngandlat
        {
            var rtn = from q in queryable
                      let radlat1 = lat * math.pi / 180.0
                      let radlat2 = q.lat * math.pi / 180.0
                      let a = radlat1 - radlat2
                      let b = lng * math.pi / 180.0 - q.lng * math.pi / 180.0
                      let s = 2 * sqlfunctions.asin(sqlfunctions.squareroot(math.pow((double)sqlfunctions.sin(a / 2), 2) +
               sqlfunctions.cos(radlat1) * sqlfunctions.cos(radlat2) * math.pow((double)sqlfunctions.sin(b / 2), 2))) * 6378.137
                      let d = math.round((double)s * 10000) / 10000
                      orderby d
                      select new datawithdistance<tentity> { entity = q, distance = d };

            return rtn;
        }
    }

以上就完成了 entity framework 按照距离排序的功能。

 

接下来我们用它来写一个小小的demo

首先创建一个商店实体类,具有经纬度字段,实现了  ihaslngandlat 接口。

    /// <summary>
    /// 商店实体
    /// </summary>
    public class shop : ihaslngandlat
    {
        /// <summary>
        /// 主键
        /// </summary>
        public int id { get; set; }
        /// <summary>
        /// 商店名称
        /// </summary>
        [required]
        [stringlength(64)]
        public string shopname { get; set; }
        /// <summary>
        /// 经度
        /// </summary>
        public double lng { get; set; }
        /// <summary>
        /// 纬度
        /// </summary>
        public double lat { get; set; }
    }

然后创建ef上下文类

    /// <summary>
    /// ef上下文
    /// </summary>
    public class demodbcontext : dbcontext
    {
        public demodbcontext()
            : base("name=demodbcontext")
        {
        }
        public virtual dbset<shop> shop { get; set; }
    }

最后我们分页查询商店,并按照距离由近到远排序

            #region 入参
            double user_lng = 113.46, user_lat = 22.27;  //用户经纬度
            int pageindex = 3; //当前页码
            int pagesize = 10; //每页条数
            #endregion

            using (demodbcontext context = new demodbcontext())
            {
                var queryable = context.shop.asnotracking().asqueryable();
                iqueryable<datawithdistance<shop>> sort_queryable = queryable.orderbydistance(user_lng, user_lat);  //按照用户的距离从近到远排序
                list<datawithdistance<shop>> data = sort_queryable.skip((pageindex - 1) * pagesize).take(pagesize).tolist();   //分页并执行sql查询获取数据

                //todo:将查到的数据映射成dto对象,并返回给客户端
            }

好了,entity framework 实现按照距离排序 也就全部完成了。

 

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网