基于对象的数据筛选与排序(二)
来源:互联网 发布:sql去除重复数据 编辑:程序博客网 时间:2024/06/04 19:35
OK,在上一篇中,我们从对象的角度将数据从传统的SQL数据库筛选模式转换了出来,这样做的好处在于如果数据量不是特别大的情况下,一次性的提取出数据缓存到缓存中,将数据的操作从数据库中脱离出来,利用对象在缓存的基础上操作,从而更高效率的处理数据。
上一节中,主要对数据的筛选做了分析与运用,当然,在大多数情况下,排序也是一个常用且重要的数据操作。
在对业务对象进行排序时,不能使用ObjectDataSource作为数据源,因为它只支持DataView、DataTable、DataSet的自动排序。当然,仍然可以对GridView进行Sorting处理,直接拼装SQL语句,利用“Order By”子句即可完成排序。
基本的数据库操作这里就不再举例,和进行数据筛选思路一样,我们同样可以将数据一次性抽到缓存中,后继的请求只针对缓存了的业务对象进行。本节将在上篇的基础上讨论如何对业务对象进行排序,包括简单排序和高级排序。
同样,我们这里先建立一个显示交互页面(由于ObjectDataSource的原因无法用之前的列子)。创建一个AgriDataSort.aspx文件,拖放一个Repeater控件,编写前端代码:
<asp:Repeater ID="rpAgriDataList" runat="server"> <HeaderTemplate> <table> <tr> <th> <asp:LinkButton runat="server" ID="lbtDataID">AgriDataID</asp:LinkButton> </th> <th> <asp:LinkButton runat="server" ID="lbtAgriDataTem">AgriDataTem</asp:LinkButton> </th> <th> <asp:LinkButton runat="server" ID="lbtAgriDataSun">AgriDataSun</asp:LinkButton> </th> <th> <asp:LinkButton runat="server" ID="lbtAgriDataEle">AgriDataEle</asp:LinkButton> </th> <th> <asp:LinkButton runat="server" ID="lbtAgriDataWater">AgriDataWater</asp:LinkButton> </th> <th> <asp:LinkButton runat="server" ID="lbtAgriDataBelong">AgriDataBelong</asp:LinkButton> </th> <th> <asp:LinkButton runat="server" ID="lbtAgriDataTime">AgriDataTime</asp:LinkButton> </th> </tr> </HeaderTemplate> <ItemTemplate> <tr> <td><%#Eval("ID") %></td> <td><%#Eval("Tem") %></td> <td><%#Eval("Sun") %></td> <td><%#Eval("Ele") %></td> <td><%#Eval("Water") %></td> <td><%#Eval("Belong") %></td> <td><%#Eval("Date") %></td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:Repeater>
显示效果如图:
接下来用相同的方法将要处理的数据放入到缓存中,我们在ObjAgriManager类下创建该方法(方便显示就提取前十五条数据):
public static List<AgriData> GetSortList() { List<AgriData> list = HttpContext.Current.Cache["SortList"] as List<AgriData>; if (list == null) { //获取前15条记录 list = SqlAgriDataManager.GetList("select Top (15) * from AgriData"); HttpContext.Current.Cache.Insert("SortList", list); } return list; }
基本的数据源得到之后,将它与页面链接起来,在AgriDataSort.aspx.cs的Page_Load事件下,将数据源绑定:
protected void Page_Load(object sender, EventArgs e){ List<AgriData> list = ObjAgriDataManager.GetSortList(); rpAgriDataList.DataSource = list; rpAgriDataList.DataBind();}
运行效果如下:
简单排序——IComarable接口的实现
接下来便进行简单的排序操作,利用集合自带的Sort方法即可,通常代码会这样编写:
List<AgriData> list = ObjAgriDataManager.GetSortList(); list.Sort(); rpAgriDataList.DataSource = list; rpAgriDataList.DataBind();
实际上这段代码是会报错的,原因很简单,没有实现IComparable< T>接口,从本质上讲,List< T>.Sort()的实现基础就是实现了IComparable< T>接口,而诸如int、char、string一类基础类型都是实现了该接口才能进行排序操作的。
IComparable< T>的定义很简单:
public interface IComparable<in T> { // 摘要: // 比较当前对象和同一类型的另一对象。 // // 参数: // other: // 与此对象进行比较的对象。 // // 返回结果: // 一个值,指示要比较的对象的相对顺序。 返回值的含义如下: 值 含义 小于零 此对象小于 other 参数。 零 此对象等于 other。 大于零 // 此对象大于 other。 int CompareTo(T other); }
详细的注释源码上已经很清楚了,根据返回额int型数值,来判断数据的先后位置。我们这里默认根据Tem的大小进行比较,因为在业务对象AgriData中Tem的类型为int,所以比较操作可以直接调用其CompareTo方法:
public class AgriData:IData,IComparable<AgriData> { //...略 int IComparable<AgriData>.CompareTo(AgriData other) { return this.Tem.CompareTo(other.Tem); } }
运行程序,效果如预期所致:
高级排序——IComparer接口的实现
很显然,在实际运用中,我们经常需要对多个列进行排序,同时还要考虑升序和降序,比如我们先对ID进行升序排列,再对Sun值进行降序排列,这种情况下CompareTo虽然也可以实现但需要对AgriData添加额外的属性。这些.Net Framework已经考虑到了,并提供IComparer< T>接口进行了排序规则。
public interface IComparer<in T> { // 摘要: // 比较两个对象并返回一个值,指示一个对象是小于、等于还是大于另一个对象。 // // 参数: // x: // 要比较的第一个对象。 // // y: // 要比较的第二个对象。 // // 返回结果: // 一个有符号整数,指示 x 与 y 的相对值,如下表所示。 值 含义 小于零 x 小于 y。 零 x 等于 y。 大于零 x 大于 y。 int Compare(T x, T y); }
IComparer< T>同样需要实现一个方法,Compare(),计算机制和CompareTo基本相同,不过需要注意的是,这个接口不是要求AgriData对象实现的,而是要求另一个对象实现它,比如AgriDataComparer,而在调用Sort方法时,再将它作为参数传递过去,由于这个AgriDataComparer只针对AgriData进行,所以将它作为嵌套类更为合适。
首先考虑到排序的规则(升降?对那一列进行升降?),这里同样可以定义2个内部枚举:
public enum SortDir { Ascending = 0, Descending } public enum SortField { ID, Tem, Ele, Sun, Water, Belong, Date }
为了方便将这两个规则做参数处理,我们将它设计为一个结构体:
//内部排序属性结构体 public struct Sorter { public SortDir dir; public SortField field; public Sorter(SortField field,SortDir dir) { this.dir = dir; this.field = field; } }
这个排序规则结构体就作为AgriDataComparer的内部的字段存储,当然,实际中一组排序规则不一定足够,所以最好封装成List< Sorter>存储给为合适:
public class AgriDataComparer : IComparer<AgriData> { //一组排序规则集合 private List<Sorter> list; } public AgriDataComparer(List<Sorter> list) { this.list = list; }
我们先从简单的单个属性的某种升降序入手,不考虑多个属性,我们来便写一个Compare方法体:
public int Compare(AgriData x, AgriData y, SortDir dir, SortField field) { int result = 0; switch (field) { case SortField.ID: if (dir == SortDir.Ascending) result = x.ID.CompareTo(y.ID); else result = y.ID.CompareTo(x.ID); break; case SortField.Tem: if (dir == SortDir.Ascending) result = x.Tem.CompareTo(y.Tem); else result = y.Tem.CompareTo(y.Tem); break; case SortField.Sun: if (dir == SortDir.Ascending) result = x.Sun.CompareTo(y.Sun); else result = y.Sun.CompareTo(x.Sun); break; case SortField.Ele: if (dir == SortDir.Ascending) result = x.Ele.CompareTo(y.Ele); else result = y.ID.CompareTo(x.Ele); break; case SortField.Water: if (dir == SortDir.Ascending) result = x.Water.CompareTo(y.Water); else result = y.ID.CompareTo(x.Water); break; case SortField.Belong: if (dir == SortDir.Ascending) result = x.Belong.CompareTo(y.Belong); else result = y.ID.CompareTo(x.Belong); break; case SortField.Date: if (dir == SortDir.Ascending) result = x.Date.CompareTo(y.Date); else result = y.ID.CompareTo(x.Date); break; }
通过传递的2个AgriData对象,和属性、升降序规则,对对象进行排序操作,不过,这个方法不能作为IComparer< T>的实现方法,因为IComparer< T>.Compare只接受两个参数传递,那么排序规则怎么去处理呢?多个排序规则又怎么处理呢?这个时候之前定义的List< Sorter>集合和之前的Compare就派上用场了,我们只要遍历List< Sorter>这个集合,每轮遍历对其中的排序规则调用之前定义的Compare方法处理即可,当两个值的某个属性相等时,触发下一组排序属性直到两个值不同为止:
//实现ICompare接口 int IComparer<AgriData>.Compare(AgriData x, AgriData y) { int result = 0; foreach (Sorter n in list) { result = Compare(x, y, n.dir, n.field); if (result != 0) break; } return result; }
哈哈,代码就是这么简单,这样就很好的解决了多组排序规则的处理。
为了方便Sort方法参数的传递,我们继续编写一组GetCompare方法做相关处理,首先我们看下按排序要求进行的Sort重载方法:
public void Sort(IComparer<T> comparer);
很显然,我们只要传递一个IComparer< T>类型的参数即可,为了方便调用,我们将GetCompare作为静态方法,并且返回类型为IComparer< T>,所以这组重载方法可以这样定义:
//单个指定排序 public static AgriDataComparer GetComparer(SortField field,SortDir dir) { Sorter sorter = new Sorter(field, dir); List<Sorter> list = new List<Sorter>(); list.Add(sorter); return new AgriDataComparer(list); } //单个默认排序——ID、升序 public static AgriDataComparer GetComparer() { List<Sorter> list = new List<Sorter>() { new Sorter(SortField.ID,SortDir.Ascending), }; return new AgriDataComparer(list); } //多个指定排序 public static AgriDataComparer GetComparer(List<Sorter> list) { return new AgriDataComparer(list); }
好的,我们在页面的后台进行测试:
protected void Page_Load(object sender, EventArgs e) { List<AgriData.Sorter> sorter = new List<AgriData.Sorter>() { //1级条件——光照度降序 new AgriData.Sorter(AgriData.SortField.Sun,AgriData.SortDir.Descending), //2级条件——湿度升序 new AgriData.Sorter(AgriData.SortField.Water,AgriData.SortDir.Ascending), }; List<AgriData> list = ObjAgriDataManager.GetSortList(); list.Sort(AgriData.AgriDataComparer.GetComparer(sorter)); rpAgriDataList.DataSource = list; rpAgriDataList.DataBind(); }
运行如图:
确实完成了我们的要求。
- 基于对象的数据筛选与排序(二)
- 基于对象的数据筛选与排序(一)
- “筛选”与数据透视表的筛选
- 基于内存缓冲区的流媒体数据缓存排序(二)
- C# DataView数据筛选与排序
- 基于ES的搜索+筛选+排序解决方案
- 数据集的筛选和排序
- 脱机数据的排序、搜索和筛选
- 【Python学习系列二十二】pandas数据筛选和排序
- pandas筛选排序数据
- 自动筛选的逻辑(7)-与数据透视表的筛选不同
- orderBy排序与筛选的例子
- Linq(筛选与排序)
- #研发解决方案介绍#基于ES的搜索+筛选+排序解决方案
- 研发解决方案介绍#基于ES的搜索+筛选+排序解决方案
- DataView的使用与筛选数据
- map 数据筛选和排序
- 关于数据排序筛选算法
- mysql事务隔离级别
- Linux常用命令汇总
- 【配置】Hadoop单节点集群搭建
- 【计算机系统组成】存储器知识要点
- class not found终结者
- 基于对象的数据筛选与排序(二)
- 第十二周LeetCode算法题三道
- 【Scikit-Learn 中文文档】内核岭回归
- [LeetCode] [C] 100. Same Tree
- 【CodeForces
- 在C# 中 textbox 文本的转换
- 栈的压入、弹出序列
- ndpi转换为wireshark的接口
- Ionic常用指令事件