Dapper簡介


 

Dapper文檔

一,介紹:Dapper是一款輕量級ORM工具。如果你在小的項目中,使用Entity Framework、NHibernate 來處理大數據訪問及關系映射,未免有點殺雞用牛刀。你又覺得ORM省時省力,這時Dapper 將是你不二的選擇。

  ---ORM框架的核心思想是對象關系映射,ORM是將表與表之間的操作,映射成對象和對象之間的操作,就是通過操作實體類來達到操作表的目的。從數據庫提取的數據會自動按你設置的映射要求封裝成特定的對象。之后你就可以通過對對象進行操作來修改數據庫中的數據。這時候你面對的不是信息的碎片,而是一個形象鮮明的對象。

二,假如你喜歡原生的Sql語句,又喜歡ORM的簡單,那你一定會喜歡上Dapper,這款ROMDapper的優勢:

  1. 輕量。只有一個文件(SqlMapper.cs),編譯完成之后只有120k(好象是變胖了)
  2. 速度快。Dapper的速度接近與IDataReader,取列表的數據超過了DataTable。
  3. 支持多種數據庫。Dapper可以在所有Ado.net Providers下工作,包括sqlite, sqlce, firebird, oracle, MySQL, PostgreSQL and SQL Server
  4. 可以映射一對一,一對多,多對多等多種關系。
  5. 性能高。通過Emit反射IDataReader的序列隊列,來快速的得到和產生對象,性能不錯。
  6. 支持FrameWork2.0,3.0,3.5,4.0,4.5  

下面介紹Dapper如何使用,來進行高效開發,以下操作是編譯后在Net3.5下操作的例子,Net4.0下大部分函數有默認值,參數很簡單。

三, 為什么要擴展Dapper?

  了解Dapper都知道,在書寫代碼時,我們還是會手動寫SQL,擴展的目的就是在完全不改變dapper源代碼和使用基礎上,進行一次封閉,達到零SQL,實現完全對象操作。

四,原生Dapper使用流程:

  0,兩種下載使用方法:

  (1),推薦下載方法(使用Nuget下載):

  ---Nuget是一個.NET平台下的開源的項目,它是Visual Studio的擴展。在使用Visual Studio開發基於.NET Framework的應用時,Nuget能把在項目中添加、移除和更新引用的工作變得更加快捷方便。

  

  ---安裝成功以后,生成一下網站,項目bin目錄下,會生成幾個Dapper文件(主要是Dapper.dll,120k)。

  (2),可以在官網上下載Dapper源代碼,即SqlMapper.cs文件,在項目中App_Code文件夾中加入這個文件,就像Ado.net中的SqlHelper一樣。

  ---源文件地址:https://github.com/StackExchange/dapper-dot-net/blob/master/Dapper%20NET40/SqlMapper.cs

  1,下面可以在項目中開始使用Dapper了

  2,連接數據庫字符串。根據不同的數據庫進行相應設置,如果是SQL,就類似下邊設置;如果是使用SQLite,則設置方法不同。

private readonly string sqlconnection =
                 "Data Source=RENFB;Initial Catalog=test;User Id=sa;Password=sa;";
//public readonly string mysqlconnectionString =
                 @"server=127.0.0.1;database=test;uid=renfb;pwd=123456;charset='gbk'";

  3,獲取Sql Server的連接數據庫對象。

public SqlConnection OpenConnection()
{
    SqlConnection connection = new SqlConnection(sqlconnection);  //這里sqlconnection就是數據庫連接字符串
    connection.Open();
    return connection;
}
//獲取MySql的連接數據庫對象。MySqlConnection
//public MySqlConnection OpenConnection()
//{
//     MySqlConnection connection = new MySqlConnection(mysqlconnectionString);
//     connection.Open();
//     return connection;
//}

  注:如果需要換成Mysql數據庫,只用將獲得sql Server的連接數據庫對象的函數注釋掉,取消MySql的連接數據庫對象的函數的注釋,一並取消Mysql連接字符串的注釋,並修改為自己的連接信息。

  Query()方法: Query()是IDbConnection擴展方法並且重載了,從數據庫里提取信息,並用來填充我們的業務對象模型。

  4,//先創建一個類,是數據庫的user表的模型。
  public class user
     {
        public int id { get; set; }
        public string name { get; set; }
        public string address { get; set; }
        public string age { get; set; }
     }
    5,手寫Sql插入數據(增)

    /// <summary>
        /// 手寫Sql插入數據
        /// </summary>
        public int InsertWithSql()
        {
            using (var conn = SQLiteHelper.OpenConnection())  //這里訪問的是Sqlite數據文件,這里OpenConnection即上邊獲取連接數據庫對象方法
            {
                user user=new user();
                user.name = "Dapper01";
                user.address = "周口";
                user.age="15";
                //string _sql = "INSERT INTO User(name,address,age)VALUES('Dapper01','周口',13)";
                string _sql = "INSERT INTO User(name,address,age)VALUES(@name,@address,@age)";
                return conn.Execute(_sql,user);
            }
        }

    ---如果不用Dapper,用插入一條數據需要多少代碼量(相對上邊只用了2行代碼,下邊需要用6行代碼):

   public static int insert_news(string title, string content)
    {
        string sql = "insert into news(title,content,addtime) values(@title,@content,@addtime)";
        SQLiteParameter[] parameters =
            {
                SQLiteHelper.MakeSQLiteParameter("@title", DbType.String, title.Trim()),
                SQLiteHelper.MakeSQLiteParameter("@content", DbType.String, content.Trim()),
                SQLiteHelper.MakeSQLiteParameter("@addtime", DbType.DateTime,DateTime.Now)
            };
        return SQLiteHelper.ExecuteSql(sql, parameters);  //調用SQLiteHelper文件中方法,執行數據庫插入
    }

6,手寫Sql輸出數據(刪)

protected void Page_Load(object sender, EventArgs e)
        {
            user user = new user();
            user.id = 15;
            DeleteColumn(user);
        }

        //刪除一個類別(3行):
        public int DeleteColumn(user user)
        {
            using (IDbConnection conn = SQLiteHelper.OpenConnection())
            {
                const string query = "delete from user where id=@id";
                return conn.Execute(query, user);
            }
        }

  ---不用Dapper,刪除一條數據,代碼如下(4行):

  public static int del_news(string newid)
    {
        string sql = "delete from news where newid=@newid";
        SQLiteParameter[] parameters =
            {
                SQLiteHelper.MakeSQLiteParameter("@newid", DbType.String, newid.Trim())
            };
        return SQLiteHelper.ExecuteSql(sql, parameters);
    }

7,手寫Sql更新數據(改)

protected void Page_Load(object sender, EventArgs e)
        {
            user user = new user();
            user.id = 14;
            user.name = "Dapper03";
            user.address = "太康";
            user.age = "25";
            UpdateColumn(user);
        }

//更新一個類別:
        public int UpdateColumn(user user)
        {
            using (IDbConnection conn = SQLiteHelper.OpenConnection())
            {
                const string query = "update user set name=@name,address=@address,age=@age where id=@id";
                return conn.Execute(query, user);
            }
        }

8,手寫Sql查詢數據(查)

protected void Page_Load(object sender, EventArgs e)
        {
            user user = new user();
            user.id = 14;
            user=SelectColumn(user.id);
            Context.Response.Write(user.name+"|"+user.address+"|"+user.age);
            Context.Response.End();
        }

 //獲取單個user對象。
        public user SelectColumn(int user_id)
        {
            using (IDbConnection conn = SQLiteHelper.OpenConnection())
            {
                const string query = "select * from user where id=@id";
                return conn.Query<user>(query, new {id = user_id}).SingleOrDefault<user>();  //這里用的是linq語法,所以必須引用System.Linq;
            }
        }

  ---這里我們傳遞了一個參數給Query方法,參數可以是任何對象,其屬性在查詢中與sql的參數匹配,由於Query總是返回一個集合,我們只需調用SingleOrDefault方法,因為我們知道總是返回0或1行.

  //獲取user對象的集合。
        public IEnumerable<user> SelectUsers()
        {
            using (IDbConnection conn = SQLiteHelper.OpenConnection())
            {
                const string query = "select * from user order by id asc";
                return conn.Query<user>(query, null);
            }
        }

    protected void Page_Load(object sender, EventArgs e)
        {
            IEnumerable<user> list = SelectUsers();
            foreach (var i in list)
            {
                Context.Response.Write(i.name + "|" + i.address + "|" + i.age);
                Context.Response.Write("<br/>");
            }
            Context.Response.End();
        }

五,如果想直接插入一個實體對象,Sql語句都不要了,可以在Nuget上下載Dapper的擴展包--->Dapper.SimpleCRUD安裝包。(crud即增查改刪)

  ---使用Dapper.SimpleCRUD時,兩個注意點,1是直接插入實體,類代碼要改:

  public class user
    {
        [Key]    //主鍵值前加個key
        public int id { get; set; }
        public string name { get; set; }
        public string address { get; set; }
        public string age { get; set; }
    }

       ///<summary>
         ///實體插入數據
         ///</summary>
        public int? InsertWithEntity()
        {
            using (var conn = SQLiteHelper.OpenConnection())
            {
                var user = new user { name = "Dapper02", address = "周口",age="22"};
                return conn.Insert(user);
            }
        } 

  ---2是使用sqlite數據庫時,會報錯!錯誤內容如下,因為sqlite不支持scope_identity函數,沒有這個函數:

SQL logic error or missing database
no such function: SCOPE_IDENTITY

 



5,就是這么簡單,直接在例子中嵌入Sql,很容易擴展為存儲過程,可以使用別名使結果集中的列與業務對象模型(ColumnCat)的屬性對應。

//下面使用上面的集合顯示出分類。
List<ColumnCat> AllColumnCat =SelectColumnCats().ToList<ColumnCat>();
foreach (ColumnCat cat in AllColumnCat.Where(c => c.Parentid == 0))
{
    Response.Write("Name==>" + cat.Name + "\t");
    Response.Write("時間==>" + cat.ModifiedOn + "\t");
    Response.Write("<br/>");

    foreach (ColumnCat c in AllColumnCat
                .Where<ColumnCat>(subColumnCat => subColumnCat.Parentid == cat.Id))
    {
        Response.Write("&nbsp;&nbsp;++++");
        Response.Write("Name==>" + c.Name + "\t");
        Response.Write("時間==>" + c.ModifiedOn + "\t");
        Response.Write("<br/>");
    }
}

//將一級類別和二級類別顯示在頁面上,如果使用一個遞歸,很容易實現無限級分類(你懂的)。

7,//Dapper也可以加載填充嵌套對象,考慮這樣一種情形,考慮到新聞的類別屬性,返回類別對象,
//我們創建一個Column的類
public class Column
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime ModifiedDate { get; set; }
    public ColumnCat ColumnCat { get; set; }
}

//接下來我們來填充我們的業務對象。
public IList<Column> SelectColumnsWithColumnCat()
{
    using (IDbConnection conn = OpenConnection())
    {
        const string query = "select c.Id,c.Name,c.ModifiedDate,c.ColumnCatid
        ,cat.id,cat.[Name],cat.ModifiedOn,cat.Parentid from [Column] as c
        left outer join ColumnCat as cat on c.ColumnCatid=cat.id";
        return conn.Query<Column, ColumnCat, Column>(query
               , (column, columncat) => { column.ColumnCat = columncat; return column; }
               , null, null, false, "Id", null, null).ToList<Column>();
    }
}

  注:1,在填充嵌套對象的時候,只好執行 ToList<>方法,否則回報ExecuteReader 要求已打開且可用的連接。連接的當前狀態為已關閉,而單個對象不會報錯,估計是using結束后關閉了連接,而嵌套對象在map的時候又執行了 ExecuteReader,只好在using結束之前返回list集合。 2,嵌套對象的參數是比較多的,主要是前兩個參數,其它參數沒用可以設置為null,不過在4.0版本可以只寫兩個參數,其它參數都有默認值。特別要注意 的是splitOn,這個參數不能為空,否則會報對象為引用的錯誤。【splitOn參數的意思是讀取第二個對象的的分割列,從哪個列起開始讀取第二個對 象,如果表里的自增長列都為Id,可以設置這個參數為”Id”】.

  Execute方法: 正如Query方法是檢索數據的,Execute方法不會檢索數據,它與Query方法非常相似,但它總返回總數(受影響的行數),而不是一個對象集合【如:insert update和delete】.

8,//接下來向數據庫里添加一個類別
public int InsertColumnCat(ColumnCat cat)
{
    using (IDbConnection conn = OpenConnection())
    {
        const string query = "insert into ColumnCat([name],ModifiedOn,Parentid)
        values (@name,@ModifiedOn,@Parentid)";
        int row = conn.Execute(query,cat);
        //更新對象的Id為數據庫里新增的Id,假如增加之后不需要獲得新增的對象,
        //只需將對象添加到數據庫里,可以將下面的一行注釋掉。
        SetIdentity(conn,id=>cat.Id=id,"id","ColumnCat");    
        return row;
    }
}
 
public void SetIdentity(IDbConnection conn, Action<int> setId,string primarykey
                          ,string tableName)
{
    if (string.IsNullOrEmpty(primarykey)) primarykey = "id";
    if (string.IsNullOrEmpty(tableName))
    {
        throw new ArgumentException("tableName參數不能為空,為查詢的表名");
    }
    string query = string.Format("SELECT max({0}) as Id FROM {1}", primarykey
                         , tableName);
    NewId identity = conn.Query<NewId>(query, null).Single<NewId>();
    setId(identity.Id);
}

public class NewId
{
    public int Id { get; set; }
}

  由於Dapper是通過類的屬性自動綁定的,所以增 加了NewId類來獲取增加對象后的Id,本來打算使用@@identity,Net3.5下使用總是報錯,只好使用Max函數獲取。當然如果不需要獲得 更新后的對象的ID,可以不使用SetIdentity,這個函數通用。

編譯Dapper源碼生成的是Net4.0下使用的,可以借助Net4.0新增的dynamic動態類型,
//SetIdentity的實現將非常方便。如下:
public void SetIdentity<T>(IDbConnection conn, Action<int> setId)
{
    dynamic identity = connection.Query("SELECT @@IDENTITY AS Id").Single();
    T newId = (T)identity.Id;
    setId(newId);
}
9,下面介紹一下Dapper的高級用法 
//Dapper對事務處理的例子,如刪除類別的同時刪除類別下的所有新聞。或者刪除產品的同時,
//刪除產品圖片表里關聯的所有圖片。
public int DeleteColumnCatAndColumn(ColumnCat cat)
{
    using (IDbConnection conn = OpenConnection())
    {
        const string deleteColumn = "delete from [Column] where ColumnCatid=@catid";
        const string deleteColumnCat = "delete from ColumnCat where id=@Id";

        IDbTransaction transaction = conn.BeginTransaction();
        int row=conn.Execute(deleteColumn, new { catid =cat.Id},transaction,null,null);
        row += conn.Execute(deleteColumnCat, new { id=cat.Id},transaction,null,null);
        transaction.Commit();
        return row;
    }
}


 

原文地址:https://www.cnblogs.com/feichengwulai/articles/4277100.html


免責聲明!

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



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