web-dev-qa-db-ja.com

マイクロORMがあるため、インラインSQLは依然として悪い習慣として分類されていますか?

これは少し自由回答式の質問ですが、インラインSQLスクリプトが標準である世界で育ったので、私はいくつかの意見を求めていました。それで、SQLインジェクションに基づく問題と、SQLがいかに脆弱であるかについて、私たちは皆気づかされました。あらゆる場所で文字列操作を行います。

次に、ORMの夜明けが来て、ORMにクエリを説明し、それが独自のSQLを生成するようにしました。多くの場合、これは最適ではありませんしかし、安全で簡単でした。 ORMまたはデータベースアブストラクションレイヤーのもう1つの良い点は、SQLがデータベースエンジンを念頭に置いて生成されたため、MSSQL、MYSQLでHibernate/Nhibernateを使用でき、コードが変更されたことはなく、構成の詳細にすぎませんでした。

マイクロORMがより多くの開発者に勝っているように見える今日に早送りします。なぜインラインSQLテーマ全体にUターンをしたのかと思っていました。

私はORM構成ファイルがなく、クエリをより最適な方法で記述できることを気に入っていることを認めなければなりませんが、SQLインジェクションなどの古い脆弱性に立ち直りつつあり、また、 1つのデータベースエンジンなので、ソフトウェアで複数のデータベースエンジンをサポートする場合は、文字列ハッカーをさらに実行する必要があります。これにより、コードが読みにくくなり、壊れやすくなります。 (誰かが言及する直前に、ほとんどの場合SQLインジェクションからの保護を提供するほとんどのマイクロオームでパラメーターベースの引数を使用できることを知っています)

では、このようなことについての人々の意見は何ですか?このインスタンスでは、マイクロORMとしてDapperを使用し、このシナリオでは通常のORMとしてNHibernateを使用していますが、各フィールドのほとんどは非常に似ています。

inline sqlと呼んでいるのは、ソースコード内のSQL文字列です。かつては、ロジックの基本的な意図を損なうソースコードのSQL文字列に関する設計の議論がありました。そのため、静的に型付けされたlinqスタイルのクエリが非常に人気を博したのは、まだ1言語だけですが、C#とSQLが1ページにあるとしましょう生のソースコードに2つの言語が混在しています。明確にするために、SQLインジェクションはsql文字列の使用に関する既知の問題の1つにすぎません。パラメーターベースのクエリでこれが発生しないようにできることはすでに述べましたが、SQLクエリがソースコードに組み込まれていることによる他の問題についても強調します。 DBベンダーの抽象化の欠如、および文字列ベースのクエリでのあらゆるレベルのコンパイル時エラーキャプチャの喪失。これらはすべて、HQLやLINQなどのより高いレベルのクエリ機能を備えたORMの黎明期を回避できたすべての問題です。 (すべての問題ではなく、ほとんどの問題)。

したがって、ほとんどのMicro ORMがこのメカニズムを使用しているため、個々の強調表示された問題に焦点を当てるのではなく、より大きな全体像として、SQLコードを再びソースコードに直接含めることが受け入れられるようになりました。

以下は、いくつかの異なる視点を持つ同様の質問ですが、micro ormコンテキストのないインラインSQLについての詳細です。

https://stackoverflow.com/questions/5303746/is-inline-sql-hard-coding

27
Grofit

「インラインSQL」として記述しているものは、実際には「パラメータ化なしの文字列連結」と呼ばれるべきであり、Micro ORMを安全に使用するためにそうする必要はありません。

このDapperの例を考えてみましょう:

_string sql = "SELECT * from user_profile WHERE FirstName LIKE @name;";
var result = connection.Query<Profile>(sql, new {name = "%"+name+"%"});
_

文字列の連結が行われている場合でも、完全にパラメーター化されています。 @記号を参照してください。

またはこの例:

_var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", 
          new { Age = (int?)null, Id = guid });
_

これは、次のADO.NETコードとほぼ同じです。

_List<Dog> dog = new List<Dog>();
using(var cmd = connection.CreateCommand()) {
    cmd.CommandText = "select Age = @Age, Id = @Id";
    cmd.Parameters.AddWithValue("Age", DBNull.Value);
    cmd.Parameters.AddWithValue("Id", guid);
    using(var reader = cmd.ExecuteReader()) {
        while(reader.Read()) {
            int age = reader.ReadInt32("Age");
            int id = reader.ReadInt32("Id");
            dog.Add(new Dog { Age = age, Id = id });
        }
    }
}
_

これ以上の柔軟性が必要な場合、DapperはSQLテンプレートとAddDynamicParms()関数を提供します。すべてのSQLインジェクションは安全です。

では、なぜ最初からSQL文字列を使用するのでしょうか。

同じ理由で、他のORMでカスタムSQLを使用することになります。たぶん、ORMはコード生成の準最適SQLであり、最適化する必要があります。たぶん、UNIONのように、ネイティブでORMで行うのが難しいことをしたいかもしれません。または、単にこれらすべてのプロキシクラスを生成する複雑さを回避したいだけかもしれません。

Dapperのすべての [〜#〜] crud [〜#〜] メソッドに対してSQL文字列を書きたくない場合は、次のライブラリを使用できます。

https://github.com/ericdc1/Dapper.SimpleCRUD/

これにより、非常にシンプルで簡単なCRUDが得られると同時に、手書きのSQLステートメントの柔軟性も得られます。上記のADO.NETの例は、ORMが登場する前に誰もがそうであった方法を思い出してください。 Dapperはその上にある薄いベニアです。

31
Robert Harvey

私はsqlが大好きで、文字列リテラルで途切れるのを我慢できなかったので、実際のsqlファイルで作業できるように、VS拡張機能を少し書きましたC#プロジェクトで。独自のファイルでsqlを編集すると、列とテーブル、構文検証、テスト実行、実行計画などのインテリセンスが得られます。ファイルを保存すると、拡張機能によってc#ラッパークラスが生成されるので、接続コード、コマンドコード、パラメーターまたはリーダーコードの行を記述する必要はありません。他に方法がないため、クエリはすべてパラメーター化され、入力パラメーターと結果にインテリセンスを使用して、ユニットテスト用のリポジトリとPOCOを生成しました。

そして、私は無料のステーキナイフを投入しました...エキスパートが開発者のSQLを修正する必要があるとき、彼女は実際のSQLファイルを見ており、C#に手を加える必要はありません。彼女が戻ってDBを片付け、一部の列を削除すると、欠落している列への参照がc#のコンパイルエラーとしてすぐに飛び出します。データベースは、ハッキングできるソリューションの別のプロジェクトのようになり、コードで検出可能なインターフェイスになります。ソリューションがコンパイルされると、すべてのクエリが機能していることがわかります。無効なキャストまたは無効な列名、または無効なクエリによる実行時エラーはありません。

職場でまだ使用しているdapperを振り返ってみると、2016年にこれがデータアクセスの中で最もクールなものであるとは信じられません。ランタイムmsilの生成はすべて巧妙ですが、すべてのエラーはランタイムエラーであり、他の目的での文字列操作と同様に、文字列操作は時間がかかり、壊れやすく、エラーが発生しやすくなります。そして、POCOで列名を繰り返す必要があるのはどうして乾燥してしまうのでしょうか。

さあ、行きます。あなたが余暇に働いている前代未聞の開発者からの知られていないデータアクセステクノロジーを見たい場合(幼い子供と他の多くの趣味と)、ここにあります

2
bbsimonbb

パラメータ化されたクエリとリポジトリ設計パターンにより、クエリへの入力を完全に制御して、インジェクション攻撃を防ぐことができます。この場合のインラインSQLは、大規模で複雑なクエリの読みやすさ以外の問題ではありません。

1
Kyle J V