Как изменить тип данных DataColumn в DataTable? - PullRequest
106 голосов
/ 27 января 2012

У меня есть:

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];

Что я хочу сделать, это:

Предположим, в настоящее время column.DataType.Name is "Double«.Я хочу, чтобы он стал "Int32" .

Как мне этого добиться?

Ответы [ 10 ]

249 голосов
/ 27 января 2012

Нельзя изменить тип данных после того, как таблица данных заполнена данными.Однако вы можете клонировать таблицу данных, изменить тип столбца и загрузить данные из предыдущей таблицы данных в клонированную таблицу, как показано ниже.

DataTable dtCloned = dt.Clone();
dtCloned.Columns[0].DataType = typeof(Int32);
foreach (DataRow row in dt.Rows) 
{
    dtCloned.ImportRow(row);
}
26 голосов
/ 27 января 2012

Хотя верно, что вы не можете изменить тип столбца после заполнения DataTable, вы можете изменить его после вызова FillSchema, но до вызова Fill. Например, скажем, 3-й столбец - это тот, который вы хотите преобразовать из double в Int32, вы можете использовать:

adapter.FillSchema(table, SchemaType.Source);
table.Columns[2].DataType = typeof (Int32);
adapter.Fill(table);
13 голосов
/ 21 июня 2017

Старая запись, но я подумал, что мне нужно взвесить расширение 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));

Конечно, используя любой тип, который вы пожелаете, при условии, что каждое значение в столбце действительно может быть преобразовано в новый тип.

8 голосов
/ 16 февраля 2016

Я выбрал немного другой подход. Мне нужно было проанализировать дату и время импорта из Excel в формате даты OA. Эта методология достаточно проста для построения из ... по сути,

  1. Добавить желаемый столбец типа
  2. Копирование строк, преобразовывающих значение
  3. Удалить исходный столбец и переименовать в новый, чтобы соответствовать старому

    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;
        }
    
8 голосов
/ 28 августа 2014
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)
8 голосов
/ 02 июля 2013

Также рассмотрите возможность изменения типа возвращаемого значения:

select cast(columnName as int) columnName from table
4 голосов
/ 27 января 2012

После заполнения DataTable тип столбца изменить нельзя.

В этом случае лучше всего добавить столбец Int32 в DataTable перед его заполнением:

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

Затем вы можете клонировать данные из исходной таблицы в новую таблицу:

DataTable dataTableClone = dataTable.Clone();

Вот сообщение с более подробной информацией .

3 голосов
/ 21 сентября 2015

если вы хотите изменить только столбец. Например, с строки на int32, вы можете использовать выражение.

DataColumn col = new DataColumn("col_int" , typeof(int));
table.columns.Add(col)
col.Expression = "table_exist_col_string"; // digit string convert to int  
2 голосов
/ 13 октября 2016

Я создал функцию расширения, которая позволяет изменять тип столбца 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;  
    });
}

Приведенный выше код заменяет все десятичные столбцы на двойные.

0 голосов
/ 08 июня 2017
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" );
...