理論篇告一段落,進入實戰範例,貫穿後續所有章節。
每個用戶擁有一個部落格,每篇文章屬於一個分類,用戶有角色。定義實體:
public class User {
public int UserId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string BlogName { get; set; }
public Role Role { get; set; }
}
public class Role {
public int RoleId { get; set; }
public string RoleName { get; set; }
}
public class Post {
public int PostId { get; set; }
public string Title { get; set; }
public string Abstract { get; set; }
public string Body { get; set; }
public string UserName { get; set; }
public int Click { get; set; }
public int Comments { get; set; }
public int CategoryId { get; set; }
}
假設啟動時將所有資料載入記憶體:IList<User> users、IList<Post> posts、IList<Role> roles,對這些集合進行 LINQ to Objects 操作。
依 URL 參數 u=yuyijq 查詢該部落主文章,僅需標題與摘要綁定 GridView:
var dataSource = from post in posts
where post.UserName == "yuyijq"
select post.Title;
mainGridView.DataSource = dataSource;
mainGridView.DataBind();
利用延遲執行特性,可使用變數:
string userName = Request.QueryString["u"];
var dataSource = from post in posts
where post.UserName == userName
select post.Title;
延遲執行驗證:
string userName = "zhzkl";
var dataSource = from post in posts where post.UserName == userName select post.Title;
userName = "yuyijq";
mainGridView.DataSource = dataSource;
mainGridView.DataBind(); // 實際繫結 yuyijq 的文章
舊版 ArrayList 實作 IEnumerable,需轉型:
var dataSource = from post in posts.Cast<Post>()
where post.UserName == userName
select post.Title;
Cast<T>() 逐一轉型,若有無法轉型元素會拋例外。保險用 OfType<T>() 僅保留可轉型元素。
使用者可自訂排序依據(點擊率、評論數等)。OrderBy 需傳入 key selector delegate,可封裝排序方法:
public IEnumerable<Post> Sort<TKey>(string userName, Func<Post, TKey> selector, bool isAsc) {
var newPosts = from post in posts where post.UserName == userName select post;
return isAsc ? newPosts.OrderBy(selector) : newPosts.OrderByDescending(selector);
}
多重排序:orderby post.Click, post.Comments 會轉為 OrderBy(...).ThenBy(...)。
依 UserName 分組:
var dataSource = from post in posts group post.Title by post.UserName;
多鍵分組需用匿名型別:
var dataSource = from post in posts group post.Title by new { post.UserName, post.CategoryId };
使用 into 繼續查詢:
var dataSource = from post in posts
group post by post.UserName into grouping
select new { Key = grouping.Key, TotalClick = grouping.Sum(p => p.Click) };
依 UserId 找 UserName 再找 Post:
var dataSource = from post in posts
join user in users on post.UserName equals user.UserName
where user.UserId == 2
select post;
注意:聯結條件用 equals 而非 ==。
本篇以實例說明重點用法。LINQ 雖效能略遜傳統寫法,但在複雜聯結/分組時程式碼簡潔度極高。效能問題如 Rails 作者所言:「當效能未成問題前,它永遠不是問題」。