【问题标题】:DataTable - how to achieve datacolumn expression (computed column) persistence?DataTable——如何实现datacolumn表达式(计算列)持久化?
【发布时间】:2014-06-18 13:22:24
【问题描述】:

我有这个DataTable

FName LName Tag1 Tag2 Tag3 ... (not fixed, can be as many)

我想要的是

FName LName TagAll

所以,我创建了一个TagAll 类型的列string,表达式为

var expression = string.Empty;
// ... other code
// In a loop for all tag columns
expression = expression + " + ',' + " + tagColumn;
// at the end of loop
 dtContact.Columns["Tag_All"].Expression = expression;

所以,如果我有 3 列,表达式是这样的

"Tag1 + ',' + Tag2 + ',' + Tag3"

例如数据是

FName LName    Tag1    Tag2    Tag3
Jeff  Atwood   test    tag     other
Matt  breeden  myTag   total   last

生成的DataTable变成这样

FName LName    Tag1    Tag2    Tag3   Tag_All
Jeff  Atwood   test    tag     other  test, tag, other 
Matt  breeden  myTag   total   last   myTag, total, last

到目前为止还不错,但现在我想删除所有其他 Tag(s) 列。我试过做

dtContact.Columns.RemoveAt(2) 但它会抛出 'System.ArgumentException'

我猜这是因为在计算列表达式中使用了该列,对吗?因为当我删除第 0 列或第 1 列时,它工作正常。那么,有没有一种方法可以删除所有这些其他 Tag(s) 列,因为它们用于计算列表达式?可能以某种方式使该列持久化?虽然我在 Google 上搜索过,但找不到任何东西。

另外,就像我说的那样,Tag(s) 列中只有 2 个、3 个或 n 个是不固定的,它们是动态的,最多只能有 1 个 Tag1。 .. 说Tag88 或其他。

【问题讨论】:

    标签: c# datatable expression calculated-columns datacolumn


    【解决方案1】:

    试试这个方法:

    //Usage
    DataTable dtMod = GetModifiedTable( dt);
    
    //Function to return modified data table
    public DataTable GetModifiedTable(DataTable dt)
    {
        var columnList = dt.Columns.Cast<DataColumn>()
                                     .Where(x => x.ColumnName.StartsWith("Tag"))
                                     .Select(x => x.ColumnName)
                                     .ToArray();
    
        DataTable dtNew = new DataTable();
        dtNew.Columns.Add("FName");
        dtNew.Columns.Add("LName");
        dtNew.Columns.Add("Tag_All");
    
        var results  = dt.AsEnumerable().Select(r => 
                           dtNew.LoadDataRow( 
                             new object[] { 
                                    r.Field<string>("FName"),
                                    r.Field<string>("LName"),
                                    GetTagValues(r, columnList)
    
                                  }, false
                            ));
    
        dtNew.Rows.Add(results.ToArray());
    
        return dtNew;
    }
    
    //Function to return csv values of given column list
    public string GetTagValues(DataRow r, string[] columns )
    {
        string csv = string.Empty;
        foreach(string column in columns)
        {
            csv += r[column].ToString() + ",";
        }
        return csv.Substring(0, csv.Length - 1);
    }
    

    【讨论】:

      【解决方案2】:

      你不能这样做。你必须采取另一种方法。

      添加 TAG_ALL 列,但不作为计算列。对于 DataTable 中的每一行,遍历所有 TagX 列,将它们相加,然后将值分配给 Tag_All 列。对每一行重复。完成后,您现在可以删除 TagX 列。

      根据行数,这实际上可能非常快。

      但是,我会质疑这是否是个好主意。如果您要将 DataTable 数据绑定到某个网格,那么您只需要不绑定 TagX 列,或者告诉 Grid 使这些列不可见。

      【讨论】:

        【解决方案3】:

        在处理数据表中的大量数据(大约 500000 行)时,循环遍历行需要时间(即使使用 dt.AsEnumerable().Select() 方法)。在找到以下解决方法之前,我一直在寻找一种更快的方法:

        1. 将数据表(仅结构)克隆到新表中
        2. 遍历列并删除表达式(设置为“”),或者只删除特定Datacolumn 的表达式
        3. 将新数据表与旧数据表合并。

        现在您可以删除原始列而不影响计算列。

        例子:

        //assign expression
        var expression = string.Empty;
        expression = expression + " + ',' + " + tagColumn;
        dtContact.Columns["Tag_All"].Expression = expression;
        
        //Clone datatable structure
        DataTable dtNew = dtContact.Clone();
        
        //Remove expression from a specific column
        dtNew.Columns["Tag_All"].Expression = "";
        
        //Merge data with the new Table
        dtNew.Merge(dtContact);
        dtContact.Dispose();
        
        //Now you can remove the column used within the expression
        dtNew.Columns.RemoveAt(2);
        

        【讨论】:

          【解决方案4】:

          查看此代码:

          private void creatable()
          {
             dt.Columns.Add("FName");
             dt.Columns.Add("LName");
             dt.Columns.Add("Tag1");
             dt.Columns.Add("Tag2");
             dt.Columns.Add("Tag3");
             dt.Columns.Add("Tag_All");
          }
          private void removeColumn()
          {
                  string temp = null;
                  List<string> colToRemove = new List<string>();
                  int colcount = dt.Columns.Count;
                  for (int i = 0; i <colcount ;i++ )
                  {
                      temp = dt.Columns[i].ColumnName;
                      if (temp == "Tag1" || temp == "Tag2" || temp == "Tag3")
                      {
                          colToRemove.Add(temp);
                      }
                      temp = null;
          
                  }
                  foreach (string item in colToRemove)
                  {
                      dt.Columns.Remove(item);
                  }
              }
          

          它正在按照您的要求工作。

          【讨论】:

          • 感谢您的回答,但我认为您没有阅读整个问题。我说我只有 2 或 3 列不是固定的,它可以是动态的。
          猜你喜欢
          • 2013-09-17
          • 1970-01-01
          • 2010-12-16
          • 2010-09-18
          • 1970-01-01
          • 1970-01-01
          • 2015-05-17
          • 2023-03-19
          • 2011-05-12
          相关资源
          最近更新 更多