【问题标题】:Creating a DataTable by filtering another DataTable通过过滤另一个 DataTable 创建一个 DataTable
【发布时间】:2010-12-24 05:52:42
【问题描述】:

我正在开发一个系统,该系统当前有一个相当复杂的函数,该函数返回一个 DataTable,然后将其绑定到 ASP.NET WebForm 上的 GUI 控件。

我的问题是我需要过滤返回的数据——一些正在返回的数据不应该显示给用户。

我知道 DataTable.select(),但这并不是我真正需要的。首先,它返回一个 DataRows 数组,我需要一个 DataTable,所以我可以将它数据绑定到 GUI 控件。但更重要的是,我需要做的过滤并不是简单的表达方式。我有一个不想显示的元素数组,我需要将 DataTable 中的每个元素与该数组进行比较。

当然,我可以做的是创建一个新的 DataTable,从原始数据表中读取所有内容,将适当的内容添加到新数据表中,然后将新数据绑定到 GUI 控件。但这似乎是错误的,不知何故。在这种情况下,原始 DataTable 中的元素数量可能不够,将它们全部复制到内存中会造成太多麻烦,但我想知道是否还有其他方法。

.NET DataTable 是否具有允许我通过回调函数进行过滤的功能?

【问题讨论】:

    标签: .net datatable


    【解决方案1】:

    使用DataView.ToTable 方法:

    DataTable sourceTable = ...
    string filter = ...
    string sort = ...
    DataView view = new DataView(sourceTable, filter, sort, DataViewRowState.CurrentRows);
    DataTable newTable = view.ToTable();
    

    如果您不能将过滤逻辑放在过滤器表达式中,您可以求助于Linq to DataSet

    var query = from row in sourceTable.AsEnumerable()
                where row.Field<int>("foo") > 42
                && row.Field<string>("bar") == "hello"
                && ...
                select r;
    
    var newTable = query.AsDataView().ToTable();
    

    或者,如果您已经有实现过滤的方法:

    bool FilterRow(DataRow row)
    {
        ...
    }
    
    ...
    
    var newTable = sourceTable.AsEnumerable().Where(FilterRow).AsDataView().ToTable();
    

    【讨论】:

      【解决方案2】:

      如何将 GUI 控件绑定到满足您条件的 DataRows 列表?像这样:

      var lst = new List<DataRow>();
      foreach(DataRow dr in dt.Rows) {
        if (SatisfiesCondition(dr)) lst.Add(dr);
      }
      
      // in Linq dialect
      var lst = dt.AsEnumerable().Where(SatisfiesCondition).ToList();
      
      // here: bind control to list
      

      这样做,数据行不会被复制,但列表会保留对您需要的行的引用。

      【讨论】:

      • 在上面,你的 SatisfiesCondition 是一个任意函数,它接受一行并返回一个布尔值?
      • 是的。在你没有说明条件是什么的问题中,这样你可以抽象出决定一行是否合格的逻辑
      • 您正在构建一个包含对数据集中行的引用的列表 - 这意味着不需要复制行,它们只是被指向。但是所有的行都需要实例化,如果有很多行,那可能是个问题。 AIUI,DataTable 实际上不需要包含数据,它只是有一种机制来枚举它们,也许可以根据需要从数据库中检索它们。我理想的解决方案是在枚举行时进行过滤,而不是构建静态集。但是对于手头的问题,我真的不需要那个,所以你所拥有的就可以了。
      • 那么不要在 DataSet/DataTable/DataRow 模型上工作,因为所有这些对象都是为了在 ADO.Net 模型中断开连接使用,然后您应该使用某种 DataReader 加载机制。
      【解决方案3】:

      我不知道你说的回调函数是什么意思

      可能其他人会为此推荐LINQ。但是因为我还在用3.5 Framework,所以不太熟悉。

      您的数据表有多少行?使用 Datatable.Select 可能就足够了:

      Private Function SelectIntoDataTable(ByVal selectFilter As String, ByVal sourceDataTable As DataTable) As DataTable
          Dim newDataTable As DataTable = sourceDataTable.Clone
          Dim dataRows As DataRow() = sourceDataTable.Select(selectFilter)
          Dim typeDataRow As DataRow
      
          For Each typeDataRow In dataRows
              newDataTable.ImportRow(typeDataRow)
          Next
          Return newDataTable
      End Function
      

      您还可以使用 Dataview 作为第二个控件的源,并使用其 RowFilter 属性:

      DataView dv = new DataView( sourceDataTable );
      dv.RowFilter = selectFilter 
      GridView1.DataSource = dv
      

      您还可以使用 INNOT IN 语法按列表/数组来过滤 Select 和 RowFilter,例如:

      dv.RowFilter = "SomeID NOT IN(1,2,3)"
      

      【讨论】:

      • 回调函数是为每个输入行调用以确定它是否将包含在输出数据集中的函数。
      猜你喜欢
      • 2016-04-27
      • 1970-01-01
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多