none
SQLServer接続時のクエリ実行に関して。 RRS feed

  • 質問

  • 初めてSQLServerに接続して、SQLを実行するようなプログラムを行っているのですが、

    皆さんどの様にやっているかを教えて頂きたいです。

    SQL接続と、SELECT文等は殆ど共通にできると思うので共通とし

    クエリ部分を可変にしようと思ったのですが、VisualStudio2012のコード分析を行うと

    クエリの部分を可変文字にするとCA2100で警告が出ます。

    SELECT文の一部をパラメータ付きにすれば良いと、

    https://msdn.microsoft.com/ja-jp/library/ms182310.aspx

    MSDNで記載されていますが、皆さん以下のようにベタ書きでプログラムしてるのでしょうか?

       someCommand.CommandText = "SELECT AccountNumber FROM Users " + 
                "WHERE Username=@username AND Password=@password";

    SQL少し変えるだけで、毎回コンパイルしないといけないので、app.configなどにクエリを書ければなーと思ってました。

    ※まさしくこれが脆弱性といえるかもしれませんが。

    よろしくお願いいたします。

    --

    追記

    すみません、やりたい事は単純なことで以下のようにマジックナンバー的に書くのではなく

    string query = "SELECT * FROM XXX 略"という記載

    string query = "SELECT * FROM YYY 略"という記載をプログラム等で持つのではなく

    app.configエリア等に、SELECT * FROM ZZZのように文字列を定義しておいて

    コンパイル無しで後から簡単に変えれないのかなと思ったのです。

    定義ファイルを変えれば実行する事を変えれるので、脆弱なプログラムになりそうな。というのは

    そういう事で書いた感じです。

    理想は、

    void 呼び出し関数A

    {

    XXX.Command(Properties.Settings.Default.QueryA);

    }

    void 呼び出し関数B

    {

    XXX.Command(Properties.Settings.Default.QueryB);

    }

    void Command(string query)

    {

    .CommandText = query;

    }

    のようにしたいのですが、これではセキュリティに引っかかるので

    どうしているのかなという話でした。

    SELECT~等の記載をプログラム内部で持たせたくないな。という考え方をしていたため、この質問になります。

    一般的に"SELECT * FROM"等の文字列は内部で持つのが普通なのかな。と


    • 編集済み mogja 2018年5月11日 4:06
    2018年5月10日 11:54

回答

  • ご質問の意図を正しく汲み取れていなかったようで、失礼しました。「皆さんどの様にやっているかを教えて頂きたい」の部分を誤って解釈していたようです。

    コード分析規則 CA2100 に焦点をあてた視点で再度、回答させてください。

    既に確認されているかもしれませんが、この CA2100 の規則は次のような根拠が説明されています。

    > この規則では、文字列引数にユーザー入力が含まれていることが想定されています。 ユーザー入力から構築された SQL コマンド文字列には、SQL 注入攻撃に対する脆弱性があります。

    [1] CA2100: Review SQL queries for security vulnerabilities
    https://docs.microsoft.com/ja-jp/visualstudio/code-quality/ca2100-review-sql-queries-for-security-vulnerabilities

    コード分析において、セキュリティの警告が出てしまうのは、 Microsoft マネージドコード推奨規則と「SELECT~等の記載をプログラム内部で持たせたくない」という考え方が相反しているためです。

    「皆さんどの様にやっているか」に対して改めて回答させていただくならば、少なくとも Microsoftのコード分析規則を準拠する開発者の中では、
    他の回答者からも既に回答されている方法(SQL の基本構文部分にユーザー入力を含ませない)を選択するのが多数派と思われます。

    ご返信の中のご質問「CA2100に引っかかるのでどうしたらいいのか」に対しては、対象のプログラムのみ、コード分析の規則セットを変更することで警告を非表示にすることができます(ルール CA2100 のチェックを外す)。規則セットの変更方法は次のリンクで説明されています:

    [2] 方法: マネージ コード プロジェクトのコード分析を構成する
    https://docs.microsoft.com/ja-jp/visualstudio/code-quality/how-to-configure-code-analysis-for-a-managed-code-project

    [3] カスタム規則セット
    https://docs.microsoft.com/ja-jp/visualstudio/code-quality/how-to-create-a-custom-rule-set

    また、SQL にユーザー入力を含ませながら、かつコード分析標準規則に違反しない1つの方法として、C# プログラムから .sql ファイルを SQLCMD.EXE に引き渡して実行する、という方法もあります。ここで「違反しない」とは、コード分析の隙間を潜り抜けているだけであって、規則の本質に準拠していません。

    例えば、以下のコード例は標準規則のコード分析に違反しません(そして、明らかに標準的な使用方法ではありません)
    string cmd = @"{SQL_SERVER_ROOT}\Tools\Binn\SQLCMD.EXE";
    string sql = @"{APP_ROOT}\transaction.sql";
    string arguments = String.Format("-S {SERVERNAME} -U {USERNAME} -P {PASSWORD} -i \"{0}\"", sql);
    
    System.Diagnostics.ProcessStartInfo procStartInfo =
        new System.Diagnostics.ProcessStartInfo(cmd, arguments);
    procStartInfo.RedirectStandardOutput = true;
    procStartInfo.UseShellExecute = false;
    procStartInfo.CreateNoWindow = true;
    System.Diagnostics.Process proc = new System.Diagnostics.Process();
    proc.StartInfo = procStartInfo;
    proc.Start();
    string result = proc.StandardOutput.ReadToEnd();
    Console.WriteLine(result);

    以上は、提案を意味するものではなく、ご質問に対する単純な回答です。回答として余計な意見と承知していますが、この CA2100 について、私は良い規則であるように思います。


    --- Seiji Momoto

    • 回答としてマーク mogja 2018年6月2日 10:22
    2018年5月12日 17:48
  • 質問者さん>

    先の私のレスで、

    > データーソース構成ウィザードを使って、DB のテーブル毎に型付 DataSet + TableAdapter を作ることをお勧めします。

    ・・・と書きましたが、その作り方を書いた記事を紹介しておきます。

    7.6 データコンポーネント機能によるデータアクセスコンポーネントの開発
    http://www.atmarkit.co.jp/fdotnet/bookpreview/vs2005webapp_07/vs2005webapp_07_01.html

    上記は ASP.NET Web アプリの記事ですが型付 DataSet + TableAdapter に関しては Web アプリに限らず共通です。

    この記事が、自分の知る限りでは一番まとまっていてわかりやすかったと思っています。

    VS2008 からは(上の記事は VS2005)TableAdapterManager も自動生成されるようになり、それを使っての階層更新も可能になっています。

    10 行でズバリ !! 非接続型のデータ アクセス (ADO.NET) (C#)
    https://code.msdn.microsoft.com/windowsdesktop/10-ADONET-C-cbfe7688

    今回の話とは直接の関係はないですが、ご参考まで。

    • 回答としてマーク mogja 2018年6月2日 10:23
    2018年5月13日 2:21

すべての返信

  • 参考にされている記事を見ると SQL インジェクション防止のためのクエリのパラメータ化のことを聞きたいと理解していいのですか? その理解で良ければ・・・

    > MSDNで記載されていますが、皆さん以下のようにベタ書きでプログラムしてるのでしょうか?

    あなたの言う「ベタ書き」とはどういう意味か分かりませんが、それはともかく、あなたが MSDN からコピーした以下のクエリはパラメータ化されています。@username と @password がそれです。

    SELECT AccountNumber FROM Users WHERE Username=@username AND Password=@password

    パラメータ化するならこれ以外の書き方はないです。あなたは上記クエリを「ベタ書き」とか言って何か気に入らないように見えますが、それ以外の書き方がありますか?

    クエリをパラメータ化すると、パラメータの入力はリテラルとして扱われるから SQL インジェクション攻撃を防ぐことができるということは理解してますか?

    そのあたりが不明であれば以下の記事の説明を見てください。

    パラメータ化クエリ
    http://surferonwww.info/BlogEngine/post/2012/02/02/Parameterized-query.aspx

    > SQL少し変えるだけで、毎回コンパイルしないといけないので、

    パラメータ化のもう一つのメリットに「毎回コンパイルしないといけない」ということがなくなるというパフォーマンスの向上があります。

    > app.configなどにクエリを書ければなーと思ってました。

    それは全くの見当違いでしょう。

    2018年5月10日 14:49
  • こんばんは、

    私の C# の経験の中でも、SQL のベタ書きだったものは多かったです。しかし、どの方法が最も良いのか?の答は、そのプログラムの用途や求められる性能、扱うデータ、利用者の規模等の要因によって変わるものだと考えています。

    [1] SQL クエリを直接実行する方法  - これは、スクラッチにおいて機動的に開発できますので、初期の開発フェーズや試験用途では大変有利と思います。Web アプリケーションのように不特定多数の利用者が想定される場合には、特にSQLインジェクションの対策が必要です。この点に関しては、IPA の セキュアプログラミング講座 [6] のプリペアドステートメントの説明が大変参考になります。C#はあまり言及されていませんが、DB 操作一般の視点で一読をおすすめします。

    [2] コンパイル済みクエリ - docs.microsoft.com によると、この方法が最も一般的で、似たようなクエリを繰り返し実行するようなアプリケーションにおいてパフォーマンスも良いと説明されています。個人的には、あまり見たことない印象だったのですが、今度実用してみたいと思う方法です。

    [3] LINQ to SQL - DB をデータソースとして使用したことはないのですが、DB オブジェクトが一定で かつ SQL が複雑に変化するようなパターンでは柔軟な開発ができそうな印象です。PHP:PDO や Perl:DBI のような、いわゆる Web 系言語で使われる方法とも似てるように思います。また、セキュリティの観点でも [1] [2] の方法より優れているかと思います。

    [4] ストアドプロシージャ - DB への問い合わせが一連のトランザクションとして確立されている場合には有効な選択肢と思います。[1] の方法とは対照的に、開発フェーズ初期の段階には向かないと思いますが、トランザクションのACID特性を重視されるようなケースにおいては SQL のベタ書きより断然よいと思います。ご質問の意図から少し脱線しているかもしれませんが、、

    以上、様々な例が考えられますが、状況や環境によって最善の選択とは変化するものと思います。

    [1] 方法 : SQL クエリを直接実行する - docs.microsoft.com
    https://docs.microsoft.com/ja-jp/dotnet/framework/data/adonet/sql/linq/how-to-directly-execute-sql-queries

    [2] 方法 : クエリを格納および再利用する - docs.microsoft.com
    https://docs.microsoft.com/ja-jp/dotnet/framework/data/adonet/sql/linq/how-to-store-and-reuse-queries

    [3] LINQ to SQL - docs.microsoft.com
    https://docs.microsoft.com/ja-jp/dotnet/framework/data/adonet/sql/linq/how-to-connect-to-a-database

    [4] ストアド プロシージャを使用する (C#) - docs.microsoft.com
    https://docs.microsoft.com/ja-jp/dotnet/framework/data/adonet/sql/linq/walkthrough-using-only-stored-procedures-csharp

    [5] クエリの例 - docs.microsoft.com
    https://docs.microsoft.com/ja-jp/dotnet/framework/data/adonet/sql/linq/query-examples

    [6] IPA セキュア・プログラミング講座:IPA 独立行政法人 情報処理推進機構
    https://www.ipa.go.jp/security/awareness/vendor/programming/

    以上です、ご不明な点があればご返信にてお知らせください、


    --- Seiji Momoto

    2018年5月10日 14:55
  • 私の場合、プログラムのコード中に(C#のコード中に)、SQL文を書くことはまずありません。ただ、TableAdapterを利用して同時実行制御のコードを自動的に生成させる場合は除きます。
    では、どこに書くかというとストアドプロシージャに書きます。SQL文もここで動的に組み立てることができますし、SQL文を少し変える場合でもストアドプロシージャ内で変えれば良いので、C#のアプリをコンパイルする必要はありません。また、ストアドプロシージャは実行面でもパフォーマンスが良いです。パラメータを使うのでセキュリティ面でも安心です。(パラメータを使ってもSQL文を内部で動的に組み立てる場合、SQLインジェクションが発生するようなケースがありますので、パラメータを使ったから大丈夫というわけではありません)

    基本的にはストアドプロシージャで作成すること。例外としてTableAdapterで同時実行制御を行わせたい場合はそこにSQLを書くというのが今の私のスタイルです。

    ちなみに本題とは関係ないですが、以下の、

    someCommand.CommandText = "SELECT AccountNumber FROM Users " +
             "WHERE Username=@username AND Password=@password";

    は、逐語的文字列リテラルを使うと以下のように書けます。

    someCommand.CommandText = @"
       SELECT AccountNumber FROM Users
               WHERE Username=@username AND Password=@password
    ";

    逐語的文字列リテラルは、もちろんSQL以外にも使えますので、活用してみて下さい。

    #ちなみにストアドプロシージャ内でselect文で返される項目を変えるなど少し変えた場合でも、それを受け取って処理するC#のコードもおそらく変える必要があると思いますので、コンパイルは必要になりますよ。
    ストアドプロシージャを変えてもC#のコードのコンパイルが必要ないのは、ストアドプロシージャ内で抽出条件を変えるなど、C#でストアドプロシージャの結果を受け取ってからの処理が変わらない場合だけでしょう。


    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    2018年5月11日 0:12
    モデレータ
  • trapemiya さん>

    > 基本的にはストアドプロシージャで作成すること。

    反対意見を一言述べさせてください。

    ストアドのメリットを生かせるのは、ストアドを正しく書いて管理できる知識・スキルを持った人に限った話と思います。

    たとえば、以下のように C# のコードでクエリをパラメータ化すると、

    query ="INSERT INTO [Table] ([Name]) VALUES (@Name)";
    using(SqlCommand cmd = new SqlCommand(query, conn))
    {
        cmd.Parameters.Add(
            new SqlParameter("@Name", SqlDbType.NVarChar, 50));
        cmd.Parameters["@Name"].Value = "かきくけこ";
        cmd.ExecuteNonQuery();
    }
    SQL Server では以下のようなクエリが実行されるはずです。

    exec sp_executesql 
        N'INSERT INTO [Table] ([Name]) VALUES (@Name)',
        N'@Name nvarchar(5)',
        @Name=N'かきくけこ'

    sp_executesql に変換されて実行される点、N プレフィックスがつけられる点に注目してください。

    これと同等のクエリが書ける知識・スキルをどのくらいの人が持っているでしょう?(少なくとも自分にはそこまでの知識はないです。お前にないだけだろうと言われるかもしれませんが)

    その他、C# のコードでパラメータ化するだけで以下のような副次的な効用もあると思います。

    パラメータ化の副次的な効用
    http://surferonwww.info/BlogEngine/post/2016/06/04/use-parameterized-query-to-avoid-unexpected-character-corruption.aspx

    なので、パラメータ化とは何かの基本的なことをまず知って、次に C# のコードでのメリット / デメリットは何かを知るのが先で、その後ストアドを使った方がメリットがあるかを吟味してストアドを使うか否かを決める話という話になるのではと思います。


    2018年5月11日 1:21
  • Seiji Momoto さん>

    レスに書かれている [1] ~ [5] は全て Linq to SQL の話のようです。

    質問者さんが質問に書いた、

    CA2100: セキュリティの脆弱性について、SQL クエリを確認してください
    https://msdn.microsoft.com/ja-jp/library/ms182310.aspx

    のような ADO.NET の SqlCommand を使ったプリミティブなコードを書くのではなく、Linq to SQL を使うことを提案されているのでしょうか?

    2018年5月11日 1:33
  • SurferOnWwwさん>

    あくまで私の場合を述べましたが、根底にはストアドプロシージャを使うことを推薦する下心があることはお見通しかもしれませんね。
    確かにストアドプロシージャは凝れば奥は深いですが、今回のようなストアドプロシージャであれば、そう難しくはないと思いますよ。Nプレフィクスは実行時にパラメータに自動的に付与されます。

    CREATE PROCEDURE GetAccountNumber
    	@username	nvarchar(50),
    	@password	nvarchar(50)
    AS
    BEGIN
    
    	SELECT AccountNumber FROM Users 
             WHERE Username=@username AND Password=@password;
    END
    
    おっしゃる通り、ストアドプロシージャを使うにはその勉強が必要になりますので、スキルが要求されます。
    ですので、どうするかは最終的にポリシーの問題になり、ストアドプロシージャを使う使わないかは自由です。
    ただ、私の経験上、
    ストアドプロシージャ、というよりSQLになりますが、ストアドプロシージャ上でSQLを駆使できるスキルを身に付ければ、C#などのコード側であれこれやる手間も省け、パフォーマンスも良くなります。確かにここまでできるスキルは必要になりますが、その努力に十分見合うものだと思います。

    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    • 回答の候補に設定 huahi11112 2018年5月11日 3:30
    2018年5月11日 2:49
    モデレータ
  • > ストアドプロシージャ上でSQLを駆使できるスキルを身に付ければ、C#などのコード側であれこれやる手間も省け、パフォーマンスも良くなります。確かにここまでできるスキルは必要になりますが、その努力に十分見合うものだと思います。

    その「ストアドプロシージャ上でSQLを駆使できるスキル」というのが大問題で、それを習得するための時間と労力に見合うメリットがあるとすると、以下のようなケースに対応する場合しかなさそうな気がします。(他に、これはというメリットがあれば教えていただけると幸いです)

    (1) アプリと SQL Server のラウンドトリップがボトルネックになっていて、それを解消できる

    (2) セキュリティ対策としてユーザーにはストアドの実行権限しか与えない。

    (3) PIVOT 関係演算子を利用してデータをまとめ、クロス集計レポートを生成。

    多分今回のケースではどれもメリットとはならず、逆に以下のデメリットの方が大きそうです。

    (1) ストアドを作るには、SQL 言語(Transact-SQL)を習得しなけれなばならない。(C# と ADO.NET だけでも大変なのに)

    (2) ストアドの保守・管理に SQL Server にアクセスしなければならない。(Visual Studio の Express 版は既定のインスタンスにアクセスできないなど制約があったりする)

    (3) ADO.NET ライブラリのデフォルト設定がストアド対象ではないので(例:SqlCommand.CommandType プロパティのデフォルトは Text など)コーディングの際注意が必要。

    質問者さんは、

    > 初めてSQLServerに接続して、SQLを実行するようなプログラムを行っているのですが、

    とのことですので、積極的にストアドの使用を勧めるようなことはせず、ストアドという方法もある程度の説明にとどめておいた方がよさそうな気がします。


    • 編集済み SurferOnWww 2018年5月11日 6:00 誤字訂正
    2018年5月11日 5:57
  • 質問者さんへ>

    質問に追記されたようですが気が付きませんでした。レスに対しては、最初の質問の編集ではなく、レスで返してもらえると助かります。

    で、追記の件ですが、最初の話と変わってきていませんか?

    最初の質問の話は、(1) パラメータ化しないでクエリを書いたら警告が出たのでそれに対処したいという話、追記では (2) クエリの文字列をプログラムにハードコーディングしない方法はあるのか・・・という質問になっているようです。

    どっちがメインなのですか?

    少なくとも (1) については私の最初のレスで回答済と思ってますが、その理解で良いですか?

    (2) については、可能と思いますけど、それにどういうメリットがあるのだろうという感じです。

    クエリを差し替えれば、それで取得した情報も変わってくるはずで、取得した情報が変わればそれを処置するコードも変わってきて、結局は、

    > コンパイル無しで後から簡単に変えれないのかなと思ったのです。

    ということは無理そうな気がするのですが。

    具体的にどういうケースがあるのでしょう。全体的なストーリー・シナリオを書けませんか?

    2018年5月11日 6:25
  • (2)がメインで行いたく、そのまま記載すると、警告が出るため、解決方法を探すと、掲題の解決方法が表示されました。

    という流れです。

    以下のように単純にとあるテーブルからDataTableに丸ごと設定するだけなら

    異なるテーブルでも同じ挙動が出来ると思うので、共通化したいのですが

    その場合取得先等を変える必要があるので、コマンド部分を可変にしたいのですが、

    引数で渡したりするようなやり方ですと、CA2100に引っかかるのでどうしたらいいのかなと。

    abstract BaseClass
    {
        DataTable table {get;set;}
        public vertual DataTable GetDataTable(string query)
        {
            string server = Properties.Settings.Default.SqlSever;
                // SQL接続
                using (SqlConnection connection = 
                          new SqlConnection(sqlServerName))
                {
                        connection.Open();
                        using (SqlCommand command 
                                  = new SqlCommand())
                        {
                            command.Connection = connection;
                            command.CommandText = query;
                            using (SqlDataAdapter adapter 
                                      = new SqlDataAdapter(command))
                            {
                                adapter.Fill(table);
                            }
                        }
                }
         }
    }
    
    public SqlClassA : BaseClass
    {
        private static readonly string query = "SELECT*FROM AAA";
        public getData()
        {
            DataTable tbl = null;
            tbl = this.GetDataTable(query);
        }
    }
    
    
    public SqlClassB : BaseClass
    {
        private static readonly string query = "SELECT*FROM ABC";
        public getData()
        {
            DataTable tabel = null;
            tbl = this.GetDataTable(query);
        }
    }

    コンパイル無しでも変えれるという件は例えば、この場合全レコード引っ張ってきますが

    例えば、WHERE等でレコード件数を絞ったりはコンパイルしなくてもできても良いかなと思った次第です。

    2018年5月12日 8:01
  • 言ってることが矛盾していませんか?

    > (2)がメインで行いたく、そのまま記載すると、警告が出るため、解決方法を探すと、掲題の解決方法が表示されました。

    ・・・ということは、質問者さんが最初の質問に書いた MSDN の記事のコードを例に取ると、

    someCommand.CommandText = "SELECT AccountNumber FROM Users " +
                "WHERE Username='" + name + 
                "' AND Password='" + password + "'";

    では SQL インジェクションの恐れがあるからパラメータ化するということだったはずですよね。

    それは、あなたが直近のレスで書いたような "SELECT*FROM AAA" を "SELECT*FROM ABC" に差し替えるという話とはつながらないのですが。

    たとえ警告を無視して上記のクエリの形のまま(パラメータ化しない)としても、単純に SELECT クエリを差し替えるだけで済ませるのは無理では? コードを書き換えて再コンパイルする以外の方法があるのですか?

    DB のテーブル毎にクエリを変えたいということであれば、クエリを差し替えるなどというあまり現実的ではないことは考えず、データーソース構成ウィザードを使って、DB のテーブル毎に型付 DataSet + TableAdapter を作ることをお勧めします。

    【追伸】

    (2) がメインとのことですが、(1) と (2) の両方を考えてどちらが重要かというと、絶対的に (1) の SQL インジェクション対策のためのクエリのパラメータ化です。

    そこのところはきちんと理解してください。(2) のために SQL インジェクション防止という非常に重要なことをやらないなんていうことはあり得ません。



    • 編集済み SurferOnWww 2018年5月12日 11:16 誤字訂正
    2018年5月12日 9:55
  • ご質問の意図を正しく汲み取れていなかったようで、失礼しました。「皆さんどの様にやっているかを教えて頂きたい」の部分を誤って解釈していたようです。

    コード分析規則 CA2100 に焦点をあてた視点で再度、回答させてください。

    既に確認されているかもしれませんが、この CA2100 の規則は次のような根拠が説明されています。

    > この規則では、文字列引数にユーザー入力が含まれていることが想定されています。 ユーザー入力から構築された SQL コマンド文字列には、SQL 注入攻撃に対する脆弱性があります。

    [1] CA2100: Review SQL queries for security vulnerabilities
    https://docs.microsoft.com/ja-jp/visualstudio/code-quality/ca2100-review-sql-queries-for-security-vulnerabilities

    コード分析において、セキュリティの警告が出てしまうのは、 Microsoft マネージドコード推奨規則と「SELECT~等の記載をプログラム内部で持たせたくない」という考え方が相反しているためです。

    「皆さんどの様にやっているか」に対して改めて回答させていただくならば、少なくとも Microsoftのコード分析規則を準拠する開発者の中では、
    他の回答者からも既に回答されている方法(SQL の基本構文部分にユーザー入力を含ませない)を選択するのが多数派と思われます。

    ご返信の中のご質問「CA2100に引っかかるのでどうしたらいいのか」に対しては、対象のプログラムのみ、コード分析の規則セットを変更することで警告を非表示にすることができます(ルール CA2100 のチェックを外す)。規則セットの変更方法は次のリンクで説明されています:

    [2] 方法: マネージ コード プロジェクトのコード分析を構成する
    https://docs.microsoft.com/ja-jp/visualstudio/code-quality/how-to-configure-code-analysis-for-a-managed-code-project

    [3] カスタム規則セット
    https://docs.microsoft.com/ja-jp/visualstudio/code-quality/how-to-create-a-custom-rule-set

    また、SQL にユーザー入力を含ませながら、かつコード分析標準規則に違反しない1つの方法として、C# プログラムから .sql ファイルを SQLCMD.EXE に引き渡して実行する、という方法もあります。ここで「違反しない」とは、コード分析の隙間を潜り抜けているだけであって、規則の本質に準拠していません。

    例えば、以下のコード例は標準規則のコード分析に違反しません(そして、明らかに標準的な使用方法ではありません)
    string cmd = @"{SQL_SERVER_ROOT}\Tools\Binn\SQLCMD.EXE";
    string sql = @"{APP_ROOT}\transaction.sql";
    string arguments = String.Format("-S {SERVERNAME} -U {USERNAME} -P {PASSWORD} -i \"{0}\"", sql);
    
    System.Diagnostics.ProcessStartInfo procStartInfo =
        new System.Diagnostics.ProcessStartInfo(cmd, arguments);
    procStartInfo.RedirectStandardOutput = true;
    procStartInfo.UseShellExecute = false;
    procStartInfo.CreateNoWindow = true;
    System.Diagnostics.Process proc = new System.Diagnostics.Process();
    proc.StartInfo = procStartInfo;
    proc.Start();
    string result = proc.StandardOutput.ReadToEnd();
    Console.WriteLine(result);

    以上は、提案を意味するものではなく、ご質問に対する単純な回答です。回答として余計な意見と承知していますが、この CA2100 について、私は良い規則であるように思います。


    --- Seiji Momoto

    • 回答としてマーク mogja 2018年6月2日 10:22
    2018年5月12日 17:48
  • Seiji Momoto さん>

    質問は、

    (1) パラメータ化しないでクエリを書いたら警告が出たのでそれに対処したい, and

    (2) クエリの文字列をプログラムにハードコーディングしない方法はあるのか

    ・・・というということで、質問者さんとしては (2) がメインと理解しています。(Seiji Momoto さんの理解が違うなら、どこがどう違うのかを書いてください)

    > コード分析規則 CA2100 に焦点をあてた視点で再度、回答させてください。

    ということは (1) に対してのみ回答を書いたということでしょうか? そうだとしても、書かれたレスの中のどの部分が回答になっているか分かりませんでした。

    「他の回答者からも既に回答されている方法」とは具体的にどういうものでしょう?

    「警告を非表示にする」というのが回答ではないですよね?


    • 編集済み SurferOnWww 2018年5月13日 1:45 訂正
    2018年5月13日 1:44
  • 質問者さん>

    先の私のレスで、

    > データーソース構成ウィザードを使って、DB のテーブル毎に型付 DataSet + TableAdapter を作ることをお勧めします。

    ・・・と書きましたが、その作り方を書いた記事を紹介しておきます。

    7.6 データコンポーネント機能によるデータアクセスコンポーネントの開発
    http://www.atmarkit.co.jp/fdotnet/bookpreview/vs2005webapp_07/vs2005webapp_07_01.html

    上記は ASP.NET Web アプリの記事ですが型付 DataSet + TableAdapter に関しては Web アプリに限らず共通です。

    この記事が、自分の知る限りでは一番まとまっていてわかりやすかったと思っています。

    VS2008 からは(上の記事は VS2005)TableAdapterManager も自動生成されるようになり、それを使っての階層更新も可能になっています。

    10 行でズバリ !! 非接続型のデータ アクセス (ADO.NET) (C#)
    https://code.msdn.microsoft.com/windowsdesktop/10-ADONET-C-cbfe7688

    今回の話とは直接の関係はないですが、ご参考まで。

    • 回答としてマーク mogja 2018年6月2日 10:23
    2018年5月13日 2:21
  • 回答を見ながらいろいろ確認中です。

    確認完了終わり次第対応させてください

    2018年5月21日 10:37
  • 回答を見ながらいろいろ確認中です。

    確認完了終わり次第対応させてください

    きちんと確認結果と対応を書いてください。「回答としてマーク」を付けて終わりにするのは、回答者やこのスレッドを見ている閲覧者にとって十分な情報を提供しているとは言えません。

    このフォーラムは技術者同志の情報共有の場所として提供されているそうですので、このフォーラムで質問する以上、質問者さんにも情報提供に協力いただけると幸いです。

    2018年6月2日 10:32
  • フォーラム オペレーターの栗下 望です。
    mogja さん、こんにちは。
     
    既に SurferOnWww さんからお話しが出ていますが、
    確認が終わられましたら、確認されたことや対応された結果を共有いただき、
    同じ問題でお困りの方へ情報をご提供いただけますと幸いです。
     
    重ねてのお願いとなり恐縮ですが、
    ご協力の程、どうかよろしくお願いいたします。

    参考になった投稿には回答としてマークの設定にご協力ください
    MSDN/TechNet Community Support 栗下 望

    2018年6月4日 9:41
    モデレータ
  • 結論を書きますと、解決はしませんでした。

    が、DataSet + TableAdapterが参考になりました。

    作りとしてこうした方が良い。というのはDataSet+TableAdapterを使った方が

    非常に簡単にDBからデータを取得出来るのですが

    ・接続先と、クエリを全てテキストで外から書き換えれるようにすると上記では難しいと感じました。

    恐らく、上記のような使い方がそもそも今の時代にあっていないので、使い方を見直す必要があるというのが

    解決だと思いますが、それは出来ないので、この質問としては使い方を見直しましょうという事だと思います。

    2018年6月5日 3:19
  • mogja さん、こんにちは。フォーラム オペレーターの立花です。
    MSDN フォーラムをご利用くださいましてありがとうございます。

    また、結果をご共有くださいまして重ねてお礼申し上げます。

    解決することはできなかったとのことで残念ですが、
    参考となる情報を得られたとお伺いできうれしく思っております。

    情報をご提供くださいました皆様も誠にありがとうございました。
    今後とも MSDN/TechNet フォーラムをどうぞよろしくお願いいたします。


    参考になった投稿には回答としてマークの設定にご協力ください
    MSDN/TechNet Community Support 立花楓

    2018年6月5日 4:00
    モデレータ