Dapper.NET
パラメータ構文リファレンス
サーチ…
パラメーター
パラメータ | 詳細 |
---|---|
this cnn | 基礎となるデータベース接続 - this は拡張メソッドを示します。接続が開いている必要はありません。開いていなければ自動的に開閉します。 |
<T> / Type | (オプション)返すオブジェクトの型。非ジェネリック/非Type APIが使用されてdynamic 場合は、クエリごとに返される列名ごとに名前が付けられたプロパティをシミュレートするdynamic オブジェクトが行ごとに返されます(このdynamic オブジェクトはIDicionary<string,object> も実装しIDicionary<string,object> )。 |
sql | 実行するSQL |
param | (オプション)含めるパラメータ。 |
transaction | (オプション)コマンドに関連付けるデータベーストランザクション |
buffered | (オプション)リストにデータを事前に消費するかどうか(デフォルト)、開いているIEnumerable をライブリーダーで公開するか |
commandTimeout | (オプション)コマンドで使用するタイムアウト。指定されていない場合、 SqlMapper.Settings.CommandTimeout が指定されているとみなされます。 |
commandType | 実行されるコマンドのタイプ。デフォルトはCommandText |
備考
パラメータを表現するための構文は、RDBMSによって異なります。上記のすべての例では、SQL Server構文、つまり@foo
使用しています。しかし、 ?foo
と:foo
もうまく動作するはずです。
基本的なパラメータ化されたSQL
Dapperを使用すると、完全にパラメータ化されたSQLを使用してベストプラクティスを簡単に実行できます。
パラメータは重要なので、大まかにそれを正しく取得することができます。あなたは自分のRDBMSのための通常の方法であなたのパラメータを表現する(通常は@foo
、 ?foo
または:foo
)と呼ばれるメンバー持つオブジェクトDapperの与えるfoo
。これを行う最も一般的な方法は、匿名型です:
int id = 123;
string name = "abc";
connection.Execute("insert [KeyLookup](Id, Name) values(@id, @name)",
new { id, name });
以上です。 Dapperは必要なパラメータを追加し、すべてが機能するはずです。
オブジェクトモデルの使用
既存のオブジェクトモデルをパラメータとして使用することもできます。
KeyLookup lookup = ... // some existing instance
connection.Execute("insert [KeyLookup](Id, Name) values(@Id, @Name)", lookup);
Dapperはcommand-textを使ってオブジェクトのどのメンバーを追加するかを決定します。 Description
、 IsActive
、 CreationDate
ような不必要なものは通常追加しません。これは明らかに発行したコマンドには関係しません。例えば、あなたのコマンドに以下のものが含まれているとします。
// TODO - removed for now; include the @Description in the insert
上記は単なるコメントであることを理解しようとはしません。
ストアドプロシージャ
ストアドプロシージャのパラメータは全く同じになりますが、dapperは何を含むべきか/含まないべきかを判断できません。利用可能なものはすべてパラメータとして扱われます。そのため、通常は匿名型が優先されます。
connection.Execute("KeyLookupInsert", new { id, name },
commandType: CommandType.StoredProcedure);
バリューインライン化
場合によっては、保守性や表現力の面でパラメータの利便性が、パラメータとして扱うための性能のコストよりも凌駕されることがあります。たとえば、ページサイズが構成設定によって固定されている場合などです。または、ステータス値がenum
値と一致しています。検討してください:
var orders = connection.Query<Order>(@"
select top (@count) * -- these brackets are an oddity of SQL Server
from Orders
where CustomerId = @customerId
and Status = @open", new { customerId, count = PageSize, open = OrderStatus.Open });
実際の唯一のパラメータはcustomerId
。他の2つは実際には変更されない疑似パラメータです。これらを定数として検出すると、RDBMSはしばしばより良い仕事をすることができます。 Dapperには、 @name
{=name}
代わりに - {=name}
という特殊な構文があります。これは数値型にのみ適用されます。 (これにより、SQLインジェクションからの攻撃面が最小限に抑えられます)。例は次のとおりです。
var orders = connection.Query<Order>(@"
select top {=count} *
from Orders
where CustomerId = @customerId
and Status = {=open}", new { customerId, count = PageSize, open = OrderStatus.Open });
Dapperは、SQLを発行する前に値をリテラルに置き換えるので、RDBMSは実際に次のように見えます。
select top 10 *
from Orders
where CustomerId = @customerId
and Status = 3
これは、RDBMSシステムがより良い意思決定を行うだけでなく、実際のパラメータが回避するクエリプランを開くときに特に便利です。たとえば、列述語がパラメータに対抗する場合、その列に特定の値を持つフィルタされた索引は使用できません。これは、 次の照会に、指定された値の1つから離れたパラメーターがある可能性があるためです。
リテラル値では、クエリオプティマイザは、将来のクエリで値が変更できないことがわかっているので、フィルタされたインデックスを使用できます。
リスト展開
データベースクエリの一般的なシナリオはIN (...)
です。ここでのリストは実行時に生成されます。ほとんどのRDBMSにはこのための優れたメタファーがありません。これには汎用のクロスRDBMSソリューションはありません。代わりに、dapperは穏やかな自動コマンド拡張を提供します。必要なのは、 IEnumerable
提供されるパラメータ値です。 @foo
を含むコマンドは、 (@foo0,@foo1,@foo2,@foo3)
(4つのアイテムのシーケンスに対して)展開されています。これの最も一般的な使用法はIN
です。
int[] orderIds = ...
var orders = connection.Query<Order>(@"
select *
from Orders
where Id in @orderIds", new { orderIds });
これは自動的に展開され、複数行フェッチの適切なSQLが発行されます。
select *
from Orders
where Id in (@orderIds0, @orderIds1, @orderIds2, @orderIds3)
@orderIds0
などのパラメータが@orderIds0
から取得された値として追加されます。この機能が誤って使用されていないことを確認するために、有効なSQLではないという事実は意図的なものです。この機能は、SQL ServerのOPTIMIZE FOR
/ UNKNOWN
クエリヒントでも正しく動作します。あなたが使用する場合:
option (optimize for
(@orderIds unknown))
これを正しく展開します:
option (optimize for
(@orderIds0 unknown, @orderIds1 unknown, @orderIds2 unknown, @orderIds3 unknown))
複数の入力セットに対する操作の実行
時々、あなたは同じことを何度もやりたいと思っています。 最も外側のパラメータ(通常は単一の匿名型またはドメインモデルインスタンス)が実際にIEnumerable
シーケンスとして提供されている場合、DapperはこれをExecute
メソッドでサポートします。例えば:
Order[] orders = ...
// update the totals
connection.Execute("update Orders set Total=@Total where Id=@Id", orders);
ここで、dapperは単純に私たちのデータを単純にループしています。
Order[] orders = ...
// update the totals
foreach(Order order in orders) {
connection.Execute("update Orders set Total=@Total where Id=@Id", order);
}
この使用法は、すべての「複数のアクティブな結果セット」に明示的に設定された接続でasync
APIと組み合わせると特に興味深いものになります。この使用法では、dapperは自動的に操作をパイプラインするので、行ごとの遅延コストを払っていません。これにはやや複雑な使い方が必要ですが、
await connection.ExecuteAsync(
new CommandDefinition(
"update Orders set Total=@Total where Id=@Id",
orders, flags: CommandFlags.Pipelined))
ただし、テーブル値のパラメータを調べることもできます。
擬似位置パラメータ(名前付きパラメータをサポートしないプロバイダ用)
一部のADO.NETプロバイダ(特にOleDB)は、 名前付きパラメータをサポートしていません。パラメータは位置によってのみ指定され、 ?
プレースホルダ。 Dapperはどのメンバをこれらのために使うのか分からないので、dapperは別の構文を許します?foo?
;これは、他のSQL変種の@foo
または:foo
と同じですが、dapperはパラメータトークンを完全に置き換えます?
クエリを実行する前に
これはリスト展開などの他の機能と組み合わせて機能するので、以下が有効です:
string region = "North";
int[] users = ...
var docs = conn.Query<Document>(@"
select * from Documents
where Region = ?region?
and OwnerId in ?users?", new { region, users }).AsList();
したがって、 .region
および.users
メンバーは使用され、発行されるSQLは(たとえば、3人のユーザーが)です。
select * from Documents
where Region = ?
and OwnerId in (?,?,?)
ただし、この機能を使用する場合、dapper は同じパラメータを複数回使用することはできません 。これは、同じパラメータ値(大きな値でもよい)を複数回追加する必要がないようにするためです。同じ値を複数回参照する必要がある場合は、次のように変数を宣言することを検討してください。
declare @id int = ?id?; // now we can use @id multiple times in the SQL
変数が使用できない場合は、パラメーターに重複メンバー名を使用できます。これにより、値が複数回送信されていることが明らかになります。
int id = 42;
connection.Execute("... where ParentId = $id0$ ... SomethingElse = $id1$ ...",
new { id0 = id, id1 = id });