• entity framework 实现按照距离排序[转]


    原文地址: https://www.cnblogs.com/hucheng/p/9885573.html

    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
                        ),
                    ) + COS(30.611842 * PI() / 180) * COS(es_lat * PI() / 180) * POW(
                        SIN(
                            (
                                104.074666 * PI() / 180 - es_lon * PI() / 180
                            ) / 2
                        ),
                    )
                )
            ) * 1000
        ) AS distance_um
    FROM
        c_ershuai
    ORDER BY
        distance_um ASC

    以下是我采用的方案

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

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

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

    double user_lng = 113.46, user_lat = 22.27;  //用户经纬度
    int pageIndex = 3; //当前页码
    int pageSize = 10; //每页条数
    
    
    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 实现按照距离排序 也就全部完成了。

  • 相关阅读:
    观《逻辑思维,如何成为一个高手》
    第十八周 最后冲刺
    第十六周 个人项目开发流程
    个人作业
    第十四周个人总结
    排球比赛计分程序功能说明书
    Spring实战(1)
    java基础知识(三)
    JAVA中框架总结
    java基础知识(一)
  • 原文地址:https://www.cnblogs.com/adinet/p/12110954.html
Copyright © 2020-2023  润新知