Dapper的基本使用


Dapper - a simple object mapper for .Net

Dapper是.NET下一個micro ORM,它和Entity Framework或Nhibnate不同,屬於輕量級的,並且是半自動的,也就是說實體類都要自己寫。

下載地址:https://github.com/StackExchange/Dapper/

優點

1. 使用Dapper可以自動進行對象映射。

2. 輕量級,單文件。

3. 支持多數據庫。

4. Dapper原理通過Emit反射IDataReader的序列隊列,來快速的得到和產生對象。

5. 可以映射一對一,一對多,多對多等多種關系。

發布說明

Located at stackexchange.github.io/Dapper

Packages

MyGet Pre-release feed: https://www.myget.org/gallery/dapper

Package NuGet Stable NuGet Pre-release Downloads MyGet
Dapper Dapper Dapper Dapper Dapper MyGet
Dapper.Contrib Dapper.Contrib Dapper.Contrib Dapper.Contrib Dapper.Contrib MyGet
Dapper.EntityFramework Dapper.EntityFramework Dapper.EntityFramework Dapper.EntityFramework Dapper.EntityFramework MyGet
Dapper.EntityFramework.StrongName Dapper.EntityFramework.StrongName Dapper.EntityFramework.StrongName Dapper.EntityFramework.StrongName Dapper.EntityFramework.StrongName MyGet
Dapper.Rainbow Dapper.Rainbow Dapper.Rainbow Dapper.Rainbow Dapper.Rainbow MyGet
Dapper.SqlBuilder Dapper.SqlBuilder Dapper.SqlBuilder Dapper.SqlBuilder Dapper.SqlBuilder MyGet
Dapper.StrongName Dapper.StrongName Dapper.StrongName Dapper.StrongName Dapper.StrongName MyGet

Features

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

連接語句

var _connectionString = ConfigurationManager.ConnectionStrings["SqlServer"].ConnectionString;
IDbConnection conn = new SqlConnection(_connectionString);

使用dapper不需要考慮conn是否連接,在執行dapper時自行判斷 open狀態,如果沒有打開它會自己打開。一條查詢的時候不用管,多個查詢在一起的時候,建議自己打開,寫事務的時候還是需要自己打開的哦。

它提供了3個 helpers:

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

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

使用示例:

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

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

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

3、執行不返回任何結果的命令

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 rows inserted: "1,1", "2,2" and "3,3"

這適用於任何為某個T實現IEnumerable的參數。

query = "INSERT INTO Dogs(Id,Name,Age,Weight) VALUES(@Id,@Name,@Age,@Weight)";
conn.Execute(query, new List<Dog>(){
    new Dog{ Id = DateTime.Now.Ticks+1, Name = "小紅1", Age = 2, Weight = 10 },
    new Dog { Id = DateTime.Now.Ticks+2, Name = "小紅2", Age = 2, Weight = 10 },
    new Dog { Id = DateTime.Now.Ticks+3, Name = "小紅3", Age = 2, Weight = 10 },
    new Dog { Id = DateTime.Now.Ticks+4, Name = "小紅3", Age = 2, Weight = 10 },
});

參數化查詢

參數作為匿名類傳入。這允許您輕松地命名參數,並使您能夠簡單地剪切和粘貼SQL片段,並在db平台的查詢分析器中運行它們。

new {A = 1, B = "b"} // A will be mapped to the param @A, B to the param @B

List 支持

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中in,like的使用

list = conn.Query<Dog>("SELECT * FROM Dogs WHERE id IN @ids ", new { ids = new long[] { list[0].Id, list[1].Id, list[2].Id } }).ToList();
list = conn.Query<Dog>("SELECT * FROM Dogs WHERE name LIKE @name ", new { name = $"%{name}%" }).ToList();

文字字面替換

Dapper支持對bool和numeric類型進行文字替換。

connection.Query("select * from User where UserTypeId = {=Admin}", new { UserTypeId.Admin });

文字替換不作為參數發送;這允許更好的計划和過濾索引的使用,但通常應該在測試后謹慎使用。

當注入的值實際上是固定值時(例如,特定於查詢的固定“category id”、“status code”或“region”),此特性尤其有用。

對於正在考慮文本的實時數據,您可能還需要考慮和測試provider-specific的查詢提示,比如使用常規參數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表的查詢。

直到現在,如果我們需要合並兩個查詢的結果,我們需要一個新的對象來表示它,但是在這種情況下,將User對象放在Post對象中更有意義。

這是多映射的用例。您告訴dapper查詢返回一個Post和一個User對象,然后給它一個函數,描述您想對包含Post和User對象的每一行做什么。在本例中,我們希望獲取user對象並將其放入post對象中。我們寫下函數:

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

查詢方法的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完全支持存儲過程:

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 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時使用unicode,和在查詢非unicode時使用ANSI是至關重要的。

每行類型切換

通常,您希望將給定表中的所有行視為相同的數據類型。

但是,在某些情況下,能夠將不同的行解析為不同的數據類型是很有用的。這就是我成為玩家的地方。IDataReader.GetRowParser遲早會派上用場。

假設您有一個名為“Shapes”的數據庫表,列有:Id、Type和Data,並且您希望根據Type列的值將其行解析為Circle, Square, or Triangle 對象。

var shapes = new List<IShape>();
using (var reader = connection.ExecuteReader("select * from Shapes"))
{
    // 您期望的每種類型生成一個行解析器。    // 通用類型<IShape>是解析器將返回的內容。    // 參數(typeof(*))是要解析的具體類型。    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變量與MySql連接器,你必須添加以下選項到你的連接字符串:

Allow User Variables=True

請確保沒有向Dapper提供要映射的屬性。

限制和警告

Dapper緩存關於它運行的每個查詢的信息,這允許它快速物化對象並快速處理參數。

當前實現將此信息緩存到一個ConcurrentDictionary對象中。只使用一次的語句通常會從該緩存中刷新。但是,如果您在不使用參數的情況下動態地生成SQL字符串,那么可能會遇到內存問題。

Dapper的簡潔性意味着ORMs自帶的許多功能都被去掉了。它關注95%的場景,並為您提供大多數情況下需要的工具。它並不試圖解決所有的問題。

Dapper會與我的DB provider一起工作嗎?

Dapper沒有DB特定的實現細節,它可以跨所有。net ADO提供程序工作,包括SQLite, SQL CE, Firebird, Oracle, MySQL, PostgreSQL and SQL Server.

你有一個完整的例子列表嗎??

Dapper有一個全面的測試套件:test project.

誰在用這個?

Dapper在生產中使用:Stack Overflow.

擴展:Dapper To Linq框架

此框架是Dapper的擴展,效率優於EntityFramwork,並且支持.NetFramework和.NetCore框架

https://www.cnblogs.com/kogel/p/10805696.html

EntityFrameworkCore結合Dapper的使用

基本使用:

我們可以通過DbContext.Database.GetDbConnection() 獲得 EF 使用的數據庫連接對象 DbConnection,這允許我們使用 Dapper 。

與DbContext不同的是,使用 DbConnection 進行的 【寫】 操作將直接在數據庫生效,不需要調用 DbContext.SaveChanges()。

使用事務:

我們可以通過 DbContext.Database.BeginTransaction() 獲取到 IDbContextTransaction 對象,但它不是 IDbTransaction,所以沒法直接在 Dapper 中使用。

幸運的是微軟提供了擴展方法 IDbContextTransaction.GetDbTransaction() 獲取 IDbTransaction ,為了統一控制 EFCore 和 Dapper 的事務,所以在 Dapper 執行數據庫操作時,必須將 IDbTransaction 傳到 transaction 參數中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM