DataTable - 如何实现datacolumn表达式(计算列)持久性?

时间:2014-06-18 13:22:24

标签: c# datatable expression calculated-columns datacolumn

我有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或其他什么。

4 个答案:

答案 0 :(得分:2)

试试这个方法:

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

答案 1 :(得分:1)

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

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

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

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

答案 2 :(得分:0)

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

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

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

示例:

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

答案 3 :(得分:-1)

查看此代码:

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

它符合您的要求。