Как изменить тип данных DataColumn в DataTable?
Я имею:
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 имеет значение "Double". Я хочу, чтобы он стал "Int32".
Как мне этого добиться?
Ответы
Ответ 1
Вы не можете изменить DataType после заполнения Datatable данными. Однако вы можете клонировать таблицу данных, изменять тип столбца и загружать данные из предыдущей таблицы данных в клонированную таблицу, как показано ниже.
DataTable dtCloned = dt.Clone();
dtCloned.Columns[0].DataType = typeof(Int32);
foreach (DataRow row in dt.Rows)
{
dtCloned.ImportRow(row);
}
Ответ 2
Хотя верно, что вы не можете изменить тип столбца после заполнения DataTable
, вы можете изменить его после вызова FillSchema
, но перед вызовом Fill
. Например, скажем, что третий столбец - это тот, который вы хотите преобразовать из double
в Int32
, вы можете использовать:
adapter.FillSchema(table, SchemaType.Source);
table.Columns[2].DataType = typeof (Int32);
adapter.Fill(table);
Ответ 3
Старый пост, но я думал, что буду взвешивать, с расширением 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 name
dc.ColumnName = columnName;
}
}
}
Затем он может быть вызван следующим образом:
MyTable.ConvertColumnType("MyColumnName", typeof(int));
Конечно, используя любой тип, который вы желаете, до тех пор, пока каждое значение в столбце действительно может быть преобразовано в новый тип.
Ответ 4
Рассмотрим также изменение типа возвращаемого значения:
select cast(columnName as int) columnName from table
Ответ 5
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)
Ответ 6
Я принял немного другой подход.
Мне нужно было проанализировать datetime из импорта excel, который был в формате даты OA. Эта методология достаточно проста, чтобы строить из... по существу,
- Добавить столбец типа, который вы хотите
- Пролистайте строки, преобразующие значение
-
Удалите исходный столбец и переименуйте его в новое, чтобы соответствовать старому
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;
}
Ответ 7
Как только a DataTable
будет заполнено, вы не сможете изменить тип столбца.
Ваш лучший вариант в этом сценарии - добавить столбец Int32
в DataTable
перед его заполнением:
dataTable = new DataTable("Contact");
dataColumn = new DataColumn("Id");
dataColumn.DataType = typeof(Int32);
dataTable.Columns.Add(dataColumn);
Затем вы можете клонировать данные из исходной таблицы в новую таблицу:
DataTable dataTableClone = dataTable.Clone();
Здесь сообщение с более подробной информацией.
Ответ 8
если вы хотите изменить только column.for, например, с 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
Ответ 9
Я создал функцию расширения, которая позволяет изменять тип столбца 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;
});
}
Приведенный выше код меняет все десятичные столбцы на два.
Ответ 10
Я объединил эффективность решения Mark - поэтому мне не нужно. .Clone
весь DataTable - с обобщениями и расширяемостью, чтобы я мог определить свою собственную функцию преобразования. Вот чем я закончил:
/// <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 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());
Ответ 11
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" );