Micro ORMが導入された今、インラインSQLは依然として悪い習慣に分類されていますか?


26

これは少し自由な質問ですが、インラインSQLスクリプトが標準である世界で育ったので、私はいくつかの意見が欲しかったので、SQLインジェクションに基づく問題と、SQLがどれほど脆弱であるかをすべて非常に認識しましたあらゆる場所で文字列操作を行います。

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

マイクロORMがより多くの開発者を獲得しているように見える今日に早送りします。なぜインラインSQLの主題全体でU-Turnを採用したように見えるのか疑問に思いました。

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

それでは、この種のことについての人々の意見は何ですか?この例ではDapperをMicro ORMとして使用し、NHibernateをこのシナリオでは通常のORMとして使用していますが、各フィールドのほとんどは非常によく似ています。

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

したがって、私は個々の強調された問題にはあまり焦点を当てておらず、より大局的には、ほとんどのマイクロORMがこのメカニズムを使用するため、ソースコードに直接SQL文字列を含めることがより受け入れられるようになりました。

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

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


1
意見を求めないように質問を言い換えることができると思いますか?意見のポーリングは、Stack ExchangeのQ&A形式にうまく適合しません。

「Micro ORM」クエリはいつでも別のクラスに抽象化できます。必要に応じて、DBMSの変更に応じて実行中のクエリを交換します。
CodeCaster

「マイクロORM」という用語を聞いたことがない。SQLを完全に引き継ごうとしないORMを意味しますか?
ハビエル

気にしないで、少しグーグルで調べた後、.netのように思えます。
ハビエル

1
@GrandmasterB:答えで理由を説明してください。私はそれがトレードオフの問題であると信じているので、私は答えでその問題をほとんど回避しました。
ロバートハーベイ

回答:


31

「インライン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はその上に薄いベニアです。


良い例です。パラメーターを介してSQLインジェクションを回避できることは既に述べましたが、これは大きな質問のほんの一部であり、インラインsqlという用語を使用する場合の意味を明確にする編集も追加しました。
Grofit

回答に詳細を追加しました。
ロバートハーベイ

2
SimpleCRUDに関する情報の+1は、これが存在することを知りませんでした。
-Grofit

Javaでは、あなたは見つけるでしょうMyBatisの休止状態またはEclipseLinkはとよりligtherです。その方法は、(コードのハードコーディングの代わりに)XMLの事前定義された文によるものです。また、最終的なSQLを強化するための前提条件としていくつかの興味深い機能を追加します。最近、同時実行性が非常に高く、ビジネスが複雑ではないAPI Webに使用しました。
ライヴ

2

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

そして、私は無料のステーキナイフを投入しました...専門家が来て開発者のsqlを作り直す必要があるとき、彼女は本物のsqlファイルを見ており、C#に触れる必要はありません。彼女が戻ってDBを整理し、いくつかの列を削除すると、欠落している列への参照がc#のコンパイルエラーとしてすぐに飛び出します。データベースは、ソリューション内でハッキングできる別のプロジェクトのようになり、コードで検出可能なインターフェイスになります。ソリューションがコンパイルされると、すべてのクエリが機能していることがわかります。無効なキャスト、無効な列名、または無効なクエリによる実行時エラーはありません。

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

それであなたは行き​​ます。暇なときに働いている前代未聞の開発者(幼い子供や他の趣味がたくさんある)の未知のデータアクセステクノロジーをご覧になりたい場合は、こちらをご覧ください


あなたは小さな「革新」の多くを考えているように見えますが、これは、たとえばEntity FrameworkのExecuteStoreQueryExecuteStoreCommandとどう違うのでしょうか?
ロバートハーヴェイ

私はEFやSQLの議論に参加していません。私のことは、SQLを使いたい人向けです。SQLを実行する方法として、ExecuteStoreQuery()はPOCOを埋めますが、物事の見た目でPOCOを定義する必要がありますか?また、SQLをファイルに追加したり、パラメーターを作成したりするのに役立ちません。クエリはコード内で発見できないか、テストできません。列を削除しても、アプリケーションでコンパイルエラーは発生しません。私は続けることができますが、私は自分自身を繰り返しているのではないかと心配しています:-)おそらく、YouTubeのビデオを見るのに3分かかるかもしれません。フランス語で、音を小さくします!英語が来ます。
bbsimonbb

EFはすべてのPOCOを自動的に生成できます。ここに何が欠けていますか?DapperとMassiveの真の革新は、POCOがまったく必要ないことです。あなただけを使用することができますdynamic
ロバートハーヴェイ

EFについてはほとんど何も知りません。ExecuteStoreQuery()はエンティティを埋めます。それは実体を生成しますクエリから。エンティティは、クエリからではなく、DBオブジェクトから生成されます(またはその逆)。クエリが既存のエンティティに対応していない場合、POCOを記述する必要がありますか?
bbsimonbb

1
:-)私は自分の最高のアイデアを自由に出しているとき、広告の料金に敏感だと言わなければなりません。これが私の最新の積極的な商業主義です。3分経過するまでに、私が何かに夢中かどうかを知る必要があります。
-bbsimonbb

1

パラメータ化されたクエリとリポジトリ設計パターンにより、クエリの内容を完全に制御して、インジェクション攻撃を防止できます。この場合のインラインSQLは、大規模で複雑なクエリの可読性以外の問題ではありません。クエリはとにかくストアドプロシージャに存在する必要があります。

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