使用 Dynamic LINQ 補足強型別所帶來的小遺憾
前言
在開發撰寫LINQ語句時,透過其強型別的特性再搭配Intellisense輔助,讓我們可以行雲流水般地使用Lambda運算式篩選所需資料;但是當我們的條件是透過前端傳回,例如由前端控制資料排序是依據哪個欄位,所以只會回傳欄位名稱字串,此時若只允許以強型別方式操作LINQ就會形成莫大的阻力了,當然還是可以自行使用反射(Reflection)方式來解決,但還有更好的方式就是使用 Dynamic LINQ 來達成。以下介紹。
環境
System.Linq.Dynamic 1.0.4
案例說明
誠如前言所述,我們需要一個測驗(Quiz)資料排序功能,定義Quiz物件包含資訊學生ID及各項成績如下。
public class Quiz
{
public int StudentId { get; set; }
public int MathScore { get; set; }
public int ChineseScore { get; set; }
}
前端就只回傳排序欄位(sortKey)名稱與排列方向(isDesc),接著就依據該名稱來對資料進行排序。
public class QuizController : Controller
{
public ActionResult SortQuiz(string sortKey = "MathScore", bool isDesc = false)
{
// sample data
var quizzes = new List<Quiz>()
{
new Quiz() {StudentId=1, MathScore=33, ChineseScore=88},
new Quiz() {StudentId=2, MathScore=88, ChineseScore=66},
new Quiz() {StudentId=3, MathScore=11, ChineseScore=22}
}.AsQueryable();
// sort data
quizzes = Sort(quizzes, sortKey, isDesc);
return View(quizzes);
}
}
如果使用直挺挺的方式處理排序功能,約略代碼如下。
public IQueryable<Quiz> Sort(IQueryable<Quiz> quizzes, string key, bool isDesc)
{
Expression<Func<Quiz, object>> sortExpression;
switch (key)
{
case "StudentId":
sortExpression = (q => q.StudentId);
break;
case "MathScore":
sortExpression = (q => q.MathScore);
break;
case "ChieseScore":
sortExpression = (q => q.ChineseScore);
break;
default:
sortExpression = (q => q.StudentId);
break;
}
// sort direction
quizzes = isDesc
? quizzes.OrderByDescending(sortExpression)
: quizzes.OrderBy(sortExpression);
return quizzes;
}
從上面的代碼中不難發現,為了遷就其強型別的特性而造成程式碼過於攏長;因此這時就可以使用 Dynamic LINQ 來處理不同欄位排序問題。首先請先至NuGet安裝 System.Linq.Dynamic Package。
引用 Dynamic LINQ 後就可以使用字串方式來撰寫LINQ。我們可以發現程式碼變得相當精簡,就如同在編寫SQL語句般地暢快,但此舉會讓程式缺乏編譯時偵錯的保護,因此需特別注意傳入 key 值是否與屬性名稱一致,如果傳入值異常,那麼這個錯誤最終就只會在Runtime炸開而造成災情。
using System.Linq.Dynamic;
public IQueryable<Quiz> Sort(IQueryable<Quiz> quizzes, string key, bool isDesc)
{
quizzes = quizzes.OrderBy(key + (isDesc ? " descending" : ""));
return quizzes;
}
執行結果如下所示,排序條件與撈出資料順序相符
除排序(OrderBy)功能外,搜尋條件(Where)也可使用字串方式進行,參考代碼如下。
執行結果如下所示,篩選及排序條件與撈出資料相符
參考資訊
http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library
https://ericflemingblog.wordpress.com/2015/01/02/dynamic-linq-queries/
希望此篇文章可以幫助到需要的人
若內容有誤或有其他建議請不吝留言給筆者喔 !