2016-07-20 4 views
-1

C#でストアドプロシージャを呼び出すC#アプリケーションがあります。リストオブジェクトをプロシージャに渡し、レコードの検証を実行します。しかし、多くのレコードを処理するには非常に時間がかかりますが、これを実現するためのより良い方法があるでしょうか。私は、ループ内でPROCを呼び出して除外することができますが、任意の助けが理解されるであろう、このコードを最適化する方法を正確に知らない方法があるかしらストアドプロシージャループを最適化する

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

以下の私のコードを参照してください。

+0

あなたが使用しているセクションにいるため、接続を明示する必要はありません。 –

+0

最適化は、スレッドプールまたは単純なParallel.ForEach –

+0

を使用してストアドプロシージャコールをマルチスレッド化することができます。また、storedprocのコードを取得してソーステーブルなどから直接読み取る別のバージョンを作成するとパフォーマンスが向上します。 – montewhizdoh

答えて

1

私は、ストアドプロシージャが各レコードに対して複数回呼び出されることがわかりました。これは時間の遅れを引き起こします。したがって、「supplierClaimsData」リスト/配列をXMLまたは表型変数を介してプロシージャ全体に渡し、プロシージャに後続の入力レコード用の表を戻すことをお薦めします。その後、各結果テーブルのwhileループを実行すると、より高速になります。

プロシージャにテーブルを渡す例の1つがリンクに定義されています。 How to pass User Defined Table Type as Stored Procedured parameter in C#

+0

私はBIチームによって構築されたprocを変更するアクセス権がなく、procが2つのパラメータを取ることができるようにビルドし、請求書と金額を請求し、請求書と金額を持つ項目で構成されます。手順を変更せずにこれを達成できる方法はありますか? – Papi

+1

その場合、foreachループの前にSQLCommandとプロシージャ宣言を一般化し、SQL接続を閉じないでください。 foreachループの後に閉じます。各繰り返しの返された結果をデータテーブルに収集し、whileループロジックを再構成してデータテーブルに対応します。 –

+0

@papiプロシージャのコードを取得し、新しいプロシージャを作成します(ベスト)。プロシージャを別のプロシージャにラップします(適切ではありません) – montewhizdoh