【问题标题】:DataView.Sort - more than just asc/desc (need custom sort)DataView.Sort - 不仅仅是 asc/desc(需要自定义排序)
【发布时间】:2009-02-24 16:09:28
【问题描述】:

我有一个从数据集构建的报告。数据集使用 Sort 属性对数据进行排序。我知道我可以创建这样的排序表达式:

"field desc, field2 asc"

但我现在需要的是一种进行自定义排序的方法。在 SQL 中,我可以通过执行以下操作来执行自定义排序:

order by 
    case when field = 'Some Value' then 0 end
    case when field = 'Another Value' then 1 end

从根本上重新定义我的排序(即,一些值在另一个值之前)。

是否可以对 DataView 执行类似于排序表达式的操作?

【问题讨论】:

    标签: c# asp.net


    【解决方案1】:

    我喜欢 BFree 的回答,但我担心我的代码最终会更新克隆表而不是真实表的风险。 (如果您仅在 DataView 中使用扩展方法,我还没有仔细考虑过这是否真的是一个问题。)

    您可以在原始DataTable 上执行此操作,方法是向其添加计算得到的DataColumn(使用Expression 属性),然后对其值进行排序。

    在你的情况下,它会是这样的:

    DataColumn c = myTable.Columns.Add("Sort", typeof(int));
    c.Expression = "iif(field='SomeValue', 0, iif(field='AnotherValue', 1, 2))";
    

    首先排序SomeValue,其次是AnotherValue,然后是其他所有内容。

    【讨论】:

    • 您好,我需要这种解决方案。所以我所要做的就是单独使用这些代码行吗?如我错了请纠正我。另外,如果我要排序的列多于 2 列怎么办?例如,一列在每行“A”、“B”、“C”、“D”中都有这些值。我希望订单为 B、A、D、C。我如何使用您的应用程序来执行此操作?抱歉,我对.net 有点陌生。在这个上使用 VB
    • +1 当克隆数据表不是一种选择时,这是一个理想的解决方案,也不是任何类似的技术,如替换不同的数据视图。我发现散布在 StackOverflow 和 Internet 其余部分的几乎所有其他解决方案都涉及到原始数据的某种重复,这对于大型表来说可能很昂贵,并且可能导致插入/更新/删除等同步问题。我希望我能 +10 这个。 ;)
    【解决方案2】:

    好的,我只是快速完成了这个,并没有进行所有必要的错误处理和空值检查,但它应该给你一个想法并且应该足以让你开始:

    public static class DataTableExtensions
    {
        public static DataView ApplySort(this DataTable table, Comparison<DataRow> comparison)
        {
    
            DataTable clone = table.Clone();
            List<DataRow> rows = new List<DataRow>();
            foreach (DataRow row in table.Rows)
            {
                rows.Add(row);    
            }
    
            rows.Sort(comparison);
    
            foreach (DataRow row in rows)
            {
                clone.Rows.Add(row.ItemArray);
            }
    
            return clone.DefaultView;
        }
    
    
    }
    

    用法:

        DataTable table = new DataTable();
        table.Columns.Add("IntValue", typeof(int));
        table.Columns.Add("StringValue");
    
        table.Rows.Add(11, "Eleven");
        table.Rows.Add(14, "Fourteen");
        table.Rows.Add(10, "Ten");
        table.Rows.Add(12, "Twelve");
        table.Rows.Add(13, "Thirteen");
    

    //按StringValue排序:

     DataView sorted = table.ApplySort((r, r2) =>
            {
                return ((string)r["StringValue"]).CompareTo(((string)r2["StringValue"]));
            });
    

    结果:

    11 点 11

    14 十四

    10 十

    13 十三

    12 12

    //按IntValue排序:

    DataView sorted = table.ApplySort((r, r2) =>
                {
                    return ((int)r["IntValue"]).CompareTo(((int)r2["IntValue"]));
                });
    

    结果:

    10 十

    11 点 11

    13 十三

    12 12

    14 十四

    编辑:将其更改为扩展方法。

    现在在您的 Lambda 中(或者您可以创建一个完整的比较方法),您可以执行您需要的任何类型的自定义排序逻辑。请记住,-1 小于,0 等于,1 大于。

    【讨论】:

    • 很好的答案。只需要对双向排序和将视图绑定回网格进行一些调整。
    【解决方案3】:

    我知道这篇文章有点老,但我通过实现 IComparable 来解决这个问题。在这个例子中,我想按版本排序(格式为 0.0.0.0 作为字符串)。

    这是实现 IComparable 的版本控制类:

    public class Versioning : IComparable {
        string _version;
    
        int _major;
        public int Major { 
            get { return (_major); } 
            set { _major = value; } 
        }
    
        int _minor;
        public int Minor {
            get { return (_minor); }
            set { _minor = value; }
        }
    
        int _beta;
        public int Beta {
            get { return (_beta); }
            set { _beta = value; }
        }
    
        int _alpha;
        public int Alpha {
            get { return (_alpha); }
            set { _alpha = value; }
        }
    
        public Versioning(string version) {
            _version = version;
    
            var splitVersion = SplitVersion();
            if (splitVersion.Length < 4) {
                Major = Minor = Beta = Alpha = 0;
            }
    
            if (!int.TryParse(splitVersion[0], out _major)) _major = 0;
            if (!int.TryParse(splitVersion[1], out _minor)) _minor = 0;
            if (!int.TryParse(splitVersion[2], out _beta)) _beta = 0;
            if (!int.TryParse(splitVersion[3], out _alpha)) _alpha = 0;
        }
    
        string[] SplitVersion() {
            return (_version.Split('.'));
        }
    
        int GetCompareTo(Versioning versioning) {
            var greater = -1;
            var equal = 0;
            var less = 1;
    
            if (Major > versioning.Major) return (greater);
            if (Major < versioning.Major) return (less);
            if (Minor > versioning.Minor) return (greater);
            if (Minor < versioning.Minor) return (less);
            if (Beta > versioning.Beta) return (greater);
            if (Beta < versioning.Beta) return (less);
            if (Alpha > versioning.Alpha) return (greater);
            if (Alpha < versioning.Alpha) return (less);
    
            return (equal);
        }
    
        public int CompareTo(Versioning versioning) {
            return (GetCompareTo(versioning));
        }
    
        public override string ToString() {
            return (_version);
        }
    
        public int CompareTo(object obj) {
            if (obj == null) return (1);
            return (GetCompareTo((Versioning)obj));
        }
    }
    

    当您将列添加到表中时,不是将 Version 添加为字符串,而是将其添加为 Versioning 类:

    _table.Columns.Add("Version", typeof(Versioning));
    _view = new View(_table);
    

    然后正常排序:

    _view.Sort = "Version";
    

    【讨论】:

      【解决方案4】:

      我不这么认为。但是,您可以更改 SQL 以返回作为案例语句结果的“CustomSort”列:

      select
          (case when f = 'a' then 0 else 1 end) as CustomSort
      from MyTable
      

      【讨论】:

      • 这是一个可能的解决方案;希望我不必使用它,因为这意味着要编辑大约 20 多个报告的 SQL。
      【解决方案5】:

      您可以使用 if 或 switch 语句来获得与 select case 语句类似的功能:

                  if (Something == "1")
                      MyView.Sort = "Field1 ASC";
                  else
                      MyView.Sort = "Field2 ASC";
      

                  switch (MyProperty)
                  {
                      case 1:
                          MyView.Sort = "Field1 ASC";
                          break;
                      case 2:
                          MyView.Sort = "Field2 ASC";
                          break;
                      default:
                          MyView.Sort = "Field3 ASC";
                          break;
                  }
      

      【讨论】:

        【解决方案6】:

        如果你的上下文允许 (.NET 4+),你可以简单地使用这样的东西:

        DataView orderedDataTableView = sourceDataTable.AsEnumerable()
                                                       .OrderByDescending(row => !string.IsNullOrWhiteSpace(row.Field<string>("COLUMN_NAME")))
                                                       .ThenBy(row => row.Field<string>("COLUMN_NAME"))
                                                       .AsDataView();
        

        在此示例中,null 值放置在表的末尾(请注意,空格和空格字符串将具有相同的排名),然后按升序对请求的列进行排序。

        【讨论】:

          猜你喜欢
          • 2017-12-17
          • 1970-01-01
          • 1970-01-01
          • 2015-11-26
          • 1970-01-01
          • 2015-03-05
          • 2017-10-27
          • 2014-07-11
          相关资源
          最近更新 更多