【问题标题】:How To Convert List Into DataTable For SQlBulkCopy如何将列表转换为 SQLBulkCopy 的数据表
【发布时间】:2018-05-15 07:30:34
【问题描述】:

我有一个对象类,我将其转换为一个列表。我想将类转换成一个列表,所以我可以做一个 SQLBulkCopy,因为我当前的方法需要很长时间才能将数据写入 SQL 数据库表。

class ExtractedInfo
{
    public string Date { get; set; }
    public string Client { get; set; }
    public string Path { get; set; }
}

List<ExtractedInfo> extractedList = new List<ExtractedInfo>(); 

try
            {

            Console.WriteLine("Writing to DB");

            using (SqlConnection conn = new SqlConnection(connectionStringPMT))
            {
                conn.Open();

                SqlCommand cmd =
       new SqlCommand(
       "IF NOT EXISTS (SELECT 1 FROM [FileTrckT] WHERE Path = @Path) " +
       "INSERT INTO [FileTrckT] (Date, Client, Path, DateAddedToDb, FileName) " +  // dont forget to add "DateAddedToDb" on live code
       "VALUES (@Date, @Client, @Path, @DateAddedToDb, @FileName)");// dont forget to add " @DateAddedToDb" on live code
                cmd.CommandType = CommandType.Text;
                cmd.Connection = conn;
                cmd.Parameters.Add("@Date", DbType.DateTime);
                cmd.Parameters.Add("@Client", DbType.String);
                cmd.Parameters.Add("@Path", DbType.String);
                cmd.Parameters.Add(@"DateAddedToDb",DbType.DateTime); //uncomment on live code 
                cmd.Parameters.Add("@FileName", DbType.String);

                foreach (var extractedRecord in extractedList)
                {   
                    cmd.Parameters[0].Value = extractedRecord.Date;
                    cmd.Parameters[1].Value = extractedRecord.Client;
                    cmd.Parameters[2].Value = extractedRecord.Path;
                    cmd.Parameters[3].Value = DateTime.Now;  //uncomment on live code 
                    cmd.Parameters[4].Value = extractedRecord.Path.Substring(extractedRecord.Path.LastIndexOf("/")+1);


                    cmd.ExecuteNonQuery();
                }

                conn.Close();
            }
        } catch(Exception ex)
        {   
            Console.WriteLine(ex.Message.ToString());
            Console.WriteLine("Error occured whilst inserting data into sql table FiletrckT");
            log.Info("Error occured whilst inserting data into sql table FiletrckT");
                log.Error(DateTime.Now + ": " + ex.Message.ToString());
        }

        }

        catch(Exception ex)
        {
            log.Error(DateTime.Now.ToString() + " " + ex.Message.ToString());
            Console.WriteLine(ex.Message);
        }
    }

【问题讨论】:

    标签: c# sql sqlbulkcopy


    【解决方案1】:

    更好的选择是使用FastMember'sObjectReader 在集合或IEnumerable 之上创建一个IDataReader。通过这种方式,您可以避免将所有内容复制到 DataTable 中,从而使内存使用量翻倍。

    来自回购的样本:

    using(var bcp = new SqlBulkCopy(connection)) 
    using(var reader = ObjectReader.Create(myList, "Id", "Name", "Description")) 
    { 
       bcp.DestinationTableName = "SomeTable"; 
       bcp.WriteToServer(reader); 
    }
    

    如果要导出所有字段,则无需传递字段列表。

    图书馆可用through NuGet

    如果出于其他原因要创建DataTable,可以使用MoreLINQ的ToDataTable。它的工作原理与ToListToArray 相同,但会生成一个DataTable。完整的 MoreLINQ 库可通过 NuGet 获得。单独的扩展可以作为代码包使用,例如 ToDataTable 的源是available here

    更新

    ExtractedInfo 类似乎与FileTrckT 表的字段不匹配。这可以通过添加一个Select 调用来解决,该调用将ExtractedInfo 对象转换为表格所期望的形式,例如:

    var itemsToAdd= from it in extractedList
                    select new { Date= DateTime.Parse(it.Date), //Or ParseExact
                                 it.Client,
                                 it.Path,
                                 DateAddedToDb = DateTime.Now,
                                 FileName = it.Path.Substring(it.Path.LastIndexOf("/")+1)
                                };
    var fields=new []{"Date", "Client", "Path","DateAddedToDb","FileName"};
    
    using(var bcp = new SqlBulkCopy(connection)) 
    using(var reader = ObjectReader.Create(itemsToAdd, fields)) 
    { 
       bcp.DestinationTableName = "FileTrckT"; 
       bcp.WriteToServer(reader); 
    }
    

    【讨论】:

    • 这给出了一个错误:参数 1:无法从 'System.IDisposable' 转换为 'System.Data.IDataReader'
    • @user8155123 仅当您没有将列表传递给读者。示例工作,我使用此代码每天导入 50K 行
    • @user8155123 代码编译并运行得很好。你尝试了什么?
    • @user8155123 我已经发布了一个使用 your 代码的示例。第一个示例显示了将列表传递给ObjectReader.Create() 方法
    • 谢谢,我犯了一个小错误......它有效
    【解决方案2】:

    您可以编写自己的通用转换方法,例如:

    private DataTable ConvertToDatatable<T>(IList<T> data)
    {
        var props = TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in props)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in data)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in props)
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }
    

    或扩展方法:

    static class MyExtenstions
    {
        public static DataTable ToDataTable<T>(this IList<T> data)
        {
            var props = TypeDescriptor.GetProperties(typeof(T));
            DataTable table = new DataTable();
            foreach (PropertyDescriptor prop in props)
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            foreach (T item in data)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in props)
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                table.Rows.Add(row);
            }
            return table;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-02-14
      • 2019-11-16
      • 1970-01-01
      • 2020-07-29
      • 2012-04-07
      • 1970-01-01
      • 2013-08-08
      相关资源
      最近更新 更多