web-dev-qa-db-ja.com

C#でMS SQL Serverからデータをクエリするためのベストプラクティス?

C#でMS SQL Serverからデータを照会する最良の方法は何ですか?

コードにSQLクエリを含めることはお勧めしません。

ストアドプロシージャを作成し、パラメーターを使用してC#から呼び出すのに最適な方法は何ですか?

using (var conn = new SqlConnection(connStr))
using (var command = new SqlCommand("StoredProc", conn) { CommandType = CommandType.StoredProcedure }) {
   conn.Open();
   command.ExecuteNonQuery();
   conn.Close();
}
9
Bruno

ストアドプロシージャの使用は1つの方法であり、長年にわたって広く使用されています。

C#(または任意の.NET言語)からSQL Serverデータベースを操作するより現代的な方法は、Entity Frameworkを使用することです。 Entity Frameworkの利点は、より高いレベルの抽象化を提供することです。

Microsoftから引用するには( https://msdn.Microsoft.com/en-us/data/jj590134 ):

ADO.NET Entity Frameworkを使用すると、開発者は、リレーショナルストレージスキーマに対して直接プログラミングするのではなく、概念的なアプリケーションモデルに対してプログラミングすることにより、データアクセスアプリケーションを作成できます。目標は、データ指向のアプリケーションに必要なコードとメンテナンスの量を減らすことです。 Entity Frameworkアプリケーションには、次の利点があります。

  • アプリケーションは、継承を伴う型、複雑なメンバー、関係など、よりアプリケーション中心の概念モデルの観点から機能します。
  • アプリケーションは、特定のデータエンジンまたはストレージスキーマへのハードコードされた依存関係から解放されます。
  • 概念モデルとストレージ固有のスキーマの間のマッピングは、アプリケーションコードを変更せずに変更できます。
  • 開発者は、さまざまなデータベース管理システムに実装されている可能性があるさまざまなストレージスキーマにマップできる、一貫したアプリケーションオブジェクトモデルを使用できます。
  • 複数の概念モデルを単一のストレージスキーマにマッピングできます。
  • 言語統合クエリ(LINQ)サポートは、概念モデルに対するクエリのコンパイル時の構文検証を提供します。

ORMとストアドプロシージャの使用には、特にセキュリティとロジックが存在する場所の点でトレードオフが伴います。

SQL Serverを使用した開発に対する「クラシック」なアプローチは、アプリケーションロジックをストアドプロシージャとプログラムに常駐させることであり、ストアドプロシージャを実行するためのセキュリティ権限のみが与えられ、テーブルを直接更新することはできません。ここでの概念は、ストアドプロシージャはアプリケーションのビジネスロジックレイヤーであるということです。理論は確かですが、さまざまな理由で好意から外れる傾向があり、C#やVBなどのプログラミング言語でビジネスロジックを実装することで置き換えられています。優れたアプリケーションは、懸念の分離などを含む段階的なアプローチで実装されますが、MVCのようなパターンに従う可能性が高くなります。

データベースではなくORMにロジックを実装することの欠点の1つは、データベースの責任者(DAまたはDBA)がデータ整合性ルールを簡単にデバッグおよびテストできることです。小切手から普通預金口座への送金の典型的な例を取り上げます。これは、アトミックな作業単位として、つまりトランザクションに挟まれて行われることが重要です。この種の転送がストアード・プロシージャーを介してのみ許可されている場合、DAおよび監査員がストアード・プロシージャーをQAするのは比較的簡単です。

一方、これがEntity FrameworkのようなORMを介して行われ、本番環境では、まれにチェックからお金が奪われるが節約につながらないことが発見された場合、特に複数のプログラムが潜在的に関与している場合は、デバッグがはるかに複雑になる可能性があります。これはおそらくエッジのケースであり、おそらく特定のシーケンスで発生する必要のある特有のハードウェアの問題などが関係しています。これをテストするにはどうすればよいですか?

10
JonnyBoats

実際、基本的なアサーションは議論の余地があります。コードにSQLを含めるか、データベース(コードをストアードプロシージャに移行させるか)にコードを含めるかにはトレードオフがあります。

その結果、単一の「ベスト」は存在しないということです。これは、どの方法を使用しても妥協しているため、一般化できるものではありません(利点を得るだけでなく、制約も導入します)。

アプリケーションとデータベースの間に1対1の対応がある場合、それは本当に重要ではありません。一方、大規模なコアデータベースを多数のアプリケーションで共有している場合は、それらのアプリケーション間でデータベース内の整合性を確保することがより重要になります。

さらに重要なことは、アプリケーションのアーキテクチャと階層化について心配することです。エンティティフレームワークやNHibernateのようなORMを使用するか、より直接的なことを行うかによって、クエリを構築するかどうかに関係なく、アプリケーションのほとんどをこの決定から分離する必要があるかどうかまたはストアドプロシージャを使用します。


私は自由に小さなチーム(1〜3人の開発者)がいる比較的小さなプロジェクトに取り組む傾向があります-アプリケーション(および私のスキルセット)の性質を考慮して、ストアドプロシージャを使用すると、その価値よりも問題が多くなります。コードは一般にスキーマの更新よりもはるかに簡単で(スキーマを比較的簡単に更新できるコードを使用できる場合でも)、一般的なデータアクセスコードを使用してビジネスルールを適用できます。これは明らかに「Your Mileage May Vary」の典型的な例です。

6
Murph

入力をパラメーター化している限り、どのアプローチも有効です。多くのライブラリがステートメントを一緒に文字列に追加することを余儀なくされ、SQLインジェクション攻撃が行われたのは、古くからのコード引数にクエリがないクエリのほとんどです。

4
Bill

ここでのベストプラクティスは誇張されています。それを行うには多くの優れた方法があり、実際に選択する方法は、アプリの内容と実行する必要のあるものに依存するはずです。とはいえ、本当に間違ってできることは2つしかありません。

  • @Billが指摘するように、クエリは常にパラメーター化する必要があります。文字列の構築は、SQLインジェクションの簡単なベクトルであり、バグの追跡が困難なあらゆる方法です。はるかに賢い人々がSQLをtupelizeしてエスケープする方法を理解したので、自分でそれを理解する必要はありません。

  • 接続を閉じます。最善の方法は、usingステートメントをすべてラップすることですが、ボートをフロートさせる場合、try/catch /最終的にもクールです。ただし、安価な車のような接続を使用するようにしてください。強くて速く運転して、すぐに取り除きます。

私が激しく主張するもう1つの方法は、データアクセスコードをできるだけ少ない場所に集中させることです。フロントエンドWebアプリがSystem.Data.SqlClientへの直接参照を保持してこの警告を強制することを許可しません。

0
Wyatt Barnett