如何更改 DataTable 中 DataColumn 的 DataType?

我有:

DataTable Table = new DataTable;
SqlConnection = new System.Data.SqlClient.SqlConnection("Data Source=" + ServerName + ";Initial Catalog=" + DatabaseName + ";Integrated Security=SSPI; Connect Timeout=120");


SqlDataAdapter adapter = new SqlDataAdapter("Select * from " + TableName, Connection);
adapter.FillSchema(Table, SchemaType.Source);
adapter.Fill(Table);


DataColumn column = DataTable.Columns[0];

我想做的是:

假设当前的 列。数据类型。名称“双倍”,我希望它变成 “ Int32”

我该怎么做呢?

383782 次浏览

一旦填充了 DataTable,就不能更改列的类型。

在这种情况下,您的最佳选择是在填充之前向 DataTable添加一个 Int32列:

dataTable = new DataTable("Contact");
dataColumn = new DataColumn("Id");
dataColumn.DataType = typeof(Int32);
dataTable.Columns.Add(dataColumn);

然后,您可以将原始表中的数据克隆到新表中:

DataTable dataTableClone = dataTable.Clone();

这是 更多细节

在用数据填充数据表之后,无法更改 DataType。但是,您可以克隆 Data 表、更改列类型并将数据从以前的数据表加载到克隆表,如下所示。

DataTable dtCloned = dt.Clone();
dtCloned.Columns[0].DataType = typeof(Int32);
foreach (DataRow row in dt.Rows)
{
dtCloned.ImportRow(row);
}

虽然确实不能在 DataTable被填充之后更改列的类型,但是可以在调用 FillSchema之后,但是在调用 Fill之前更改它。例如,假设第3列是要从 double转换为 Int32的列,您可以使用:

adapter.FillSchema(table, SchemaType.Source);
table.Columns[2].DataType = typeof (Int32);
adapter.Fill(table);

还可以考虑更改返回类型:

select cast(columnName as int) columnName from table
Dim tblReady1 As DataTable = tblReady.Clone()


'' convert all the columns type to String
For Each col As DataColumn In tblReady1.Columns
col.DataType = GetType(String)
Next


tblReady1.Load(tblReady.CreateDataReader)

如果只想将 column. (例如)从 string 更改为 int32,则可以使用 Expression 属性:

DataColumn col = new DataColumn("col_int" , typeof(int));
table.Columns.Add(col);
col.Expression = "table_exist_col_string"; // digit string convert to int

我采取了一种不同的方法。 我需要从一个 Excel 导入中解析 OA 日期格式的日期时间。这个方法非常简单,从本质上来说,

  1. 添加所需类型的列
  2. 遍历转换值的行
  3. 删除原始列并将其重命名为 new 以匹配旧列

    private void ChangeColumnType(System.Data.DataTable dt, string p, Type type){
    dt.Columns.Add(p + "_new", type);
    foreach (System.Data.DataRow dr in dt.Rows)
    {   // Will need switch Case for others if Date is not the only one.
    dr[p + "_new"] =DateTime.FromOADate(double.Parse(dr[p].ToString())); // dr[p].ToString();
    }
    dt.Columns.Remove(p);
    dt.Columns[p + "_new"].ColumnName = p;
    }
    

我创建了一个扩展函数,它允许更改 DataTable 的列类型。它没有克隆整个表并导入所有数据,而只是克隆列,解析值然后删除原始数据。

    /// <summary>
/// Changes the datatype of a column. More specifically it creates a new one and transfers the data to it
/// </summary>
/// <param name="column">The source column</param>
/// <param name="type">The target type</param>
/// <param name="parser">A lambda function for converting the value</param>
public static void ChangeType(this DataColumn column, Type type, Func<object, object> parser)
{
//no table? just switch the type
if (column.Table == null)
{
column.DataType = type;
return;
}


//clone our table
DataTable clonedtable = column.Table.Clone();


//get our cloned column
DataColumn clonedcolumn = clonedtable.Columns[column.ColumnName];


//remove from our cloned table
clonedtable.Columns.Remove(clonedcolumn);


//change the data type
clonedcolumn.DataType = type;


//change our name
clonedcolumn.ColumnName = Guid.NewGuid().ToString();


//add our cloned column
column.Table.Columns.Add(clonedcolumn);


//interpret our rows
foreach (DataRow drRow in column.Table.Rows)
{
drRow[clonedcolumn] = parser(drRow[column]);
}


//remove our original column
column.Table.Columns.Remove(column);


//change our name
clonedcolumn.ColumnName = column.ColumnName;
}
}

你可以这样使用它:

List<DataColumn> lsColumns = dtData.Columns
.Cast<DataColumn>()
.Where(i => i.DataType == typeof(decimal))
.ToList()


//loop through each of our decimal columns
foreach(DataColumn column in lsColumns)
{
//change to double
column.ChangeType(typeof(double),(value) =>
{
double output = 0;
double.TryParse(value.ToString(), out output);
return output;
});
}

以上代码将所有十进制列更改为双精度。

DataTable DT = ...
// Rename column to OLD:
DT.Columns["ID"].ColumnName = "ID_OLD";
// Add column with new type:
DT.Columns.Add( "ID", typeof(int) );
// copy data from old column to new column with new type:
foreach( DataRow DR in DT.Rows )
{ DR["ID"] = Convert.ToInt32( DR["ID_OLD"] ); }
// remove "OLD" column
DT.Columns.Remove( "ID_OLD" );

这是一篇老文章,但我想我应该参与进来,使用一个 DataTable 扩展,它可以一次将一个列转换为给定的类型:

public static class DataTableExt
{
public static void ConvertColumnType(this DataTable dt, string columnName, Type newType)
{
using (DataColumn dc = new DataColumn(columnName + "_new", newType))
{
// Add the new column which has the new type, and move it to the ordinal of the old column
int ordinal = dt.Columns[columnName].Ordinal;
dt.Columns.Add(dc);
dc.SetOrdinal(ordinal);


// Get and convert the values of the old column, and insert them into the new
foreach (DataRow dr in dt.Rows)
dr[dc.ColumnName] = Convert.ChangeType(dr[columnName], newType);


// Remove the old column
dt.Columns.Remove(columnName);


// Give the new column the old column's name
dc.ColumnName = columnName;
}
}
}

它可以这样称呼:

MyTable.ConvertColumnType("MyColumnName", typeof(int));

当然,只要列中的每个值实际上都可以转换为新类型,就可以使用所需的任何类型。

我将 Mark 的解决方案的效率(所以我是 不必 .Clone整个数据表)与泛型和可扩展性(所以是 我可以定义自己的转换函数)结合起来。这就是我最后得到的结果:

/// <summary>
///     Converts a column in a DataTable to another type using a user-defined converter function.
/// </summary>
/// <param name="dt">The source table.</param>
/// <param name="columnName">The name of the column to convert.</param>
/// <param name="valueConverter">Converter function that converts existing values to the new type.</param>
/// <typeparam name="TTargetType">The target column type.</typeparam>
public static void ConvertColumnTypeTo<TTargetType>(this DataTable dt, string columnName, Func<object, TTargetType> valueConverter)
{
var newType = typeof(TTargetType);


DataColumn dc = new DataColumn(columnName + "_new", newType);


// Add the new column which has the new type, and move it to the ordinal of the old column
int ordinal = dt.Columns[columnName].Ordinal;
dt.Columns.Add(dc);
dc.SetOrdinal(ordinal);


// Get and convert the values of the old column, and insert them into the new
foreach (DataRow dr in dt.Rows)
{
dr[dc.ColumnName] = valueConverter(dr[columnName]);
}


// Remove the old column
dt.Columns.Remove(columnName);


// Give the new column the old column's name
dc.ColumnName = columnName;
}

这样一来,使用就简单多了,而且还可以自定义:

DataTable someDt = CreateSomeDataTable();
// Assume ColumnName is an int column which we want to convert to a string one.
someDt.ConvertColumnTypeTo<string>('ColumnName', raw => raw.ToString());

你可以用不同类型的数据建立一个柱子,然后复制这些数据并删除前面的柱子

TB.Columns.Add("columna1", GetType(Integer))
TB.Select("id=id").ToList().ForEach(Sub(row) row("columna1") = row("columna2"))
TB.Columns.Remove("columna2")