web-dev-qa-db-fra.com

Comment changer le type de données d'un DataColumn dans un DataTable?

J'ai:

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

Ce que je veux faire c'est:

Supposons actuellement column.DataType.Name est "Double" . Je veux qu'il devienne "Int32" .

Comment puis-je y arriver?

107
rofans91

Vous ne pouvez pas modifier le type de données une fois que le datatable est rempli de données. Toutefois, vous pouvez cloner la table de données, modifier le type de colonne et charger les données de la table de données précédente dans la table clonée, comme indiqué ci-dessous.

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

S'il est vrai que vous ne pouvez pas modifier le type de la colonne après que la variable DataTable a été renseignée, vous pouvez le modifier après avoir appelé FillSchema, mais avant d'appeler Fill. Par exemple, supposons que la 3ème colonne soit celle que vous voulez convertir de double à Int32, vous pouvez utiliser:

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

Ancienne publication, mais je pensais que je me lancerais dans une extension DataTable capable de convertir une colonne à la fois en un type donné:

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

On peut alors l'appeler ainsi:

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

Bien entendu, vous pouvez utiliser le type de votre choix, à condition que chaque valeur de la colonne puisse être convertie dans le nouveau type.

14
Marc Ferrold
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
Superna Parajuli

Pensez également à modifier le type de retour:

select cast(columnName as int) columnName from table
8
tsilb

J'ai adopté une approche légèrement différente. Je devais analyser une date-heure à partir d'une importation Excel au format de date OA. Cette méthodologie est assez simple pour être construite à partir de ... essentiellement,

  1. Ajouter la colonne de type que vous voulez
  2. Déchirer les lignes en convertissant la valeur
  3. Supprimer la colonne d'origine et renommer la nouvelle pour qu'elle corresponde à l'ancienne

    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
John Salewski

si vous souhaitez modifier uniquement une colonne.Par exemple, de chaîne en int32, vous pouvez utiliser la propriété Expression:

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

Une fois qu'un DataTable a été rempli, vous ne pouvez pas changer le type d'une colonne.

Votre meilleure option dans ce scénario consiste à ajouter une colonne Int32 à la DataTable avant de la remplir:

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

Ensuite, vous pouvez cloner les données de votre table d'origine vers la nouvelle table:

DataTable dataTableClone = dataTable.Clone();

Voici un poste avec plus de détails .

4
Josh Earl

J'ai créé une fonction d'extension qui permet de changer le type de colonne d'un DataTable. Au lieu de cloner toute la table et d'importer toutes les données, il ne fait que cloner la colonne, analyser la valeur puis supprimer l'original.

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

Vous pouvez l'utiliser comme ceci:

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

Le code ci-dessus modifie toutes les colonnes décimales en doubles.

2
Wes Hanney
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" );
0
Altivo

J'ai combiné l'efficacité de la solution de Mark - donc je je n'ai pas à .Clone l'intégralité du DataTable - avec les génériques et l'extensibilité, donc je peux définir ma propre fonction de conversion . C'est ce que j'ai fini avec:

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

De cette façon, l'utilisation est beaucoup plus simple, tout en étant personnalisable:

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());
0
Marcell Toth