Изменение заполненных типов столбцов данных DataTable

У меня есть System.Data.DataTable, который заполняется чтением CSV файла, который устанавливает тип данных каждого столбца в строку.

Я хочу добавить содержимое DataTable в существующую таблицу базы данных - в настоящее время это делается с использованием SqlBulkCopy с DataTable в качестве источника.

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

Я не очень хорошо знаком с ADO.NET, поэтому я искал чистый способ сделать это?

Спасибо.

Ответ 1

Вы не можете изменить DataType DataColumn после заполнения его данными. Это не свойство только для чтения, но вы получите исключение во время выполнения, если попытаетесь изменить его после того, как у него уже есть данные.

В документации :

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

Поэтому вам нужно либо обеспечить правильные типы столбцов в начале (если возможно), либо создать новый DataTable специально для импорта и копирования данных из оригинала DataTable.

Вы также можете написать собственный класс IDataReader, который читает с вашего DataTable и выполняет преобразование "точно в срок" и передает его в SqlBulkCopy - это будет намного более эффективно, но это, очевидно, не быстрое исправление.

Ответ 2

Я написал эту общую функцию для выполнения этой работы, она очень хорошо работает для меня:

public static bool ChangeColumnDataType(DataTable table, string columnname, Type newtype)
{
    if (table.Columns.Contains(columnname) == false)
        return false;

    DataColumn column= table.Columns[columnname];
    if (column.DataType == newtype)
        return true;

    try
    {
        DataColumn newcolumn = new DataColumn("temporary", newtype);
        table.Columns.Add(newcolumn);
        foreach (DataRow row in table.Rows)
        {
            try
            {
                row["temporary"] = Convert.ChangeType(row[columnname], newtype);
            }
            catch
            {
            }
        }
        table.Columns.Remove(columnname);
        newcolumn.ColumnName = columnname;
    }
    catch (Exception)
    {
        return false;
    }

    return true;
}

Вы можете просто скопировать код и поместить его в класс (MyClass здесь) и использовать его следующим образом:

MyClass.ChangeColumnDataType(table, "GEOST", typeof (int));

Ответ 3

Обязательно укажите типы данных, которые вы заполняете.

например:.

    DataTable table = new DataTable("countries");
    table.Columns.Add("country_code", typeof (string));
    table.Columns.Add("country_name", typeof (string));
    //...
    //Fill table

Или вы можете изменить типы столбцов, если они совместимы:

table.Columns["country_code"].DataType = typeof(string);

Ответ 4

Если вы заполняете файл csv, сначала прочитайте схему в datatable, затем измените тип данных столбца, а затем заполните таблицу. Пример. Я использую XML файл для импорта данных.

       DataSet dstemp = new DataSet();
       dstemp.ReadXmlSchema(@"D:\path of file\filename.xml");
       dstemp.Tables[0].Columns["Student_id"].DataType = typeof(Guid);
       dstemp.ReadXml(@"D:\path of file\filename.xml");

Думаю, это сработает для вас.

Ответ 5

Так же, как "Eddie Monge Jr" или "Gisway" не может получить его.

но с правильным порядком столбцов.

public static bool ChangeColumnDataType(DataTable table, string columnname, Type newtype){
    if (table.Columns.Contains(columnname) == false)
        return false;

    DataColumn column = table.Columns[columnname];
    if (column.DataType == newtype)
        return true;

    try{
        DataColumn newcolumn = new DataColumn("temporary", newtype);
        table.Columns.Add(newcolumn);

        foreach (DataRow row in table.Rows){
            try{
                row["temporary"] = Convert.ChangeType(row[columnname], newtype);
            }
            catch{}
        }
        newcolumn.SetOrdinal(column.Ordinal);
        table.Columns.Remove(columnname);
        newcolumn.ColumnName = columnname;
    }
    catch (Exception){
        return false;
    }

    return true;
}