1. 程式人生 > >Dapper ORM 用法—Net下無敵的ORM

Dapper ORM 用法—Net下無敵的ORM

假如你喜歡原生的Sql語句,又喜歡ORM的簡單,那你一定會喜歡上Dapper這款ROM.點選下載 Dapper的優勢:

1,Dapper是一個輕型的ORM類。程式碼就一個SqlMapper.cs檔案,編譯後就40K的一個很小的Dll.

2,Dapper很快。Dapper的速度接近與IDataReader,取列表的資料超過了DataTable。

3,Dapper支援什麼資料庫。Dapper支援Mysql,SqlLite,Mssql2000,Mssql2005,Oracle等一系列的資料庫,當然如果你知道原理也可以讓它支援Mongo db

4,Dapper的r支援多表並聯的物件。支援一對多 多對多的關係。並且沒侵入性,想用就用,不想用就不用。無XML無屬性。程式碼以前怎麼寫現在還怎麼寫。 5,Dapper原理通過Emit反射IDataReader的序列佇列,來快速的得到和產生物件。效能實在高高高。

6,Dapper支援net2.0,3.0,3.5,4.0。【如果想在Net2.0下使用,可以去網上找一下Net2.0下如何配置執行Net3.5即可。】 7,Dapper語法十分簡單。並且無須遷就資料庫的設計。

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

複製程式碼
//資料庫裡的表:
CREATE TABLE ColumnCat
(
Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
NAME NVARCHAR(150) NULL,
ModifiedOn SMALLDATETIME NULL DEFAULT(GETDATE()),
Parentid INT
)

CREATE TABLE Column
(
Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
NAME NVARCHAR(150) NULL,
ModifiedDate SMALLDATETIME NULL DEFAULT(GETDATE()),
ColumnCatid INT null
)
複製程式碼


常用的表,分類和內容表,分類可以有下級類別。以下操作基本上都是對這兩個表的操作。
//連線資料庫字串。
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'";
//獲取Sql Server的連線資料庫物件。SqlConnection
複製程式碼
public SqlConnection OpenConnection()
{
    SqlConnection connection = new 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擴充套件方法並且過載了,從資料庫裡提取資訊,並用來填充我們的業務物件模型。

複製程式碼
//先建立一個類,是資料庫的ColumnCat表的模型。
public class ColumnCat
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime ModifiedOn { get; set; }
    public int Parentid { get; set; }
}

  
//獲取ColumnCat物件的集合。
public IEnumerable<ColumnCat> SelectColumnCats()
{
    using (IDbConnection conn = OpenConnection())
    {
        const string query = "select * from ColumnCat order by id desc";
        return conn.Query<ColumnCat>(query,null);
    }
}
複製程式碼

就是這麼簡單,直接在例子中嵌入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/>");
    }
}
複製程式碼
//將一級類別和二級類別顯示在頁面上,如果使用一個遞迴,很容易實現無限級分類(你懂的)。

 

複製程式碼
 
//獲取單個ColumnCat物件。
public ColumnCat SelectColumnCat(int columnCatId)
{
    using (IDbConnection conn = OpenConnection())
    {
        const string query = "select * from ColumnCat where [email protected]";
        return conn.Query<ColumnCat>(query, new { id=columnCatId})
                        .SingleOrDefault<ColumnCat>();
    }
}
複製程式碼

 

這裡我們傳遞了一個引數給Query方法,引數可以是任何物件,其屬性在查詢中與sql的引數匹配,由於Query總是返回一個集合,我們只需呼叫SingleOrDefault方法,因為我們知道總是返回0或1行.

複製程式碼
//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】.

複製程式碼
//接下來向資料庫裡新增一個類別
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);
}
 
//更新一個類別:
public int UpdateColumnCat(ColumnCat cat)
{
    using (IDbConnection conn = OpenConnection())
    {
        const string query = "update ColumnCat set [email protected]
                          ,[email protected],[email protected] where [email protected]";
        return conn.Execute(query,cat);
    }
}
 
//刪除一個類別:
public int DeleteColumnCat(ColumnCat cat)
{
    using (IDbConnection conn = OpenConnection())
    {
        const string query = "delete from ColumnCat where [email protected]";
        return conn.Execute(query, cat);
    }
}
下面介紹一下Dapper的高階用法 
//Dapper對事務處理的例子,如刪除類別的同時刪除類別下的所有新聞。或者刪除產品的同時,
//刪除產品圖片表裡關聯的所有圖片。
public int DeleteColumnCatAndColumn(ColumnCat cat)
{
    using (IDbConnection conn = OpenConnection())
    {
        const string deleteColumn = "delete from [Column] where [email protected]";
        const string deleteColumnCat = "delete from ColumnCat where [email protected]";

        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;
    }
}
複製程式碼