代码之家  ›  专栏  ›  技术社区  ›  TonE

更改填充的数据表列数据类型

  •  11
  • TonE  · 技术社区  · 16 年前

    我想将DataTable的内容附加到现有的数据库表中-目前这是使用SqlBulkCopy和DataTable作为源来完成的。

    但是,需要更改DataTable的列数据类型以匹配目标数据库表的架构,从而处理空值。

    我不是很熟悉ADO.NET,所以一直在寻找一个干净的方法来做这件事?

    谢谢。

    5 回复  |  直到 16 年前
        1
  •  10
  •   Aaronaught    16 年前

    你不能改变 DataType DataColumn

    documentation

    在列开始存储数据后更改此属性时会生成异常。

    因此,您必须确保开头的列类型正确(如果可能),或者创建一个新的 DataTable 专门用于从原始数据导入和复制数据

    你也可以写一个自定义的 IDataReader 从你的 数据表 执行实时转换并将其传递给 SqlBulkCopy -这会更有效率,但显然不是一个快速解决办法。

        2
  •  13
  •   Eddie Monge Jr    11 年前

    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
  •  3
  •   Carra    16 年前

    例如。:

        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
  •  1
  •   Mayur    13 年前

    如果您是从csv文件填充,那么首先读取datatable中的schema,然后更改列的数据类型,然后填充表。

           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
  •  1
  •   Jude Niroshan    10 年前

    就像“小埃迪·蒙格”或“吉斯韦”一样。

    但列顺序正确。

    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;
    }
    
        6
  •  0
  •   Georg Jung    6 年前

    我创建了一个 Gisway Yuri Galanter 的解决方案,解决了以下几点:

    • Don't eat exceptions ,提前失败
    • AllowDBNull 原始列的
    • 直接使用column对象,不需要将table对象作为参数
    • 改进文档
    • 在临时列名中包含guid以真正避免冲突
    • 重构成为扩展方法

    ' following methods will be defined in a module, which is why they aren't Shared
    ' based on https://codecorner.galanter.net/2013/08/02/ado-net-datatable-change-column-datatype-after-table-is-populated-with-data/ 
    ' and https://stackoverflow.com/a/15692087/1200847 
    
    ''' <summary> 
    ''' Converts DataType of a DataTable's column to a new type by creating a copy of the column with the new type and removing the old one. 
    ''' </summary> 
    ''' <param name="table">DataTable containing the column</param> 
    ''' <param name="columnName">Name of the column</param> 
    ''' <param name="newType">New type of the column</param> 
    <Extension()> 
    Public Sub ChangeColumnDataType(table As DataTable, columnName As String, newType As Type) 
        If Not table.Columns.Contains(columnName) Then Throw New ArgumentException($"No column of the given table is named ""{columnName}"".") 
        Dim oldCol As DataColumn = table.Columns(columnName) 
        oldCol.ChangeDataType(newType) 
    End Sub 
    
    ''' <summary> 
    ''' Converts DataType of a DataTable's column to a new type by creating a copy of the column with the new type and removing the old one. 
    ''' </summary> 
    ''' <param name="column">The column whichs type should be changed</param> 
    ''' <param name="newType">New type of the column</param> 
    <Extension()> 
    Public Sub ChangeDataType(column As DataColumn, newType As Type) 
        Dim table = column.Table 
        If column.DataType Is newType Then Return 
    
        Dim tempColName = "temporary-327b8efdb7984e4d82d514230b92a137" 
        Dim newCol As New DataColumn(tempColName, newType) 
        newCol.AllowDBNull = column.AllowDBNull 
    
        table.Columns.Add(newCol) 
        newCol.SetOrdinal(table.Columns.IndexOf(column)) 
    
        For Each row As DataRow In table.Rows 
            row(tempColName) = Convert.ChangeType(row(column), newType) 
        Next 
        table.Columns.Remove(column) 
        newCol.ColumnName = column.ColumnName 
    End Sub
    

    如果你有一个 int bool 列,如下使用:

    table.Columns("TrueOrFalse").ChangeDataType(GetType(Boolean)) 
    

    :由于这会更改DataTable,因此您可能希望在加载数据后立即执行此操作,然后接受更改。通过这种方式,更改跟踪、数据绑定等可以在以后正常工作:

    table.AcceptChanges()
    

    如果在加载数据时没有正确配置列的非空性,就像我的Oracle一样 NUMBER(1,0) NOT NULL 列中,您可能希望插入如下代码:

    table.Columns("TrueOrFalse").AllowDBNull = False 
    table.Columns("TrueOrFalse").DefaultValue = 0