https://github.com/dapperlib/dapper/releasesにあります
Myget Pre-Release Feed:https://www.myget.org/gallery/dapper
パッケージ | ナゲット安定 | Nuget Pre-Release | ダウンロード | myget |
---|---|---|---|---|
ダッパー | ||||
dapper.entityframework | ||||
dapper.entityframework.strongname | ||||
dapper.rainbow | ||||
dapper.sqlbuilder | ||||
dapper.strongname |
パッケージの目的:
Dapperはもともとスタックオーバーフローのために開発されましたが、f/ossです。スポンサーシップは歓迎され、招待されます - ページの上部にあるスポンサーリンクをご覧ください。 Dapperを後援してくれたすべての人(個人または組織)に感謝しますが、特に次のことに感謝します。
Dapperは、 DbConnection
インスタンスの拡張メソッドを介してADO.NET接続を強化するプロジェクトに追加できるNUGETライブラリです。これにより、SQLを呼び出すためのシンプルで効率的なAPIが提供され、同期データアクセスと非同期の両方のデータアクセスがサポートされ、バッファリングされたクエリと非バッファークエリの両方が可能になります。
複数のヘルパーを提供しますが、重要なAPIは次のとおりです。
// insert/update/delete etc
var count = connection . Execute ( sql [ , args ] ) ;
// multi-row query
IEnumerable < T > rows = connection . Query < T > ( sql [ , args ] ) ;
// single-row query ({Single|First}[OrDefault])
T row = connection . QuerySingle < T > ( sql [ , args ] ) ;
args
(とりわけ)可能性がある場所:
Dictionary<string,object>
DynamicParameters
インスタンス public class Dog
{
public int ? Age { get ; set ; }
public Guid Id { get ; set ; }
public string Name { get ; set ; }
public float ? Weight { get ; set ; }
public int IgnoredProperty { get { return 1 ; } }
}
var guid = Guid . NewGuid ( ) ;
var dog = connection . Query < Dog > ( " select Age = @Age, Id = @Id " , new { Age = ( int ? ) null , Id = guid } ) ;
Assert . Equal ( 1 , dog . Count ( ) ) ;
Assert . Null ( dog . First ( ) . Age ) ;
Assert . Equal ( guid , dog . First ( ) . Id ) ;
このメソッドはSQLを実行し、動的リストを返します。
使用例:
var rows = connection . Query ( " select 1 A, 2 B union all select 3, 4 " ) . AsList ( ) ;
Assert . Equal ( 1 , ( int ) rows [ 0 ] . A ) ;
Assert . Equal ( 2 , ( int ) rows [ 0 ] . B ) ;
Assert . Equal ( 3 , ( int ) rows [ 1 ] . A ) ;
Assert . Equal ( 4 , ( int ) rows [ 1 ] . B ) ;
使用例:
var count = connection . Execute ( @"
set nocount on
create table #t(i int)
set nocount off
insert #t
select @a a union all select @b
set nocount on
drop table #t" , new { a = 1 , b = 2 } ) ;
Assert . Equal ( 2 , count ) ;
同じ署名を使用すると、コマンドを複数回便利かつ効率的に実行することもできます(たとえば、データをロードするなど)
使用例:
var count = connection . Execute ( @"insert MyTable(colA, colB) values (@a, @b)" ,
new [ ] { new { a = 1 , b = 1 } , new { a = 2 , b = 2 } , new { a = 3 , b = 3 } }
) ;
Assert . Equal ( 3 , count ) ; // 3 rows inserted: "1,1", "2,2" and "3,3"
既存のコレクションを既に持っている場合の別の例:
var foos = new List < Foo >
{
{ new Foo { A = 1 , B = 1 } }
{ new Foo { A = 2 , B = 2 } }
{ new Foo { A = 3 , B = 3 } }
} ;
var count = connection . Execute ( @"insert MyTable(colA, colB) values (@a, @b)" , foos ) ;
Assert . Equal ( foos . Count , count ) ;
これは、いくつかのTのIEnumerable<T>
を実装する任意のパラメーターで機能します。
Dapperの重要な機能はパフォーマンスです。次のメトリックは、DBに対してSELECT
ステートメントを実行するのにかかる時間を示しています(さまざまな構成で、それぞれラベルが付けられています)、データをオブジェクトにマップします。
ベンチマークはdapper.tests.performance(貢献を歓迎します!)にあり、次のことを実行できます。
dotnet run --project . b enchmarks D apper.Tests.Performance -c Release -f net8.0 -- -f * --join
最新の実行からの出力は次のとおりです。
BenchmarkDotNet v0.13.7, Windows 10 (10.0.19045.3693/22H2/2022Update)
Intel Core i7-3630QM CPU 2.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores
.NET SDK 8.0.100
[Host] : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX
ShortRun : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX
orm | 方法 | 戻る | 平均 | stddev | エラー | GEN0 | Gen1 | Gen2 | 割り当てられます |
---|---|---|---|---|---|---|---|---|---|
ダッパーキャッシュの影響 | executeparameters_cache | 空所 | 96.75 US | 0.668 US | 1.010 US | 0.6250 | - | - | 2184 b |
ダッパーキャッシュの影響 | queryfirstparameters_cache | 空所 | 96.86 US | 0.493 US | 0.746 US | 0.8750 | - | - | 2824 b |
ハンドコード化 | SQLCommand | 役職 | 119.70 US | 0.706 US | 1.067 US | 1.3750 | 1.0000 | 0.1250 | 7584 b |
ハンドコード化 | データテーブル | 動的 | 126.64 US | 1.239 US | 1.873 US | 3.0000 | - | - | 9576 b |
sqlmarshal | SQLCommand | 役職 | 132.36 US | 1.008 US | 1.523 US | 2.0000 | 1.0000 | 0.2500 | 11529 b |
ダッパー | queryfirstordefault | 役職 | 133.73 US | 1.301 US | 2.186 US | 1.7500 | 1.5000 | - | 11608 b |
マイティ | クエリ | 動的 | 133.92 US | 1.075 US | 1.806 US | 2.0000 | 1.7500 | - | 12710 b |
linqからdb | クエリ | 役職 | 134.24 US | 1.068 US | 1.614 US | 1.7500 | 1.2500 | - | 10904 b |
repodb | executequery | 役職 | 135.83 US | 1.839 US | 3.091 US | 1.7500 | 1.5000 | - | 11649 b |
ダッパー | 「クエリ(バッファリング)」 | 役職 | 136.14 US | 1.755 US | 2.653 US | 2.0000 | 1.5000 | - | 11888 b |
マイティ | クエリ | 役職 | 137.96 US | 1.485 US | 2.244 US | 2.2500 | 1.2500 | - | 12201 b |
ダッパー | queryfirstordefault | 動的 | 139.04 US | 1.507 US | 2.279 US | 3.5000 | - | - | 11648 b |
マイティ | 単一のフロムクリー | 動的 | 139.74 US | 2.521 US | 3.811 US | 2.0000 | 1.7500 | - | 12710 b |
ダッパー | 「クエリ(バッファリング)」 | 動的 | 140.13 US | 1.382 US | 2.090 US | 2.0000 | 1.5000 | - | 11968 b |
サービス造影 | singlebyid | 役職 | 140.76 US | 1.147 US | 2.192 US | 2.5000 | 1.2500 | 0.2500 | 15248 b |
ダッパー | 「contrib get」 | 役職 | 141.09 US | 1.394 US | 2.108 US | 2.0000 | 1.5000 | - | 12440 b |
マイティ | 単一のフロムクリー | 役職 | 141.17 US | 1.941 US | 2.935 US | 1.7500 | 1.5000 | - | 12201 b |
大規模 | 「クエリ(動的)」 | 動的 | 142.01 US | 4.957 US | 7.494 US | 2.0000 | 1.5000 | - | 12342 b |
linqからdb | 「最初(コンパイル)」 | 役職 | 144.59 US | 1.295 US | 1.958 US | 1.7500 | 1.5000 | - | 12128 b |
repodb | クエリフィールド | 役職 | 148.31 US | 1.742 US | 2.633 US | 2.0000 | 1.5000 | 0.5000 | 13938 b |
規範 | 「読む<>(タプル)」 | ValueTuple`8 | 148.58 US | 2.172 US | 3.283 US | 2.0000 | 1.7500 | - | 12745 b |
規範 | 'read <()>(名付けられたタプル)」 | ValueTuple`8 | 150.60 US | 0.658 US | 1.106 US | 2.2500 | 2.0000 | 1.2500 | 14562 b |
repodb | クエリ | 役職 | 152.34 US | 2.164 US | 3.271 US | 2.2500 | 1.5000 | 0.2500 | 14106 b |
repodb | querydynamic | 役職 | 154.15 US | 4.108 US | 6.210 US | 2.2500 | 1.7500 | 0.5000 | 13930 b |
repodb | どこにクエリ | 役職 | 155.90 US | 1.953 US | 3.282 US | 2.5000 | 0.5000 | - | 14858 b |
ダッパーキャッシュの影響 | executenoparameters_nocache | 空所 | 162.35 US | 1.584 US | 2.394 US | - | - | - | 760 b |
ダッパーキャッシュの影響 | executenoparameters_cache | 空所 | 162.42 US | 2.740 US | 4.142 US | - | - | - | 760 b |
ダッパーキャッシュの影響 | queryfirstnoparameters_cache | 空所 | 164.35 US | 1.206 US | 1.824 US | 0.2500 | - | - | 1520 b |
devexpress.xpo | findObject | 役職 | 165.87 US | 1.012 US | 1.934 US | 8.5000 | - | - | 28099 b |
ダッパーキャッシュの影響 | queryfirstnoparameters_nocache | 空所 | 173.87 US | 1.178 US | 1.781 US | 0.5000 | - | - | 1576 b |
linqからdb | 初め | 役職 | 175.21 US | 2.292 US | 3.851 US | 2.0000 | 0.5000 | - | 14041 b |
EF 6 | sqlquery | 役職 | 175.36 US | 2.259 US | 3.415 US | 4.0000 | 0.7500 | - | 24209 b |
規範 | 'read <>(class)' | 役職 | 186.37 US | 1.305 US | 2.496 US | 3.0000 | 0.5000 | - | 17579 b |
devexpress.xpo | getobjectbykey | 役職 | 186.78 US | 3.407 US | 5.151 US | 4.5000 | 1.0000 | - | 30114 b |
ダッパー | 「クエリ(バッファーなし)」 | 動的 | 194.62 US | 1.335 US | 2.019 US | 1.7500 | 1.5000 | - | 12048 b |
ダッパー | 「クエリ(バッファーなし)」 | 役職 | 195.01 US | 0.888 US | 1.343 US | 2.0000 | 1.5000 | - | 12008 b |
devexpress.xpo | クエリ | 役職 | 199.46 US | 5.500 US | 9.243 US | 10.0000 | - | - | 32083 b |
ベオグラード | FirstOrdeFault | タスク1 | 228.70 US | 2.181 US | 3.665 US | 4.5000 | 0.5000 | - | 20555 b |
EFコア | 「最初(コンパイル)」 | 役職 | 265.45 US | 17.745 US | 26.828 US | 2.0000 | - | - | 7521 b |
nhibernate | 得る | 役職 | 276.02 US | 8.029 US | 12.139 US | 6.5000 | 1.0000 | - | 29885 b |
nhibernate | HQL | 役職 | 277.74 US | 13.032 US | 19.703 US | 8.0000 | 1.0000 | - | 31886 b |
nhibernate | 基準 | 役職 | 300.22 US | 14.908 US | 28.504 US | 13.0000 | 1.0000 | - | 57562 b |
EF 6 | 初め | 役職 | 310.55 US | 27.254 US | 45.799 US | 13.0000 | - | - | 43309 b |
EFコア | 初め | 役職 | 317.12 US | 1.354 US | 2.046 US | 3.5000 | - | - | 11306 b |
EFコア | sqlquery | 役職 | 322.34 US | 23.990 US | 40.314 US | 5.0000 | - | - | 18195 b |
nhibernate | SQL | 役職 | 325.54 US | 3.937 US | 7.527 US | 22.0000 | 1.0000 | - | 80007 b |
EF 6 | 「最初(追跡なし)」 | 役職 | 331.14 US | 27.760 US | 46.649 US | 12.0000 | 1.0000 | - | 50237 b |
EFコア | 「最初(追跡なし)」 | 役職 | 337.82 US | 27.814 US | 46.740 US | 3.0000 | 1.0000 | - | 17986 b |
nhibernate | linq | 役職 | 604.74 US | 5.549 US | 10.610 US | 10.0000 | - | - | 46061 b |
ダッパーキャッシュの影響 | executeparameters_nocache | 空所 | 623.42 US | 3.978 US | 6.684 US | 3.0000 | 2.0000 | - | 10001 b |
ダッパーキャッシュの影響 | queryfirstparameters_nocache | 空所 | 630.77 US | 3.027 US | 4.576 US | 3.0000 | 2.0000 | - | 10640 b |
他のORMを含むパッチを自由に送信してください - ベンチマークを実行するときは、デバッガー( CTRL + F5 )を添付しないで、リリースでコンパイルしてください。
または、Frans BoumaのRawdataAccessbencher Test SuiteまたはOrmbenchmarkを好むかもしれません。
通常、パラメーターは匿名クラスとして渡されます。これにより、パラメーターを簡単に名前を付けることができ、SQLスニペットを単純にカットアンドペーストして、DBプラットフォームのクエリアナライザーで実行することができます。
new { A = 1 , B = " b " } // A will be mapped to the param @A, B to the param @B
DynamicParametersクラスを使用して、パラメーターを動的に構築することもできます。これにより、安全性とパフォーマンスにパラメーターを使用しながら、動的なSQLステートメントを構築できます。
var sqlPredicates = new List < string > ( ) ;
var queryParams = new DynamicParameters ( ) ;
if ( boolExpression )
{
sqlPredicates . Add ( " column1 = @param1 " ) ;
queryParams . Add ( " param1 " , dynamicValue1 , System . Data . DbType . Guid ) ;
} else {
sqlPredicates . Add ( " column2 = @param2 " ) ;
queryParams . Add ( " param2 " , dynamicValue2 , System . Data . DbType . String ) ;
}
DynamicParametersは、異なるタイプの既存のオブジェクトから複数のパラメーターをコピーすることもサポートしています。
var queryParams = new DynamicParameters ( objectOfType1 ) ;
queryParams . AddDynamicParams ( objectOfType2 ) ;
IDynamicParameters
インターフェイスを実行するオブジェクトがExecute
またはQuery
関数に渡されると、このインターフェイスを介してパラメーター値が抽出されます。明らかに、この目的のために使用する最も可能性の高いオブジェクトクラスは、組み込みのDynamicParameters
クラスです。
Dapperを使用すると、 IEnumerable<int>
を通過でき、クエリを自動的にパラメーター化することができます。
例えば:
connection . Query < int > ( " select * from (select 1 as Id union all select 2 union all select 3) as X where Id in @Ids " , new { Ids = new int [ ] { 1 , 2 , 3 } } ) ;
翻訳されます:
select * from ( select 1 as Id union all select 2 union all select 3 ) as X where Id in ( @Ids1 , @Ids2 , @Ids3 ) " // @Ids1 = 1 , @Ids2 = 2 , @Ids2 = 3
Dapperは、ブールタイプと数値タイプの文字通りの代替品をサポートしています。
connection . Query ( " select * from User where UserTypeId = {=Admin} " , new { UserTypeId . Admin } ) ;
文字通りの交換はパラメーターとして送信されません。これにより、より良い計画とフィルタリングされたインデックスの使用が可能になりますが、通常、テスト後に控えめに使用する必要があります。この機能は、注入される値が実際に固定値である場合に特に役立ちます(たとえば、クエリに固有の固定「カテゴリID」、「ステータスコード」または「領域」)。リテラルを検討しているライブデータの場合、通常のパラメーターを使用してOPTIMIZE FOR UNKNOWN
などのヒントを検討およびテストすることもできます。
Dapperのデフォルトの動作は、SQLを実行し、返品時にリーダー全体をバッファすることです。これは、DBの共有ロックを最小限に抑え、DBネットワーク時間を削減するため、ほとんどの場合理想的です。
ただし、巨大なクエリを実行する場合は、メモリフットプリントを最小限に抑え、必要に応じてオブジェクトのみをロードする必要がある場合があります。そうするために、バッファリング: Query
メソッドにbuffered: false
。
Dapperを使用すると、単一の行を複数のオブジェクトにマッピングできます。これは、外部のクエリと熱心な負荷関連を避けたい場合に重要な機能です。
例:
2つのクラスを検討します: Post
とUser
class Post
{
public int Id { get ; set ; }
public string Title { get ; set ; }
public string Content { get ; set ; }
public User Owner { get ; set ; }
}
class User
{
public int Id { get ; set ; }
public string Name { get ; set ; }
}
次に、投稿とユーザーテーブルの両方に結合するクエリをマップしたいとします。これまで、2つのクエリの結果を組み合わせる必要がある場合は、それを表現するために新しいオブジェクトが必要でしたが、この場合、 User
オブジェクトをPost
オブジェクト内に配置する方が理にかなっています。
これは、マルチマッピングのユースケースです。クエリがPost
とUser
オブジェクトを返すことをDapperに伝え、 Post
とUser
オブジェクトの両方を含む各行で何をしたいかを説明する関数を与えます。私たちの場合、ユーザーオブジェクトを使用して、POSTオブジェクトの内側に配置します。したがって、関数を書きます:
( post , user ) => { post . Owner = user ; return post ; }
Query
メソッドの3型引数は、Dapperが使用するオブジェクトを使用して行をゆるくするものと、返されるものを指定します。両方の行をPost
とUser
の組み合わせとして解釈し、 Post
オブジェクトを返しています。したがって、タイプ宣言はなります
< Post , User , Post >
すべてがまとめられた、次のように見えます:
var sql =
@"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id" ;
var data = connection . Query < Post , User , Post > ( sql , ( post , user ) => { post . Owner = user ; return post ; } ) ;
var post = data . First ( ) ;
Assert . Equal ( " Sams Post1 " , post . Content ) ;
Assert . Equal ( 1 , post . Id ) ;
Assert . Equal ( " Sam " , post . Owner . Name ) ;
Assert . Equal ( 99 , post . Owner . Id ) ;
Dapperは、ID列がId
またはid
という名前であると仮定することにより、返された行を分割することができます。主キーが異なる場合、またはId
以外のポイントで行を分割したい場合は、オプションのsplitOn
パラメーターを使用します。
Dapperを使用すると、単一のクエリで複数の結果グリッドを処理できます。
例:
var sql =
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id" ;
using ( var multi = connection . QueryMultiple ( sql , new { id = selectedId } ) )
{
var customer = multi . Read < Customer > ( ) . Single ( ) ;
var orders = multi . Read < Order > ( ) . ToList ( ) ;
var returns = multi . Read < Return > ( ) . ToList ( ) ;
.. .
}
Dapperは保存されたProcsを完全にサポートしています:
var user = cnn . Query < User > ( " spGetUser " , new { Id = 1 } ,
commandType : CommandType . StoredProcedure ) . SingleOrDefault ( ) ;
あなたがもっと派手なものが欲しいなら、あなたはできます:
var p = new DynamicParameters ( ) ;
p . Add ( " @a " , 11 ) ;
p . Add ( " @b " , dbType : DbType . Int32 , direction : ParameterDirection . Output ) ;
p . Add ( " @c " , dbType : DbType . Int32 , direction : ParameterDirection . ReturnValue ) ;
cnn . Execute ( " spMagicProc " , p , commandType : CommandType . StoredProcedure ) ;
int b = p . Get < int > ( " @b " ) ;
int c = p . Get < int > ( " @c " ) ;
DapperはVarchar Paramsをサポートします。Paramを使用してVarchar列のWhere句を実行している場合は、この方法で渡すようにしてください。
Query < Thing > ( " select * from Thing where Name = @Name " , new { Name = new DbString { Value = " abcde " , IsFixedLength = true , Length = 10 , IsAnsi = true } } ) ;
SQL Serverでは、UnicodeとANSIをクエリするときにUnicodeを使用するときは、非Unicodeを照会するときにUnicodeを使用することが重要です。
通常、特定のテーブルからすべての行を同じデータ型として扱います。ただし、異なるデータ型として異なる行を解析できることが役立つ状況がいくつかあります。これは、 IDataReader.GetRowParser
が役立つ場所です。
Id
、 Type
、およびData
列に掲載した「Shapes」という名前のデータベーステーブルがあると想像してください。型列の値に基づいて、行をCircle
、 Square
、またはTriangle
オブジェクトに解析する必要があります。
var shapes = new List < IShape > ( ) ;
using ( var reader = connection . ExecuteReader ( " select * from Shapes " ) )
{
// Generate a row parser for each type you expect.
// The generic type <IShape> is what the parser will return.
// The argument (typeof(*)) is the concrete type to parse.
var circleParser = reader . GetRowParser < IShape > ( typeof ( Circle ) ) ;
var squareParser = reader . GetRowParser < IShape > ( typeof ( Square ) ) ;
var triangleParser = reader . GetRowParser < IShape > ( typeof ( Triangle ) ) ;
var typeColumnIndex = reader . GetOrdinal ( " Type " ) ;
while ( reader . Read ( ) )
{
IShape shape ;
var type = ( ShapeType ) reader . GetInt32 ( typeColumnIndex ) ;
switch ( type )
{
case ShapeType . Circle :
shape = circleParser ( reader ) ;
break ;
case ShapeType . Square :
shape = squareParser ( reader ) ;
break ;
case ShapeType . Triangle :
shape = triangleParser ( reader ) ;
break ;
default :
throw new NotImplementedException ( ) ;
}
shapes . Add ( shape ) ;
}
}
MySQLコネクタを使用してノンパラメーターSQL変数を使用するには、接続文字列に次のオプションを追加する必要があります。
Allow User Variables=True
マッピングするプロパティをDapperに提供しないようにしてください。
Dapperは、実行するすべてのクエリに関する情報をキャッシュします。これにより、オブジェクトを迅速に実現し、パラメーターをすばやく処理できます。現在の実装は、この情報をConcurrentDictionary
オブジェクトにキャッシュします。一度だけ使用されるステートメントは、このキャッシュから定期的にフラッシュされます。それでも、パラメーターを使用せずにSQL文字列をその場で生成している場合、メモリの問題にヒットする可能性があります。
Dapperのシンプルさは、Ormsが搭載した多くの機能が剥奪されることを意味します。 95%のシナリオを心配しており、ほとんどの場合、必要なツールを提供します。すべての問題を解決しようとはしません。
DapperにはDB固有の実装の詳細がありません。SQLite、SQL CE、Firebird、Oracle、Mariadb、MySQL、PostgreSQL、SQL Serverなど、すべての.NET ADOプロバイダーで動作します。
Dapperは、テストプロジェクトで包括的なテストスイートを持っています。
Dapperは、Stack Overflowで生産されています。