如何将列表转换为DataTable for SQlBulkCopy

时间:2018-05-15 07:30:34

标签: c# sql sqlbulkcopy

我有一个对象类,我将其转换为List。我想将类转换为列表,因此我可以执行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);
        }
    }

2 个答案:

答案 0 :(得分:3)

更好的选择是使用FastMember's ObjectReader在集合或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 :(得分:0)

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

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