2010-09-15 9 views
1

J'ai une liste de chaînes qui ne sont que des numéros de facture. J'énumère à travers cette liste pour obtenir les détails de chaque facture de la base de données. Cette liste peut facilement avoir une taille de 700 à 1000. la façon dont je le fais maintenant conduit à 700-1000 connexions à la base de données. cela prend trop de temps à compléter Y at-il une meilleure façon de le faire que je ne sais pas? Tout pointeur serait génial.aider à réduire le nombre de connexions à la base de données

ici est un exemple de mon énumération

foreach(string i in invoiceList) 
{ 
    Invoice inv = invoiceData.GetInvoice(i); 
    //do something with the invoice 
} 

puis est ici un exemple de ma méthode d'accès aux données en utilisant ADO.NET

public Invoice GetInvoice(string invoice) 
{ 
     SqlConnection con = new SqlConnection(//connection string); 
     SqlCommand cmd = new SqlCommand("dbo.getInvoices", con); 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.Parameters.Add("invoice", SqlDbType.VarChar).Value = invoice; 
     SqlDataReader dr; 
     Invoice inv = new Invoice(); 
     try{ 
      con.Open(); 
      dr = cmd.ExecuteReader 
      while(dr.read()) 
      { 
       //assign values from the database fields 
      } 


     } 
     catch{} 
     finally{con.close();} 

} 

donc essentiellement la méthode getInvoice est appelée 1000 fois l'ouverture d'un nouvelle connexion à chaque fois. Quelle est la meilleure façon (plus rapide) de faire cela? Merci!

+0

Encore mieux: Collectez toutes les factures et placez-les dans une instruction SQL IN. Ce code est horrible en termes de performances. – flq

+0

"Ce code est horrible en termes de performances" --- vous me dites! :) J'ai pensé à faire cela, mais je ne savais pas si c'était sage ou si je pouvais essayer. merci – twal

+0

Ne demandez pas de ** pointeurs **. Ce n'est peut-être pas ce que vous cherchez. :) –

Répondre

1

En termes simples tous facture nos dans une déclaration et exécuter cette instruction select dans une seule connexion.

+0

Oui, mon idée aussi. Mais il y a un SP utilisé. –

+0

merci, cela fonctionnera. Je peux éditer le SP. C'est la seule méthode qui l'utilise. – twal

+0

Vous pouvez envoyer tous les ID dans un param, puis créer une fonction de division qui divise tous les ID et renvoie une table d'ID ou utilise la méthode "exec string" plus sale – Ivo

1

Vous pouvez mettre votre code d'ouverture et de fermeture de connexion en dehors de votre boucle. Cela vous ferait seulement une connexion à la base de données. Mais cette connexion serait ouverte pendant un certain temps. C'est le compromis. Une connexion ouverte depuis longtemps ou beaucoup de connexions ouvrant et fermant.

Je remarque également que vous ne fermez pas votre connexion dans le code d'essai. Peut-être essayer ça.

public Invoice GetInvoice(string invoice) 
{ 
     SqlConnection con = new SqlConnection(//connection string); 
     SqlCommand cmd = new SqlCommand("dbo.getInvoices", con); 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.Parameters.Add("invoice", SqlDbType.VarChar).Value = invoice; 
     SqlDataReader dr; 
     Invoice inv = new Invoice(); 
     try{ 
      con.Open(); 
      dr = cmd.ExecuteReader 
      while(dr.read()) 
      { 
       //assign values from the database fields 
      } 
     } 
     catch{} 
     finally 
     { 
     con.Close(); 
     } 
} 
+0

ok merci je vais essayer et voir si les résultats sont meilleurs. – twal

+0

oh désolé j'ai juste raté cela dans mon message. J'ai enfin le avec le con.close. Désolé, j'ai oublié de copier et de passer cette partie .. :) – twal

+0

Vous devez fermer votre 'SqlDataReader' aussi. – tia

1

Il me manque le conn.Close() dans votre try-block.

Si cela vous manque vraiment, cela pourrait être votre problème: Vous continuez à faire de nouvelles connexions tout le temps. Donc, fermez-le, dans un bloc try/finally.

Mais s'il s'agissait d'une faute de frappe dans le code affiché, alors je ne pense pas que votre problème soit lié à la (aux) connexion (s), ADO.NET utilise ConnectionPooling pour que vous gardiez la vraie connexion ouverte vous dites conn.Close().

L'autre problème serait de faire une requête pour chaque facture. C'est cher aussi. Mais puisque vous semblez utiliser un SP, ce n'est pas si facile à surmonter. Ce qui serait utile ici est une instruction SELECT qui se termine par WHERE Id IN (a, b, c, d). Cela vous permettra de factures par lots (obtenir 5 ou 20 avec 1 requête.

+0

le con.close() est là j'ai juste oublié de l'inclure dans mon post. J'ai édité mon original. Merci d'avoir fait remarquer cela. – twal

+0

@twal: J'ai supposé autant. –

0

Je crois que vous pouvez envisager une approche différente si vous traitez uniformément 700 à 1000 numéros de facture ou plus à la fois, pourquoi ne pas envoyer tous les numéros de facture dans une seule requête au lieu de nombreuses requêtes individuelles. en dessous.

select 
* 
from 
ivoice_table 
where 
invoice_table.invoice_number in (123,124,125,126,127,128 etc....) 

Amusez-vous!

1

Quelque chose comme ceci pourrait être une amélioration.

public List<Invoice> GetInvoices(List<string> invoiceList) { 
    List<Invoice> invoices = new List<Invoice>(); 

    Invoice inv; 
    SqlDataReader dr; 

    using (SqlConnection con = new SqlConnection(//connection string)) { 
    using(SqlCommand cmd = new SqlCommand("dbo.getInvoices", con)) { 
     cmd.CommandType = CommandType.StoredProcedure; 
     SqlParameter param = cmd.Parameters.Add("invoice", SqlDbType.VarChar); 

     foreach(string i in invoiceList) { 
     inv = new Invoice(); 
     param.Value = i; 
     using (dr = cmd.ExecuteReader()) { 
      while(dr.read()) 
      { 
      // assign values from the database fields 
      inv.Property = dr.GetString(0); 

      // Add invoice to the result list 
      invoices.Add(inv); 
      } 
     } 
     } 
    } 
    } 

    return invoices; 
} 

Ensuite, vous pouvez utiliser cette méthode comme si ...

var invoiceList = new List<string> { "123", "456", "789" }; 
var invoices = GetInvoices(invoiceList); 
foreach(var i in invoices) { 
    Console.WriteLine(i.SomeInvoiceProperty); 
} 
+0

Je ne savais pas que le PO avait la possibilité de modifier le StoredProc. L'utilisation d'une instruction IN est 1000 fois meilleure que ma solution. – jessegavin