2016-07-20 31 views
-1

Ich habe eine C# -Anwendung, wo ich eine gespeicherte Prozedur in C# aufrufen, ich übergebe ein Listenobjekt an die Prozedur und es führt eine Validierung für die Datensätze. Dies ist jedoch sehr langsam mit vielen Aufzeichnungen zu verarbeiten, gibt es vielleicht einen besseren Weg, dies zu erreichen. Bitte lesen Sie meinen Code untenOptimierte Stored Procedure Schleife

using (SqlConnection conn = new SqlConnection(sqlConnection)) 
{ 
    try 
    { 
     foreach (var claim in supplierClaimsData) 
     { 
      SqlCommand cmd = new SqlCommand(); 
      cmd.CommandTimeout = 60; 
      cmd.CommandText = "CRM.Supplier_Claim_Upload"; 
      cmd.CommandType = CommandType.StoredProcedure; 
      cmd.Parameters.Add("@Invoice", SqlDbType.NVarChar).Value = claim.Line_Number; 
      cmd.Parameters.Add("@Amount", SqlDbType.Decimal).Value = claim.Total_Claim; 
      cmd.Connection = conn; 

      conn.Open(); 
      SqlDataReader reader = cmd.ExecuteReader(); 

      while (reader.Read()) 
      { 
       claim.ST_Key = reader.GetString(reader.GetOrdinal("ST_Key")); 
       claim.Error_1 = reader.GetString(reader.GetOrdinal("Error1")); 

       string lineNumberDoesNotExist = "Error: Invoice line number does not exist"; 
       if (claim.Error_1.StartsWith(lineNumberDoesNotExist)) 
       { 
        continue; 
       } 

       claim.Warning = reader.GetString(reader.GetOrdinal("Warning")); 
       claim.Error_2 = reader.GetString(reader.GetOrdinal("Error2")); 
       string warningCleanInclusion = "Warning"; 

       if (claim.ST_Key != null && string.IsNullOrEmpty(claim.Warning) && string.IsNullOrEmpty(claim.Error_1) && string.IsNullOrEmpty(claim.Error_2)) 
       { 
        var existingClaimCount = db.GPClaimsReadyToImports.Count(a => a.ST_Key == claim.ST_Key && a.CleanSupplierClaimSessionID == claim.CleanSupplierClaimsUploadSessionID); 
        if (existingClaimCount == 0) 

         db.GPClaimsReadyToImports.Add(new GPClaimsReadyToImport 
         { 
          Id = claim.Id, 
          ST_Key = claim.ST_Key, 
          Warning = claim.Warning, 
          Action = claim.Action, 
          Claim_Reference = claim.ClaimReference, 
          Currency = claim.Currency, 
          Error_1 = claim.Error_1, 
          Error_2 = claim.Error_2, 
          Line_Number = claim.Line_Number, 
          Total_Claim = claim.Total_Claim, 
          Domain_Username = domainNameOfficial.ToString(),//claim.Domain_Username, 
          DateCreated = DateTime.Now, 
          ImportFlag = true, 
          ReadyForImport = true, 
          CleanSupplierClaimSessionID = sessionIdentifier 

         }); 
        db.SaveChanges(); 
       } 
      } 

      foreach (CleanSupplierClaim saveToDBClaim in supplierClaimsData) 
      { 
       db.CleanSupplierClaims.Attach(saveToDBClaim); 

       var entry = db.Entry(saveToDBClaim); 
       entry.Property(aa => aa.Line_Number).IsModified = true; 
       entry.Property(aa => aa.Total_Claim).IsModified = true; 
       entry.Property(aa => aa.Currency).IsModified = true; 
       entry.Property(aa => aa.ClaimReference).IsModified = true; 
       entry.Property(aa => aa.Action).IsModified = true; 
       entry.Property(aa => aa.Domain_Username).IsModified = true; 
       entry.Property(aa => aa.Error_1).IsModified = true; 
       entry.Property(aa => aa.Error_2).IsModified = true; 
       entry.Property(aa => aa.Warning).IsModified = true; 
       entry.Property(aa => aa.ImportFlag).IsModified = true; 
       entry.Property(aa => aa.ReadyForImport).IsModified = true; 
       db.Entry(saveToDBClaim).State = System.Data.Entity.EntityState.Modified; 
       db.SaveChanges(); 
      } 

      conn.Close(); 
     } 
    } 
} 

Ich frage mich, ob es eine Möglichkeit, die ich den Aufruf der Prozedur in der Schleife ausschließen kann, aber nicht genau wissen, wie dieser Code zu optimieren, wird jede Hilfe dankbar.

+0

Da Sie sich in einem Verwendungsabschnitt befinden, müssen Sie Ihre Verbindung nicht explizit schließen. –

+0

Eine Optimierung könnte Multi-Threading von gespeicherten Prozeduraufrufen mit einem Thread-Pool oder einer einfachen Parallel.ForEach –

+0

einfacher, und bessere Leistung gewinnen, um Code von Storedproc zu erhalten und eine andere Version davon, die direkt aus der Quellentabelle liest usw. – montewhizdoh

Antwort

1

Ich sehe, dass die gespeicherte Prozedur mehrmals für jeden Datensatz aufgerufen wird, die die Zeitverzögerung verursacht. Daher empfehlen wir, die "supplierClaimsData" -Liste/das Array als Ganzes über die XML- oder Tabellentypvariable an die Prozedur zu übergeben und die Prozedur eine Tabelle für nachfolgende Eingabesätze zurückgeben zu lassen. Dann machen Sie Ihre while-Schleife für jede Ergebnistabelle, die schneller ist ...

Eines der Beispiele, um die Tabelle an die Prozedur zu übergeben, ist in der Verknüpfung definiert. How to pass User Defined Table Type as Stored Procedured parameter in C#

+0

Ich habe keinen Zugriff darauf, den Proc so zu ändern, wie er vom BI-Team erstellt wurde, er hat ihn so aufgebaut, dass der Proc zwei Parameter annehmen kann, Rechnung und Betrag, meine Liste besteht aus Artikeln mit Rechnung und Betrag. Gibt es eine Möglichkeit, dies zu erreichen, ohne das Verfahren zu ändern? – Papi

+1

In diesem Fall generalisieren Sie SQLCommand und die Prozedurdeklaration vor der foreach-Schleife und schließen Sie die SQL-Verbindung nicht. Schließe es nach der foreach-Schleife. Sammeln Sie das zurückgegebene Ergebnis jeder Iteration in einer Datentabelle und restrukturieren Sie Ihre While-Schleifenlogik, um die Datentabelle anzupassen. –

+0

@papi Holen Sie sich den Code für die Prozedur und machen Sie eine neue Prozedur (am besten). oder wickeln Sie die Prozedur in eine andere Prozedur (nicht so gut) – montewhizdoh