2016-04-12 17 views
3

C#で実行する必要があるSQL文があり、C#コードからパラメータを取得する必要があります。私はストアドプロシージャがSQLインジェクションを避けることが好まれていることを知っているが、私はC#でこれを行うために探している。一時ストアドプロシージャを実行中のC#

このSQLをC#に翻訳していますが、SQL Server Management Studioでクエリが機能していてもエラーが発生しました。今、私は#AddCriteriaTableプロシージャを実行しようとすると、私はエラーが発生したC#でこれをしようと

-- 1.) Declare a criteria table which can be any number of rows 
BEGIN TRY 
    DROP TABLE #CriteriaTable 
END TRY 
BEGIN CATCH 
END CATCH 

CREATE TABLE #CriteriaTable (ParameterCode VARCHAR(64), Value VARCHAR(64)) 

-- 2.) Declare a procedure to add criteria table 
BEGIN TRY 
    DROP PROCEDURE #AddCriteriaTable 
END TRY 
BEGIN CATCH 
END CATCH 
go 

CREATE PROCEDURE #AddCriteriaTable 
    (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) 
AS 
    INSERT #CriteriaTable 
    VALUES(@ParameterCode, @Value) 
GO 

-- 3.) Do a computation which accesses the criteria 
BEGIN TRY 
    DROP PROCEDURE #ComputeBasedOnCriteria 
END TRY 
BEGIN CATCH 
END CATCH 
go 

CREATE PROCEDURE #ComputeBasedOnCriteria 
    (@product VARCHAR(36) = 'ABC', 
     @currency VARCHAR(3) = 'USD', 
     @zScore FLOAT = .845) 
AS 
    -- Code inside this procedure is largely dynamic sql. 
    -- This is just a quick mock up 
    SELECT 
     @Product ProductCode, 
     @currency Currency, 
     950 ExpectedRevenue, 
     * 
    FROM 
     #CriteriaTable c 
    PIVOT 
     (min (Value) FOR ParameterCode IN 
      ([MyParam1], MyParam2, MyParam3) 
     ) AS pvt 
    GO 

    --End of code for Configuration table 

-- Samples: Execute this to add criteria to the temporary table that will be used by #ComputeBasedOnCriteria 
EXEC#AddCriteriaTable 'MyParam1', 'MyValue1' 
EXEC#AddCriteriaTable 'MyParam2', 'MyValue3' 
EXEC#AddCriteriaTable 'MyParam3', 'MyValue3' 

--Execute the procedure that will return the results for the screen 
EXEC#ComputeBasedOnCriteria 

Result is:

:それは一時的なストアドプロシージャと以下の一時テーブルを使用しています。

例外:System.Data.SqlClient.SqlException、キーワード「PROC」付近に不適切な構文私はそれがスロー最後の行に2つ目のExecuteQueryを実行しようとします。

なぜSQL Serverでは動作しますが、C#コードでは機能しませんか? C#でこれを行う別の方法はありますか?私はまだこのc# - db作業を学んでいるので、私が従うべきであるC#のガイドラインがあるかどうかを教えてください。

enter image description here

EDIT: 私は通常のストアドプロシージャとしてこれを行うと、しかし、私が言うことができないチームに問題があるのDataTableに渡すことができます知っていて、それがテキストとしてSPを使用するために私を強制します。それが失敗していることを

+0

Imは推測であなたのSQLにCREATE PROCを持っているので

しかし、すべてのことから離れては、あなたがエラーを取得しているのより多くのあなたが問題thatsのC#の呼び出しを行う方法。最後のexeC#computebasedoncritieriaの前のすべての行はexecutenonquery、行、最後のデータを取得する通常のクエリである必要があります - あなたのC#コードを表示することができます – BugFinder

+0

私はC#コードを含む画像を貼り付けました。私はまだ#computebasedoncritieriaをコード化していない。 #AddCriteriaTableを実行するとエラーが発生します。 –

+1

あなたのコードではじまるあなたはあなたがそれを作るときにそれを呼び出すように見えるので、Idは別のexecnoqueryでそれを作ることを期待し、それを実行します..それは両方の組み合わせを持っているようですその最後のコマンドセットで – BugFinder

答えて

3

理由はあなたがここにCREATE PROCセクションにパラメータを渡しているです:あなただけの手順を作成しているので、それは、ここに値を渡すことには意味がありません

cmd.CommandText = @"CREATE PROC#AddCriteriaTable (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) AS INSERT #CriteriaTable VALUES (@ParameterCode, @Value)"; 
cmd.Parameters.AddWithValue("@ParameterCode", request.Criteria.First().Key; 
cmd.Parameters.AddWithValue("@Value", request.Criteria.First().Value; 
var reader2 = cmd.ExecuteReader(); 

、あなただけの必要プロシージャの実行時にそれらを渡します。

SSMSで実行したときと同じ、誤った構文エラーがスローされます
EXEC sp_executesql 
     N'CREATE PROC#AddCriteriaTable (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) AS INSERT #CriteriaTable VALUES (@ParameterCode, @Value)', 
     N'@ParameterCode VARCHAR(64),@Value VARCHAR(64)', 
     @ParameterCode = 'MyParam1', 
     @Value = 'MyValue1' 

:あなたは、トレースを実行する場合は、これは、サーバー上で実行されているようなものが表示されます。必要なのは、次のとおりです。

EXEC sp_executesql 
    N'CREATE PROC#AddCriteriaTable (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) AS INSERT #CriteriaTable VALUES (@ParameterCode, @Value)'; 

はあなたが必要となるC#で:

//First Create the procedure 
cmd.CommandText = @"CREATE PROC#AddCriteriaTable (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) AS INSERT #CriteriaTable VALUES (@ParameterCode, @Value)"; 
cmd.ExecuteNoneQuery(); 

//Update the command text to execute it, then add parameters 
cmd.CommandText = "EXECUTE #AddCriteriaTable @ParameterCode, @Value;"; 
cmd.Parameters.AddWithValue("@ParameterCode", request.Criteria.First().Key; 
cmd.Parameters.AddWithValue("@Value", request.Criteria.First().Value; 
var reader2 = cmd.ExecuteReader(); 

私はあなたがすべてのものを複雑に超えていると思いますが、一時テーブルにデータを追加するための一時的なストアドプロシージャは、killの上にいるようです。 コードから実行している場合は、すべてを再利用する必要があるようですが、計算のための恒久的な手順があるだけでは、 を定義してから、定義された型を使用して実行のインスタンスを管理してください。

だから、最初のあなたのタイプを作成します。

CREATE TYPE dbo.CriteriaTableType AS TABLE (ParameterCode VARCHAR(64), Value VARCHAR(64)); 

次に、あなたprocdureを作成します。

CREATE PROC dbo.ComputeBasedOnCriteria 
(
    @product  VARCHAR(36)='ABC', 
    @currency  VARCHAR(3)='USD', 
    @zScore   FLOAT = .845, 
    @CriteriaTable dbo.CriteriaTableType READONLY 
) 
AS 
--Code inside this proc is largely dynamic sql. This is just a quick mock up 
SELECT 
     @Product ProductCode 
     ,@currency Currency 
     ,950 ExpectedRevenue 
     ,* 
FROM @CriteriaTable c 
     PIVOT (MIN (Value) FOR ParameterCode IN (MyParam1, MyParam2,MyParam3)) AS pvt; 
GO 

そして、最終的に実行するために:

DECLARE @Criteria dbo.CriteriaTableType; 
INSERT @Criteria 
VALUES 
    ('MyParam1', 'MyValue1'), 
    ('MyParam2', 'MyValue2'), 
    ('MyParam3', 'MyValue3'); 

EXECUTE dbo.ComputeBasedOnCriteria @CriteriaTable = @Criteria; 

をあなたもC#で基準表を移入することができますこれをC#からプロシージャに渡すだけです。

var table = new DataTable(); 
    table.Columns.Add("ParameterCode", typeof(string)).MaxLength = 64; 
    table.Columns.Add("Value", typeof(string)).MaxLength = 64; 

    foreach (var criterion in request.Criteria) 
    { 
     var newRow = table.NewRow(); 
     newRow[0] = criterion.Key; 
     newRow[1] = criterion.Value; 
     table.Rows.Add(newRow); 
    } 
    using (var connection = new SqlConnection("connectionString")) 
    using (var command = new SqlCommand("dbo.ComputeBasedOnCriteria", connection)) 
    { 
     var tvp = command.Parameters.Add("@CriteriaTable", SqlDbType.Structured); 
     tvp.TypeName = "dbo.CriteriaTableType"; 
     tvp.Value = table; 

     using (var reader = command.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       //Do Something with your results 
      } 
     } 
    } 
+0

実際には単語は 'PROC'です。 SOの誰かがそれを「手順」に編集しました。私は今戻しました。スクリーンショットからのエラーは、ExecuteReaderが実行する3番目のコマンドテキストに基づいています。それがなぜ失敗しているのかはまだ分かりません。私はあなたのコードを確認します、ありがとう! –

+0

コードを見せてくれて大変感謝しています。この時点で私はSPアプローチを使用できませんでした(EDITを参照)。私は当初あなたが示唆したものに似てそれを設計したが、それはテキストspでなければならなくなった。 tempテーブルは、2つのSPがデータを使用できるようになっています。 –

+0

私はそれを理解しましたが、私の編集では説明しましたが、その要点はパラメータ値を 'CREATE PROC'ステートメントに渡していることです。必要ない。 – GarethD

1

あなたがあなたにもちょうどのC#を経由して、あなたのSQLを実行して、手続きを忘れる可能性があるのC#を経由してストアドプロシージャを作成するためにSQLを実行している場合。

SQLインジェクションを避けるためにストアドプロシージャを使用する点は、ストアドプロシージャがサーバー上に既に存在し、コードを使用してストアドプロシージャを作成していない場合にのみ適用されます。

ここでSQL挿入を回避するには、Parameterizedクエリを使用します。 パラメータは、データ型の検証によってSQLインジェクションを防止します。したがって、コードに整数を挿入すると、注入を試みる人は、予想される結果を変える特殊文字を文字列で与えることができません。あなたがC#の代わりにCREATE PROCEDURE

関連する問題