1. 程式人生 > >C#利用Dapper實現對SQLite的操作

C#利用Dapper實現對SQLite的操作

前言

近幾天藉助C#對SQLite的學習,算是對資料庫剛入門吧,三天前寫了一篇C#利用System.Data.SQLite實現對SQLite的操作,其中方法是基於System.Data.SQLite.dll的程式包,後來在youtube和infoworld上看到利用Dapper程式包對資料庫操作更簡單、快捷,在其基礎之上自己又增加了一些用法,以下是參考視訊和文件:
參考視訊:https://www.youtube.com/watch?v=ayp3tHEkRc0
參考文件:https://www.infoworld.com/article/3025784/application-development/how-to-work-with-dapper-in-c.html

ORM介紹

介紹Dapper之前不得不提及ORM,ORM是什麼呢?
從字面理解,O是Object,物件;R是Relation,關係;M是Mapping,對映。所以,用一句話概括就是:ORM是一種物件關係對映的技術。
我們平時所使用的大多數程式設計模型都是面向物件程式設計,就是把我們研究的問題抽象出來分解成一個個物件,物件有屬性,方法等等,我們操作的是物件。
而我們平時所使用的資料庫是關係型資料庫,他是從集合論等數學知識發展過來的,他講究集合,對映,六大正規化等等,跟我們的面向物件思想的封裝繼承多型不同,這兩者之間有著根本性的差異。
所以我們就存在一個問題,怎麼去調和二者,如果能有一種技術把物件與資料庫對應起來,我們程式設計就會方便許多。於是,ORM應運而生,他就是為了解決物件與資料庫之間的差異所產生的一門技術,用他可以把物件與資料庫建立一種對映,對於業務層的程式設計師,他不用管資料庫的結構,他只需要專注於他的業務邏輯去操作物件。至於物件怎麼去變成元組進入資料庫,以及怎麼從資料庫取資料變成物件,那是ORM自動解決的。
所以,ORM為物件關係對映器,它直接將資料庫對映到C#物件。
有很多ORM框架可用,Dapper是其中之一,被稱為ORM之王。

Dapper介紹與安裝

功能:
1、速度快,效能好;
2、更少的程式碼行
3、物件對映
4、靜態物件繫結
5、動態物件繫結
6、易於處理Sql語句
7、易於處理儲存過程
8、直接操作IDBConnection類,該類直接向資料庫提供平滑性和執行查詢,而不是像在EF和ADO.NET中那樣使用各種物件傳遞資料。
9、多個查詢支援
10、支援儲存過程
11、批量處理資料插入
12、允許基於多個輸入獲取多個數據

安裝:
滑鼠右擊專案下面的引用選項,進入NuGet,輸入Dapper安裝。
在這裡插入圖片描述
如果環境是在.NET4.5環境下進行的編譯,最新版的Dapper可能與之不相容,會出現以下報錯:
在這裡插入圖片描述
你可以安裝一個低版本的Dapper來規避此問題,我採用的是1.40.0版本的Dapper,親測可用。

一、建立與資料庫表對應的實體類

此前的文章忘記介紹此步驟,特意補充。
利用SQLite的視覺化工具DB Browser for SQLite 建立資料庫檔案SQLDB.db,並建立以“people”為名稱的表,配置好資料型別,以ID作為主鍵。
在這裡插入圖片描述
然後我們需要建立一個實體類(POCO類),下面是與資料庫SQLDB中people表相對應的實體類PeopleModel,其中包含表中含有的幾個欄位:

 public class PeopleModel
    {
        public int ID { get; set; }
        public string MName { get; set; }
        public int Age { get; set; }
        public string Sex { get; set; }
        public string Phone { get; set; }
    }

二、配置路徑

App.config下配置資料庫路徑

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <connectionStrings>
      <add name="sqlDB" connectionString="data source=H:\C#\DemoDB\DemoDB\bin\Debug\SQLDB.db;version=3;"/>
    </connectionStrings>
</configuration>

在專案中訪問connectionStrings標籤

 private static string LoadConnectString(string id = "sqlDB")
 {
     return ConfigurationManager.ConnectionStrings[id].ConnectionString;
 }

三、Dapper對於SQLite的基本操作

Dapper如何工作
主要包含三個步驟
第一步:使用連線字串建立一個IDBConnection物件;
第二步:編寫一個查詢並將其儲存在一個普通的字串變數中;
第三步:呼叫db.execute()並傳遞查詢,完成。

查詢資料
Dapper中的擴充套件方法Query()能夠讓你從資料庫中檢索資料並填充到物件模型中。

public static List<PeopleModel> LoadPeople()
        {
            using (IDbConnection cnn = new SQLiteConnection(LoadConnectString()))
            {
                cnn.Open();
                var output = cnn.Query<PeopleModel>("select * from people", new DynamicParameters());
                return output.ToList();
            }
        }

儲存資料
Dapper中的Execute()方法可以用於向資料庫中插入,更新,刪除資料。這個方法會返回一個整數,表示在執行查詢時受到影響的行數。

 public static void SavePerson(PeopleModel people)
        {
            using (IDbConnection cnn = new SQLiteConnection(LoadConnectString()))
            {
                cnn.Execute("insert into people (MName,Age,Sex,Phone) values(@MName,@Age,@Sex,@Phone)", people);
            }
        }

修改資料

public static void UpdatePerson(PeopleModel people,int id)
        {
            using (IDbConnection cnn = new SQLiteConnection(LoadConnectString()))
            {
                cnn.Execute("update people set MName = @MName,Age = @Age,Sex = @Sex,Phone = @Phone where ID="+id,people);
            }
        }

刪除資料

 public static int Delete(int id)
        {
            using (IDbConnection cnn = new SQLiteConnection(LoadConnectString()))
            {
               return cnn.Execute("delete from people where ID="+id);
            }
        }

批量操作
批量操作就把物件由單個改為多個即可,即把PeopleModel people改為List<PeopleModel> peoples
刪除的操作是根據其主鍵ID,所以刪除的批量操作視情況而定,根據DataGridViewRow的單元格屬性選擇需要進行的批量操作。

四、窗體程式碼

在這裡插入圖片描述
建立窗體如上圖所示,右側為DataGridViewRow控制元件。

新建泛型集合

 List<PeopleModel> people = new List<PeopleModel>();

繫結資料來源

private void WireUpPeopleList()
        {
            dataGridView1.DataSource = null;
            dataGridView1.DataSource = people;      
        }

資料重新整理函式

private void LoadPeopleList()
        {
            people = SqliteHelper.LoadPeople();  
            WireUpPeopleList();
        }

新增/修改
其中雙擊特定行會把資料返回至填單裡,根據txtID裡的資訊判斷是否進行修改行為。

private void btn_Add_Click(object sender, EventArgs e)
        {
            PeopleModel p = new PeopleModel();
            
            p.MName = txtName.Text;
            p.Age = Convert.ToInt32(txtAge.Text);
            p.Sex = btnBoy.Checked ? "男" : "女";
            p.Phone = txtPhone.Text;
            if (txtID.Text.Equals("新增時無編號"))
            {
                SqliteHelper.SavePerson(p);
            }
            else
            {
                SqliteHelper.UpdatePerson(p,Convert.ToInt32(txtID.Text));
            }
            txtName.Text = "";
            txtAge.Text = "";
            txtPhone.Text = "";
            txtID.Text = "新增時無編號";
        } 

雙擊操作
返回資訊至填單,“新增”按鈕變為“修改”

private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
            txtID.Text = row.Cells[0].Value.ToString();
            txtName.Text = row.Cells[1].Value.ToString();
            txtAge.Text = row.Cells[2].Value.ToString();
            txtPhone.Text = row.Cells[4].Value.ToString();
            if (row.Cells[3].Value.ToString().Equals("男"))
            {
                btnBoy.Checked = true;
            }
            else
            {
                btnGirl.Checked = true;
            }
            btn_Add.Text = "修改";
        }

刪除操作

private void btn_Delete_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.dataGridView1.SelectedRows.Count > 0)
                {
                    DialogResult result = MessageBox.Show("確定要刪除嗎?", "提示", MessageBoxButtons.OKCancel);
                    if (result == DialogResult.Cancel)
                    {
                        return;
                    }
                    int x = int.Parse(dataGridView1.SelectedRows[0].Cells[0].Value.ToString());
                    SqliteHelper.Delete(x);
                    LoadPeopleList();
                }
                else
                {
                    MessageBox.Show("請選擇需要刪除的行", "提示", MessageBoxButtons.OK);
                }
            }
            catch(Exception x)
            {
                MessageBox.Show(this, x.Message, "Error", MessageBoxButtons.OK);
            }
            
        }

五、Dapper的複雜操作

查詢的In操作

public static List<PeopleModel> QueryIn()
{
    using (IDbConnection connection = new SqlConnection(connectionString))
    {
        var sql = "select * from people where id in @ids";
        //引數型別是Array的時候,dappper會自動將其轉化
        return connection.Query<Person>(sql, new { ids = new int[2] { 1, 2 }, }).ToList();
    }
}

public static List<PeopleModel> QueryIn(int[] ids)
{
    using (IDbConnection connection = new SqlConnection(connectionString))
    {
        var sql = "select * from people where id in @ids";
        //引數型別是Array的時候,dappper會自動將其轉化
        return connection.Query<Person>(sql, new { ids }).ToList();
    }
}

處理多個表
我們也會遇到一次需要處理多個表的需求,例如一次查詢多個表或者以外來鍵獲取資料
1、我們可以用Dapper同時訪問多個表,並且十分平滑
2、傳遞物件列表,Dapper本事可以識別出是批量插入
3、根據各種引數獲取資料,Dapper會自動將陣列轉換成CSV,並返回一個List物件
在這裡插入圖片描述
在兩個表上同時執行CRUD操作,使用相同的ContactId,即Contacts表中的主鍵,Address表中的外來鍵,現在讓我們通過傳遞Id從Contacts表和Address表中獲取多條資料:

static IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLDB"].ConnectionString);
string query = "select * from contacts where id = @id ; select * from address where ContactId = @id;";
using (var multipleresult = db.QueryMultiple(query, new { id = 1 }))
            {
                var contact = multipleresult.Read<Contact>().SingleOrDefault();
                var Addresses = multipleresult.Read<Address>().ToList();
                if (contact != null && Addresses != null)
                {
                    contact.Addresses.AddRange(Addresses);
                }
            }

使用儲存過程訪問資料庫
以下為sql的一個儲存過程:

Use ContactDB
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[sp_GetContact_Address]  
    @Id int 
AS
BEGIN
select * from contacts where id = @Id ;   
select * from Address where ContactId = @Id; 
END
GO

用Dapper呼叫儲存過程

第一步同上

在這裡不需要寫任何的query語句,相反的我們將呼叫資料庫內的儲存過程
在這裡將做的更改是傳遞一個儲存過程的名稱而不是查詢語句,並傳遞一個名稱為command type的引數。

using (var multipleresult = db.QueryMultiple("sp_GetContact_Address", new { id = 1 }, commandType: CommandType.StoredProcedure))
            {
                var contact = multipleresult.Read<Contact>().SingleOrDefault();
                var Addresses = multipleresult.Read<Address>().ToList();
                if (contact != null && Addresses != null)
                {
                    contact.Addresses.AddRange(Addresses);
                }
            }