1
votes

Le bouton de suppression est trop lent quel est le problème

J'utilise ce code pour supprimer des enregistrements qui est sélectionné par la case à cocher dans la datagridview , mais il faut trop de temps pour exécuter la commande

private void Chkselectall_CheckedChanged(object sender, EventArgs e)
    {
        for(int n = 0; n< advancedDataGridView1.Rows.Count;n++)
        {
            advancedDataGridView1.Rows[n].Cells[0].Value = chkselectall.Checked;
        }
    }


7 commentaires

Vérifiez la requête SQL générée et utilisez le profileur dans le serveur SQL pour détecter le problème. Je pense que l'exécution des requêtes prend beaucoup de temps


À première vue, je placerais conn.Open () et conn.Close () en dehors de la boucle.


Votre code ressemble à un excellent endroit pour jouer avec l'injection SQL ... Google un peu pour "Paramètres ADO.NET"


première chose, essayez d'exécuter la même requête dans le studio de gestion et voyez si cela prend autant de temps. si oui, alors vous devriez regarder dans votre schéma de table / indexes.profiling et vérifier le plan d'exécution aiderait à identifier les goulots d'étranglement. De plus, placer une requête simple dans le code n'est pas sûr et pose également un problème de maintenabilité.


Oui, votre code pose des questions sur l'injection SQL, moyen d'éviter: stackoverflow.com/questions/14376473/...


Veuillez ne pas écrire de code comme celui-ci: new SqlCommand ("delete from tabl where id = '" + item.Cells [1] .Value.ToString () + "'", conn); < b> Paramétrez votre SQL. Propriété SqlCommand.Parameters


Outre le risque évident d'injection SQL, le code ouvre une nouvelle connexion à chaque exécution. Le simple fait d'ouvrir la connexion à l'extérieur de la boucle entraînerait une amélioration significative.


4 Réponses :


5
votes

Eh bien, vous exécutez un tas de commandes dans une séquence. Pour chacun d'eux, vous ouvrez une nouvelle connexion, la fermez et, aussi vite qu'elle soit, il y a toujours une surcharge. Vous feriez mieux d'obtenir une liste des identifiants à supprimer et de modifier votre commande en

delete from tabl where id in (…)


1 commentaires

Non, je veux dire quelque chose comme ids = ids + "," + item.Cells [1] .Value.ToString () , et après le look, créez un SqlCommand



-1
votes

Vous devriez mettre les opérations SQL hors de la boucle foreach. Concattez la chaîne sql dans la boucle et exécutez-la hors de la boucle.

private void delete_Click(object sender, EventArgs e)
    {
        StringBuilder sb = new StringBuilder();
        foreach(DataGridViewRow item in advancedDataGridView1.Rows)
        {
            if(bool.Parse(item.Cells[0].Value.ToString()))
            {
                sb.AppendFormat("delete from tabl where id='{0}';{1}", item.Cells[1].Value, Environment.NewLine);

            }
        }
                conn.Open();
                SqlCommand cmd = new SqlCommand(sb.ToString(), conn);
                cmd.ExecuteNonQuery();
                conn.Close();
        MessageBox.Show("Successfully Deleted....");
    }

Théoriquement, passer des paramètres sql directement est assez dangereux à cause de l'injection SQL. Vous devez vous en occuper vous-même


6 commentaires

Il est en fait plus facile d'écrire du code correct qui utilise des paramètres de commande au lieu d'analyser.


@PanagiotisKanavos comment est-ce


@AhmedAlKhteeb Nick a déjà publié une bonne réponse. Si vous avez plus de 1000 lignes à supprimer, il existe d'autres moyens


@PanagiotisKanavos oui j'ai plus de 1000 lignes


@AhmedAlKhteeb Que font 1K lignes dans une grille et comment ont-elles été sélectionnées? Les critères utilisés pour sélectionner ces 1K lignes dans la grille doivent probablement être utilisés dans la requête à la place. Dans tous les cas, je vous suggère de mettre à jour la question. Une clause IN ne peut pas contenir plus de 1K éléments. Vous pouvez utiliser un paramètre table pour transmettre les ID et utiliser un JOIN dans l'instruction DELETE , ou vous pouvez insérer les ID dans une table intermédiaire et joindre avec cela


l'utilisateur l'a sélectionné en sélectionnant tout ou un par un ou en faisant un filtre et en sélectionnant tout il existe de nombreuses façons de faire la sélection. alors à quoi devrait ressembler la mise à jour ??



0
votes

Peu de choses que vous faites de manière incorrecte.

  • Vous utilisez des requêtes en ligne, nous avons déjà de nombreux threads (dans SO) qui discutent de ce problème, car cela ouvre une large porte à SQLInjection.
  • La raison qui ralentit les performances de l'exécution est la façon dont vous traitez. c'est-à-dire que vous parcourez chaque ligne et pour chaque élément correspondant, vous ouvrez une connexion et exécutez la requête de suppression.

Je préfère que vous utilisiez les étapes suivantes:

  • Parcourez les lignes et collectez les éléments à supprimer en fonction de la condition.
  • construire une requête pré-paramétrée qui accepte un paramètre de type string.
  • Attribuez les identifiants collectés comme valeur du paramètre.
  • Exécutez la requête.

Veuillez trouver l'exemple de code ci-dessous:

private void delete_Click(object sender, EventArgs e)
{
    List<string> selectedIds = new List<string>();
    foreach (DataGridViewRow item in advancedDataGridView1.Rows)
    {
        if (bool.Parse(item.Cells[0].Value.ToString()))
        {
            selectedIds.Add("'" + item.Cells[1].Value.ToString() + "'");
            // collecting all ids
        }
    }
    String sql = "delete from tabl where id in(@idsToDelete)";
    using (SqlConnection cn = new SqlConnection("Your connection string here")) 
    {
        cn.Open();
        using (SqlCommand cmd = new SqlCommand(sql, cn)) 
        {
            cmd.Parameters.Add("@idsToDelete", SqlDbType.VarChar).Value = string.Join(",", selectedIds);
            cmd.ExecuteNonQuery();
        }
    }      
}


9 commentaires

IN traitera le paramètre comme une valeur unique , pas comme une liste de valeurs


Veuillez ne pas préconiser l'utilisation de AddWithValue: AddWithValue is Evil ; Comment polluer votre cache de plan avec des instructions SQL paramétrées ; AddWithValue est diabolique! ...


@AndrewMorton: Ouais ..! moi aussi lu cet article, fait ces changements. Merci pour le reste


Cela ne peut toujours pas fonctionner pour le raison donnée par Panagiotis plus tôt . Vous pouvez essayer d'utiliser un paramètre table , mais je suis pas certain que cela peut être fait sans procédure stockée.


@AndrewMorton je n'utilise pas de procédure stockée car je suis nouveau dans le codage et je ne l'ai pas encore appris


@sujithkarivelil j'obtiens cette erreur (ExecuteNonQuery nécessite une connexion ouverte et disponible. L'état actuel de la connexion est fermé)


@AhmedAlKhteeb: Le message est assez clair na? oublié d'ouvrir la connexion. vérifier le code mis à jour dans ma réponse


@sujithkarivelil (La conversion a échoué lors de la conversion de la valeur varchar `` 1499840 '' en type de données int)


@sujithkarivelil où est le problème?



0
votes

merci à tous pour votre aide, j'ai trouvé ce dont j'avais besoin et j'espère que cela aidera quelqu'un d'autre à avoir besoin de quelque chose comme ça

String sql;
int parameterCounter;
SqlParameter parameter;

private void delete_Click(object sender, EventArgs e)
{
    sql = "delete from tabl where id in (";
    parameterCounter = 0;

    using (SqlConnection cn = new SqlConnection("....")) {
    using (SqlCommand cmd = new SqlCommand(sql, cn)) {
    foreach (DataGridViewRow item in advancedDataGridView1.Rows) {
     if (bool.Parse(item.Cells[0].Value.ToString())) {
        parameterCounter++;
        parameter = new SqlParameter();
        parameter.ParameterName = "@par" + parameterCounter.ToString();
        parameter.DbType = System.Data.DbType.Int32;
        parameter.Value = item.Cells[1].Value;
        cmd.Parameters.Add(parameter);
        sql = sql + $"{parameter.ParameterName},";
        // collecting all ids
     }
  }
  sql = sql.TrimEnd(',');
  sql = sql + ")";

  cmd.CommandText = sql;
  cmd.Connection = cn;
  cn.Open();
  cmd.ExecuteNonQuery();
    MessageBox.Show("Successfully Deleted....");
}


0 commentaires