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


9

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

8
「コードにSQLクエリを含めることはお勧めできません。」-イモ、それはナンセンスだ。
GrandmasterB 2012年

4
usingブロックで作成した場合は、conn.Close()を呼び出す必要はありません。usingブロックの重要な点は、C ++スタイルのデストラクタクリーンアップを模倣することです。より文明的な時代からのエレガントな片付け。try-catchスタイルほどランダムでも不器用でもありません。
Tydus卿12

2
ご参考までに。ストアドプロシージャも "コード"です。ストアドプロシージャの目的は、手続き型コードとセットベースのスタイルSQLを混在させることでした。したがって、コードにクエリは関係ありません。非常に大量のアプリの場合、サーバーを追加して水平方向のスケーリングを可能にするために、データベースの外部でロジックを実行する方が良い場合があります。単一のDBを維持できるが、ロジック用のマルチサーバーであれば、スケーリングがはるかに簡単になります。
Tydus卿、12

@GrandmasterB C#にはかなりの量のSQLインラインがあります(C#のLOCは現在200万近くです)。6年後には、インラインSQLを追跡する必要があるため、再びSQLの専門家を雇いました。 -パフォーマンスの微調整を行っています)。私を信じてください。あなたのアプリがどれほど大きくなるか、そして物事が将来どのように変化するかは決してわかりません。さまざまなファイルにさまざまな言語を保持します-リソースをマニフェストに委任するだけでも。// SQLCODEそれもできますが、そうすることを覚えておく必要があります。
ジョナサンディキンソン

1
@JonathanDickinson、必要に応じてストアドプロシージャを使用します。同じデータベースに対して異種のコードベースが動作している場合に、それらが有用であると何度も言ってきました。しかし、それらがいくつかの状況で役立つからといって、自動的に常に「悪い習慣」を使用しないわけではありません。SQLステートメントを直接使用しても問題が発生しない場合は、そのアプリの「悪い習慣」ではありません。
GrandmasterB 2012年

回答:


10

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


または他のORM。それらの多くがあり、EFと比較すると、さまざまな利点と欠点があります。
スビック

8
ORMの不利な点を列挙すると、この回答がより有用になります。
Den

6

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

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

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

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


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


2
+1は「1つも最善ではない」、コードをデプロイする場合は-1はストアドプロシージャの変更をデプロイするよりも簡単です。+ 1は、アプリにとって意味のあるアプローチを選択してDALを確実に分離するためです。+ 1です。
Joel Brown

展開ビットを "for me"で修飾しました。これは一貫して(特にWebアプリケーションの場合)当てはまることです。そのため、その領域で少し書き換えられる可能性があります。
Murph、2012年

+1、何が最適かはアプリケーションと状況に依存します。
GrandmasterB 2012年

1
それはあなたが働いている条件に依存すると思います。DBAがあなたをプロダクションからロックしていない場合、データベースに置換ストアドプロシージャをドロップするのは驚くほど簡単です。さらに言えば、プロダクションコントロールがなければ、新しいマークアップ、スクリプト、さらにはコンパイルされた新しいコードを一元管理されたアプリにドロップすることも、非常に簡単です。
Joel Brown

@JoelBrown-正確に-私はそうだと思います、いいえ、私はそこに仮定の全体を作ったと確信しています。まず、私のスキーマはバージョン管理されています(大雑把ですが効果的な方法で)。私はdbaではありませんが、自分のスキーマが一貫している必要があることを知っているほど賢いです。私は主にWebアプリで作業しており、サーバーにアクセスする以外にデータベースにアクセスすることはできませんが、アプリの展開を(多かれ少なかれ)1つのボタンクリックに減らしています...スキーマの更新を上記に統合しています展開はリストに含まれていますが、スキーマの更新はコードの更新よりもストレスが多い(ロールバックの容易さ?)といつも感じてました
Murph

4

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


1
パラメータ化は十分ですか?あなたも同様に消毒する必要はありませんか?
StuperUser 2012年

ソースと目的によって異なります。私は文字通り彼の質問を受けました、彼はいくつかのパラメーターで読み取り専用です。一般的なケースでは、適切にパラメーター化されて型例外が発生したり、入力が不適切な結果が得られなかったりした場合に、ダーティー入力で行う最悪のケースです。ソースを信頼できるものとして扱わない限り、挿入は異なり、通常は検証が必要です。
Bill

0

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

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.