Dapper簡易教程(翻譯自Github上StackExchange/Dapper)

本文源自:https://github.com/cnxy/Dapper-zh-cn 

本博客做者與Github上做者(cnxy)實爲同一個做者。因爲筆者翻譯水平有限,文本中錯誤不免,歡迎指正!git

 

本文翻譯自:StackExchange.Dapper

原版教程源自:Dapper Tutorial

中文教程源自:中文Dapper教程.GitBook

中文教程PDF:dapper-tutorial-cn

Dapper - .Net版本的簡單對象映射器

發行說明

請見 stackexchange.github.io/Dappergithub

組件

Nuget穩定版:web

https://www.nuget.org/packages/Dapper

Visual Studio 程序包管理器控制檯:sql

PM> Install-Package Dappe

特色數據庫

Dapper是一個NuGet庫,您能夠將其添加到項目中,以擴展您的IDbConnection接口。緩存

它提供了3個使用方法:網絡

執行一個查詢並將結果映射到強類型列表

public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null, bool buffered = true)

示例:app

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

執行一個查詢並將其映射到動態對象列表

public static IEnumerable<dynamic> Query (this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null, bool buffered = true)

這個方法會執行SQL語句,並返回一個動態列表。框架

示例:函數

var rows = connection.Query("select 1 A, 2 B union all select 3, 4");

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

執行不返回結果的命令

public static int Execute(this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null)

示例:

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行: "1,1", "2,2" 與 "3,3"

這適用於已經實現IEnumerable接口的集合對象T。

性能

Dapper的一個關鍵特性是性能。 如下度量標準顯示了對DB執行500個SELECT語句並將返回的數據映射到對象所需的時間。

性能測試分爲3個列表:

  • 支持從數據庫中提取靜態類型對象框架的POCO序列化,使用原生SQL語句。
  • 支持返回動態對象列表框架的動態序列化。
  • 典型的框架用法:一般典型的框架使用與最佳使用性能明顯不一樣,而且它不會涉及編寫SQL語句。

超過500次迭代的SELECT映射性能 - POCO序列化

方法 執行時間 備註
手工編碼 (使用 SqlDataReader) 47ms  
Dapper ExecuteMapperQuery 49ms  
ServiceStack.OrmLite (使用Id查詢) 50ms  
PetaPoco 52ms 能夠更快
BLToolkit 80ms  
SubSonic CodingHorror 107ms  
NHibernate SQL 104ms  
Linq 2 SQL ExecuteQuery 181ms  
Entity framework ExecuteStoreQuery 631ms  

超過500次迭代的SELECT映射性能 - 動態序列化

方法 執行時間 備註
Dapper ExecuteMapperQuery (動態) 48ms  
Massive 52ms  
Simple.Data 95ms  

超過500次迭代的SELECT映射性能 - 典型用法

方法 執行時間 備註
Linq 2 SQL CompiledQuery 81ms 非典型的且不涉及複雜的代碼
NHibernate HQL 118ms  
Linq 2 SQL 559ms  
Entity framework 859ms  
SubSonic ActiveRecord.SingleOrDefault 3619ms  

性能基準測試信息 點擊這裏.

能夠任意提交包含其餘ORM的補丁 - 運行基準測試時,請確保在Release中編譯,且不能附加調試器 (Ctrl+F5).

或者,你可使用Frans Bouma的RawDataAccessBencherOrmBenchmark測試套件做爲測試工具使用。

參數化查詢

能夠匿名類型做爲參數進行傳遞,這能夠輕鬆地命名這些參數名稱,且可以在數據庫平臺的查詢分析器中簡單地使用剪切、粘貼SQL語句並運行。

new {A = 1, B = "b"} // A映射到參數@A,B映射到參數@B

列表支持

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 UserId = {=Id}", new {Id = 1}));

文字替換不做爲參數發送; 更好的計劃和過濾索引用法將被容許,但一般應謹慎在測試後使用。 當注入的值其實是固定值(例如,特定於查詢的「類別ID」,「狀態代碼」或「區域」)時,此功能特別有用。 當你在思考文字live數據時,也有可能想到also並測試特定於提供程序的查詢提示,如帶有常規參數的OPTIMIZE FOR UNKNOWN

緩衝與未緩衝閱讀器

Dapper的默認行爲是執行SQL並在返回時緩衝整個閱讀器。 在大多數狀況下,這是理想的,由於它最小化了數據庫中的共享鎖並減小了數據庫網絡時間。

可是,在執行大量查詢時,可能須要最小化內存佔用並僅根據須要加載對象。 爲此,將buffered:false傳遞給Query方法。

多重映射

Dapper容許將單個行映射到多個對象。 若是想避免無關的查詢和當即加載關聯,這是一個很關鍵的特性。

例子:

思考這兩個類: Post and 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; }
}

如今咱們要把posts表單與users表單進行映射查詢。到目前爲止,若是咱們須要結合2個查詢的結果,咱們須要一個新的對象來表達它,但在這種狀況下將User對象放在Post對象中更有意義。

這是多重映射的用戶案例。你告訴dapper查詢返回一個Post和一個User對象,而後給它描述你想要對包含PostUser對象的每一行作什麼的函數。 在咱們的例子中,咱們想要獲取用戶對象並將其放在post對象中。因此編寫函數以下:

(post, user) => { post.Owner = user; return post; }

Query方法的3個類型參數指定dapper應該使用哪些對象及返回的內容進行反序列化行。咱們將把這兩行解釋爲PostUser的組合,而後咱們返回一個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徹底支持存儲過程:

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");

Ansi字符串和varchar

Dapper支持varchar參數,若是使用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編碼查詢unicode與ANSI編碼或查詢非unicode編碼時,變得相當重要。

每行類型轉換

一般,本身但願將給定表中的全部行視爲相同的數據類型。 可是,在某些狀況下,可以將不一樣的行解析爲不一樣的數據類型是有用的。 這就是IDataReader.GetRowParser派上用場的地方。

假設有一個名爲「Shapes」的數據庫表,其中包含列:IdTypeData,你想要基於Type列的值將它的行解析爲CircleSquareTriangle對象。

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

限制與警告

Dapper緩存有關它運行的每一個查詢的信息,這使它可以快速實現對象並快速處理參數。 當前實現將此信息緩存在ConcurrentDictionary對象中。僅使用一次的語句一般會今後緩存中刷新。儘管如此,若是您在不使用參數的狀況下動態生成SQL字符串,則可能會遇到內存問題。

Dapper的簡潔性意味着ORM附帶的許多功能都被剝離了。Dapper擔憂95%的狀況,併爲您提供大多數時間所需的工具,並不試圖解決全部問題。

Dapper支持哪些數據庫?

Dapper沒有特定於DB的實現細節,它適用於全部.NET ADO提供程序,包括SQLite(https://www.sqlite.org/),SQL CE,Firebird,Oracle,MySQL,PostgreSQL和SQL Server。

有完整的例子清單嗎?

Dapper有一個完整位於測試工程的測試套件。

誰在用這個?

Stack Overflow正在使用Dapper。

相關文章
相關標籤/搜索