因為對 Join Table的結果不太熟,想說做個紀錄
順便把Dapper對 Join 和 一般ADO直接取出結果來做個比較
以下內容簡單測試,命名或是Table只是做Demo使用,不要太計較正規性
對Dapper的操作及 SQL的指令,請自行上網研究
Join的觀念可以參考這篇文章,寫得算清楚
https://dotblogs.com.tw/caubekimo/2010/07/28/16874
首先資料庫裡兩張表格的內容如下圖
Dapper 所需要使用的 DataClass
// Join的表格 public class JoinTable { public int MemberId { get; set; } public string Name { get; set; } public int BookId { get; set; } public string BookName { get; set; } public int Price { get; set; } } // 原始的Table public class MemberTable { public int MemberId { get; set; } public string Name { get; set; } public int BookId { get; set; } } // 原始的Table public class BookTable { public int BookId { get; set; } public string Name { get; set; } public int Price { get; set; } }
using (var connection = new SqlConnection(connectionStr)) { string commandStr = "SELECT * FROM MemberTable LEFT JOIN BookTable ON MemberTable.BookId = BookTable.BookId"; using (SqlCommand command = new SqlCommand(commandStr, connection)) { SqlDataAdapter dataAdapter = new SqlDataAdapter(command); // 透過 SqlDataAdapter 執行 Command內容將資料填入 dataTable // P.S.忘記在哪本書有看過 SqlDataAdapter 會自動將 SqlConnection-Open DataTable dataTable = new DataTable(); dataAdapter.Fill(dataTable); // 將DB的資料Select出來後跟UI做Binding dataGridView1.DataSource = dataTable; } }
結果如下圖
使用方法參閱 http://dapper-tutorial.net/result-multi-mapping
using (var connection = new SqlConnection(connectionStr)) { connection.Open(); string commandStr = "SELECT * FROM MemberTable LEFT JOIN BookTable ON MemberTable.BookId = BookTable.BookId"; //var dapperData = connection.Query(commandStr); //取出結果是dynamic,不知道為什麼 設定DataSource無效果 var dapperData = connection.Query<MemberTable, BookTable, JoinTable>(commandStr, (member, book) => { return new JoinTable { MemberId = member.MemberId, Name = member.Name, BookId = member.BookId, BookName = (book == null) ? null : book.Name, Price = book == null ? 0 : book.Price, }; }, splitOn: "BookId") .ToList(); // 將DB的資料Select出來後跟UI做Binding dataGridView1.DataSource = dapperData; }
結果如下圖
理論上Dapper 使用上還有其它的變化
如這篇教學 http://mirchetoshevski.com/blog/2017/08/08/dapper-tutorial-2/
可惜,我看不懂他的DataClass結構方式,所以他第二種方式,我測試不出來
另外查詢指令上直接給 as 變數名稱,也可以直接把結果配回,只是就變成Table每個欄位都要填寫
public class MemberTable { public int MemberId { get; set; } public string Name { get; set; } public int BookId { get; set; } public BookTable BooKData { get; set; } }
將 BookTable 放進MemberTable 的DataClass裡面
之後再查詢結果把Book配進去即可
var dapperData = connection.Query<MemberTable, BookTable, MemberTable>(commandStr, (member, book) => { member.BooKData = book; return member; }, splitOn: "BookId") .ToList();
只是這種作法如果直接將 dataGridView1.DataSource = dapperData;
做設定,會出現如下圖的問題,跑出來的表格格式並不項是我想要的
WPF的話,可以從DataTemplate去設定Binding的資料。
Winform的話,應該是可以從 dataGridView1.DataBindings 內部去設定
不過我還沒研究出來,而且這種做法會不會比較方便,我也不清楚
所以我基本上會再做一個顯示用的DataClass
看到有一種做法,提供參考如下
public class MemberTable { public int MemberId { get; set; } public string Name { get; set; } public int BookId { get; set; } private BookTable BookData { get; set; } public void SetBook (BookTable booKData) { BookData = booKData; } [DisplayName("BookName")] public string BName { get { return BookData?.Name; } set { BookData.Name = value; } } [DisplayName("BookPrice")] public int? BPrice { get { return BookData?.Price; } set { BookData.Price = value; } } } public class BookTable { public int BookId { get; set; } public string Name { get; set; } public int? Price { get; set; } }
因為book查出來會有可能是null,所以在顯示要用到 BPrice這屬性的時候
要把int改成 Nullable<int>,否則會出問題,理論上我參數設定應該在Set也會出問題才對
只是不知道為什麼在搭配dataGridView.DataSource在存取資料 Set沒跳錯誤,我猜應該是在Binding時不會使用到Set
var dapperData = connection.Query<MemberTable, BookTable, MemberTable>(commandStr, (member, book) => { member.SetBook(book); return member; }, splitOn: "BookId") .ToList();
結果如下圖
整體作法就是把實際資料改成private 這樣在Binding的時候就不會拿這屬性來用
之後再創建要顯示的屬性去存取實際資料。順便使用 [DisplayName("Name")]
這Attribute,來做UI顯示的名稱。剛好在網路上有看到順便紀錄一下這用法
重點就是在資料Null的時候,存取不發生錯誤的處理
Join三張表的Demo,簡單的給予參考
新增一張表為出版社
然後Book的Table新增一個欄位
using (var connection = new SqlConnection(connectionStr)) { string commandStr = "SELECT * FROM MemberTable LEFT JOIN BookTable ON MemberTable.BookId = BookTable.BookId "; commandStr += "LEFT JOIN PublisherTable ON BookTable.PublisherId = PublisherTable.Id "; using (SqlCommand command = new SqlCommand(commandStr, connection)) { SqlDataAdapter dataAdapter = new SqlDataAdapter(command); DataTable dataTable = new DataTable(); dataAdapter.Fill(dataTable); dataGridView1.DataSource = dataTable; } }
查詢後結果會如下圖
(有一些Nullable的要自己去補,我這只是簡單做個參考而已,很有可能會跳錯誤)
public class MemberTable { public int MemberId { get; set; } public string Name { get; set; } public int BookId { get; set; } private BookTable BookData { get; set; } public void SetBook(BookTable booKData) { BookData = booKData; } [DisplayName("BookName")] public string BName { get { return BookData?.Name; } set { BookData.Name = value; } } [DisplayName("BookPrice")] public int? BPrice { get { return BookData?.Price; } set { BookData.Price = value; } } public string PublisherName { get { return BookData?.PublisherName; } set { BookData.PublisherName = value; } } public string PublisherAddress { get { return BookData?.PublisherAddress; } set { BookData.PublisherAddress = value; } } } public class BookTable { public int BookId { get; set; } public string Name { get; set; } public int? Price { get; set; } public int? PublisherId { get; set; } private PublisherTable PublisherData { get; set; } public void SetPublisher(PublisherTable publisherData) { PublisherData = publisherData; } public string PublisherName { get { return PublisherData?.Name; } set { PublisherData.Name = value; } } public string PublisherAddress { get { return PublisherData?.Address; } set { PublisherData.Address = value; } } } public class PublisherTable { public int Id { get; set; } public string Name { get; set; } public string Address { get; set; } }
查詢的方法修改如下
var dapperData = connection.Query<MemberTable, BookTable, PublisherTable, MemberTable>(commandStr, (member, book, publisher) => { book?.SetPublisher(publisher); member.SetBook(book); return member; }, splitOn: "BookId, PublisherId") .ToList();
注意 splitOn: "BookId, PublisherId" 的設定,
Dapper是裡用這邊給的參數去將查詢的結果分割然後Mapping到DataClass裡面
最後查詢結果如下圖
除了 Inner Join之外,其餘都要注意DataClass是Null的時候
因資料結構上的關係做Right Join的時候 Dapper理論上不太可能直接達到
變成Right的DataClass需要做初始值,當NULL的時候直接使用初始值
這就是都看使用情況去做調整,如果只是要簡單做表格,或許直接使用ADO反而簡單使用
不過大部分的時候,DataClass基礎的處理方式訂好,把Null的規則定義好,未來擴充也還算方便。
此篇大致上到這樣,如果未來有想到什麼再補充了