Comment faire pour convertir la liste en DataTable pour SQlBulkCopy

c# sql sqlbulkcopy

Question

J'ai une classe d'objet que je cobvert dans une liste. J'aimerais convertir la classe en liste afin de pouvoir effectuer une opération SQLBulkCopy, car ma méthode actuelle prend beaucoup de temps pour écrire des données dans une table de base de données 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);
        }
    }

Réponse populaire

Une meilleure option consiste à utiliser ObjectReader de FastMember pour créer un IDataReader au-dessus de la collection ou IEnumerable. De cette façon, vous évitez de doubler l'utilisation de la mémoire en copiant tout dans un DataTable.

A partir des échantillons du repo:

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

Vous n'avez pas besoin de passer une liste de champs si vous souhaitez exporter tous les champs.

La bibliothèque est disponible via NuGet

Si vous souhaitez créer un DataTable pour d'autres raisons, vous pouvez utiliser ToDataTable de MoreLINQ . Cela fonctionne de la même manière que ToList ou ToArray mais génère un DataTable. La bibliothèque complète MoreLINQ est disponible via NuGet . Les extensions individuelles sont disponibles sous forme de packages de code, par exemple le source de ToDataTable est disponible ici

METTRE À JOUR

La classe ExtractedInfo ne semble pas correspondre aux champs de la table FileTrckT . Cela peut être corrigé en ajoutant un appel Select qui convertit les objets ExtractedInfo au formulaire attendu par la table, par exemple:

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


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi