2
votes

meilleure solution pour la solution de mise à jour d'insert multiple

Luttez pour comprendre C # et Npgsql en tant que débutant. Exemples de code suivants:

// Insert some data
    using (var cmd = new NpgsqlCommand())
    {
        foreach(s in SomeStringCollectionOrWhatever)
        {
           cmd.Connection = conn;
           cmd.CommandText = "INSERT INTO data (some_field) VALUES (@p)";
           cmd.Parameters.AddWithValue("p", s);
           cmd.ExecuteNonQuery();
        }
    }

La syntaxe de plus d'une instruction d'insertion et de mise à jour comme celle-ci est claire jusqu'à présent:

cmd.CommandText = "INSERT INTO data (some_field) VALUES (@p);INSERT INTO data1...;INSERT into data2... and so on";

Mais qu'est-ce la bonne solution pour une boucle qui devrait gérer une instruction à l'intérieur.

Cela ne fonctionne pas:

   // Insert some data
    using (var cmd = new NpgsqlCommand())
    {            cmd.Connection = conn;
        cmd.CommandText = "INSERT INTO data (some_field) VALUES (@p)";
        cmd.Parameters.AddWithValue("p", "Hello world");
        cmd.ExecuteNonQuery();
    }

Il semble que les valeurs seront "concaténées" ou mémorisées . Je ne vois aucune possibilité "d'effacer" l'objet cmd existant.

Ma deuxième solution serait d'envelopper tout le bloc "using" dans la boucle. Mais chaque cycle créerait un nouvel objet. Cela me semble moche.

Alors, quelle est la meilleure solution à mon problème?


0 commentaires

3 Réponses :


1
votes

Pour insérer efficacement de nombreuses lignes, jetez un œil à la fonctionnalité de copie en bloc de Npgsql - l'API est plus appropriée (et plus efficace) pour insérer un grand nombre de lignes que pour concaténer des instructions INSERT dans un lot comme vous essayez de le faire.


1 commentaires

Non, je ne veux pas copier des données de l'extérieur vers la base de données ou vice versa de cette manière. C'est juste une question concernant le sql suivant à partir d'une boucle. (avec des valeurs de paramètres changeantes par exemple)



1
votes

Si vous souhaitez réexécuter le même SQL en modifiant les valeurs des paramètres, vous pouvez effectuer les opérations suivantes:

using (var cmd = new NpgsqlCommand("INSERT INTO data (some_field) VALUES (@p)", conn))
{
    var p = new NpgsqlParameter("p", DbType.String); // Adjust DbType according to type
    cmd.Parameters.Add(p);
    cmd.Prepare();   // This is optional but will optimize the statement for repeated use

    foreach(var s in SomeStringCollectionOrWhatever)
    {
       p.Value = s;
       cmd.ExecuteNonQuery();
    }
}


2 commentaires

D'accord, je vois. Qu'en est-il de la méthode NpgsqlCommand.CreateParameter? Le document API indique qu'une nouvelle instance de paramètre sera créée. Alors, cette méthode fonctionne-t-elle de la même manière que vous avez suggéré ci-dessus?


L'idée est de réutiliser la même instance de NpgsqlParameter à travers les exécutions de la même commande. La manière dont vous créez cette instance n'a pas vraiment d'importance - soit NpgsqlCommand.CreateParameter () ou new NpgsqlParameter () sont OK.



0
votes

Si vous avez besoin de beaucoup de lignes et que les performances sont essentielles, je recommanderais la capacité de copie en bloc de Npgsql, comme @Shay l'a mentionné. Mais si vous cherchez un moyen rapide de le faire sans la copie en bloc, je vous recommande d'utiliser Dapper .

Prenons l'exemple ci-dessous.

Supposons que vous ayez une classe appelée Event et une liste d'événements à ajouter.

var sqlInsert = "Insert into events( eventid, eventname ) values (@EventId, @EventName)";


using (IDbConnection conn = new NpgsqlConnection(cs))
{
    conn.Open();

    // Execute is an extension method supplied by Dapper
    // This code will add all the entries in the eventsToInsert List and match up the values based on property name. Only caveat is that the property names of the POCO should match the placeholder names in the SQL Statement.
    conn.Execute(sqlInsert, eventsToInsert);

    // If we want to retrieve the data back into the list
    List<Event> eventsAdded;

    // This Dapper extension will return an Ienumerable, so i cast it to a List.
    eventsAdded = conn.Query<Event>("Select * from events").ToList();

    foreach( var row in eventsAdded)
    {
        Console.WriteLine($"{row.EventId} {row.EventName} was added");
    }
}

L'extrait de code qui ajoutez la liste à la base de données ci-dessous.

List<Event> eventsToInsert = new List<Event>
{
    new Event() { EventId = 1, EventName = "Bday1" },
    new Event() { EventId = 2, EventName = "Bday2" },
    new Event() { EventId = 3, EventName = "Bday3" }
};

-HTH


0 commentaires