還好有了 Dapper,讓在舊的專案開發架構中,可以漸進導入強型別方式與資料庫進行溝通,再也不用擔心資料欄位 Key 錯或是型別給錯這種問題發生 (呃…至少在偵錯過程前,Visual Studio 會派出紅色毛毛蟲提示啦)。不過畢竟 Dapper 只是個替代方案,仍無法完整取代完整 ORM 框架的 Entity Framework,因此目前還沒辦法像 EF 一樣,透過
include()的方式將關聯的類別資料一同載入以建立完整的導覽屬性。若要使用導覽屬性,目前得要透過「手動後製」方式完成囉。
首先,先定義我們的資料情境:
我們的目的是要將目前既有的所有課程以清單方式列出,而每筆課程資訊 (Course) 中,可一併取出該課程授課老師 (Teacher) 資訊及修課學生 (Student) 清單,而每個修課學生資訊中,還要取出該學生所住的地區資訊。完整的類別定義如下:
public class CourseStudent
{
public int CID { get; set; }
public int SID { get; set; }
public virtual Course CourseClass { get; set; }
public virtual IList<student> StudentClass { get; set; }
}
public class Course
{
public int CID { get; set; }
public int TID { get; set; }
public string CourseName { get; set; }
public virtual Teacher TeacherClass { get; set; }
public virtual IList<student> StudentClass { get; set; }
}
public class Teacher
{
public int TID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
}
public class Student
{
public int SID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public int LID { get; set; }
public virtual Location LocationClass { get; set; }
}
public class Location
{
public int LID { get; set; }
public string Name { get; set; }
}
接著要如何透過 Dapper 將完整的資訊放到 Course 類別呢? 以下展示兩種方式。
方法一
將所有資訊透過QueryMultiple將所需的所有資訊全部取出,再透過後製方式,建立導覽屬性:
//使用 QueryMultiple 將所需的資料全部取出
var results = conn.QueryMultiple(@"SELECT * FROM Course;
SELECT * FROM Course c LEFT JOIN Teacher t on c.TID = T.TID;
SELECT * FROM CourseStudent cs LEFT JOIN Student s ON cs.SID=s.SID;
SELECT * FROM Location;
SELECT * FROM Student;");
//依照順序讀取資料
var courses = results.Read<course>();
var teachers = results.Read<teacher>();
var course_students = results.Read<coursestudent>();
var locations = results.Read<location>();
var students = results.Read<student>();
//進行後製 => 手動建立導覽屬性
foreach (var course in courses)
{
//取得這筆課程的 Teacher 資訊
course.TeacherClass = teachers.Where(x => x.TID == course.TID).FirstOrDefault();
//取得這筆課程的修課學生清單
course.StudentClass = students.Where(s => (course_students.Where(x => x.CID == course.CID)
.Select(x => x.SID)).Contains(s.SID)).ToList();
//將 Location 資訊一筆筆寫至每個 Student 資訊內
foreach (var s in course.StudentClass)
{
s.LocationClass = locations.Where(l => l.LID == s.LID).FirstOrDefault();
}
}
方法二
透過一個 SQL 將所有資訊全部取出,透過指定splitOn方式拆解取得的內容以自動建立導覽屬性:
var lookup = new Dictionary<int, Course>();
conn.Query<Course, Student, Location, Course>(@"
SELECT c.*, s.*, l.*
FROM Course c
LEFT JOIN CourseStudent cs ON cs.CID = c.CID
LEFT JOIN Student s ON cs.SID = s.SID
LEFT JOIN Location l ON s.LID = l.LID
", (c, s, l) =>
{
Course course;
if (!lookup.TryGetValue(c.CID, out course))
{
lookup.Add(c.CID, course = c);
}
if (s != null && l != null)
{
s.LocationClass = l;
}
if (s!=null && course.StudentClass == null)
{
course.StudentClass = new List<student>();
}
if (s != null)
{
course.StudentClass.Add(s);
}
return course;
}, splitOn: "SID, LID").AsQueryable();
var resultList = lookup.Values;
這裡值得一提的是
splitOn的用法。
splitOn是告訴 Dapper 要將哪個欄位當作資料切割的起始點。預設的切割點為 ID 或 id。假設我們的切割點非預設,就必須要告訴 Dapper 切割點是哪個欄位 (多欄位以逗號分隔)。若取得的欄位如下:
OrderId | OrderDate | OrderOwerId | MemberId | MemberName | ProductId | ProductName假設我們將 MemberId 及 ProductId 作為分割點,這樣 Dapper 就會依照分割點的欄位,將資料切割為三個物件 (Object)
目前只知道有這兩種方法,期待還有其他更方便的方法!
參考資料:
沒有留言 :
張貼留言
注意:只有此網誌的成員可以留言。