EF CodeFirst 不得不說的Where與OrderBy

来源:http://www.cnblogs.com/c-o-d-e/archive/2016/02/21/5205680.html
-Advertisement-
Play Games

先來聊上5毛錢的“排序” Code: using (ApplicationDbContext Db=new ApplicationDbContext()) { var res = Db.Threes.OrderBy(t => t.Id); } So Easy。現實往往不是這樣的,有時我們需要讓它靈活


先來聊上5毛錢的“排序”

Code

using (ApplicationDbContext Db=new ApplicationDbContext())

{

var res = Db.Threes.OrderBy(t => t.Id);

}

So Easy。現實往往不是這樣的,有時我們需要讓它靈活一點,如下這樣方在一個函數里

Code:

public List<ApplicationDbContext.Three> GetAll()

{

using (ApplicationDbContext Db = new ApplicationDbContext())

{

return Db.Threes.OrderBy(t => t.Id).ToList();

}

}

顯然這個代碼是不靈活的,如果我們不想按照ID排序了,再去寫一個方法就不好了。為了靈活我們可以把排序寫在外面,在裡面調用。怎樣才能在方法里執行外面的排序?委托就可以

Code:

public ActionResult Index()

{

GetAll(db => db.OrderBy(t => t.Id));//註釋1:隨意設置排序欄位

return View();

}

public IOrderedQueryable<ApplicationDbContext.Three> GetAll(Func<IQueryable<ApplicationDbContext.Three>,IOrderedQueryable<ApplicationDbContext.Three>> order)

{

using (ApplicationDbContext Db = new ApplicationDbContext())

{

var data = Db.Threes.Select(t => new ApplicationDbContext.Three { Id = t.Id });

return order(data);

}

}

在註釋1的地方OrderBy里的表達式就可以改變排序的欄位。這樣就比靈活了許多。這樣還是不夠靈活,很多情況下我們的排序欄位是前端傳過來的。IQueryable的擴轉方法OrderBy接受一個表達式類型的參數,我們可以把前端傳過來的值生成一個表達式

Code:

生成表達式

private static LambdaExpression GetLambdaExpression<T>(string propertyName)

{

ParameterExpression parameter = Expression.Parameter(typeof(T));

MemberExpression body = Expression.Property(parameter, propertyName);

return Expression.Lambda(body, parameter);

}

排序方法

public static IOrderedQueryable<T> OrderBy<T>(IQueryable<T> source, string propertyName)

{

dynamic orderByExpression = GetLambdaExpression<ApplicationDbContext.Three>(propertyName);

return Queryable.OrderBy(source, orderByExpression);

}

使用例子

public ActionResult Index()

{

GetAll("Id");

return View();

}

public List<ApplicationDbContext.Three> GetAll(string orderByName)

{

using (ApplicationDbContext Db = new ApplicationDbContext())

{

var data = Db.Threes.Where(t => t.Id > 0);

return OrderBy(data,orderByName).ToList();}

}

}

在排序方法里我們調用了生成表達式方法,把結果返回給動態類型變數,這樣做是為瞭解決類型不對應的問題。最後調用Queryable.OrderBy方法把數據以及表達式作為參數。為了使用方便,我們把OrderBy方法改成擴展方法,加個this就可以了。

排序方法

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)

{

dynamic orderByExpression = GetLambdaExpression<ApplicationDbContext.Three>(propertyName);

return Queryable.OrderBy(source, orderByExpression);

}

使用例子

using (ApplicationDbContext Db = new ApplicationDbContext())

{

var data =  Db.Threes.OrderBy1("Id").ToList();

}

是不是簡單了很多。

再來聊聊“Where”

Code:

using (ApplicationDbContext Db = new ApplicationDbContext())

{

Db.Threes.Where(t => t.Id == 1);

}

這樣寫如果我們想要再加一個條件該怎麼辦呢。

Db.Threes.Where(t => t.Id == 1).Where(t => t.Text == "");

這樣連續的Where都是“and”如果想要“or”該怎麼辦呢,還是要依賴於表達式

Code:

生成表達式

public static class PredicateBuilder

{

public static Expression<Func<T, bool>> True<T>() { return f => true; }

public static Expression<Func<T, bool>> False<T>() { return f => false; }

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)

{

var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());

var ExBody = Expression.Or(expr1.Body, invokedExpr);

return Expression.Lambda<Func<T, bool>>

(ExBody, expr1.Parameters);

}

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)

{

var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());

return Expression.Lambda<Func<T, bool>>

(Expression.And(expr1.Body, invokedExpr), expr1.Parameters);

}

}

使用例子

var predicate = PredicateBuilder.False<ApplicationDbContext.Three>();

predicate = predicate.Or(p => p.Text== "2");

redicate = predicate.Or(p => p.Text == "1");

var func = predicate.Compile();//註釋一

using (ApplicationDbContext Db = new ApplicationDbContext())

{

Db.Threes.Where(func);

}

這就就可以收索出Text是“2”或者是“1”的數據了。其實這樣有一個問題,看註釋一,這是把表達式生成委托傳遞進去的,所以是把全部數據載入到記憶體後篩選結果的。那如何才能不載入全部數據呢,請看下麵。

Code:

從新綁定參數

public class ParameterRebinder : ExpressionVisitor

{

private readonly Dictionary<ParameterExpression, ParameterExpression> map;

public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)

{

this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();

}

public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)

{

return new ParameterRebinder(map).Visit(exp);

}

protected override Expression VisitParameter(ParameterExpression p)

{

ParameterExpression replacement;

if (map.TryGetValue(p, out replacement))

{

p = replacement;

}

return base.VisitParameter(p);

}

}

生成表達式

public static class PredicateBuilder

{

public static Expression<Func<T, bool>> True<T>() { return f => true; }

public static Expression<Func<T, bool>> False<T>() { return f => false; }

public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)

{

var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);

var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);

}

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)

{

return first.Compose(second, Expression.And);

}

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)

{

return first.Compose(second, Expression.Or);

}

}

使用例子

var predicate = PredicateBuilder.False<ApplicationDbContext.Three>();

predicate = predicate.Or(p => p.Text != "2");

using (ApplicationDbContext Db = new ApplicationDbContext())

{

Db.Threes.Where(predicate);

}

此方法和上面的方法關鍵都是替換表達的參數,保證每一個表達式的參數都是同一個。

上面的方法是採用Expression.Invoke實現統一參數的,因為使用了Expression.Invoke,所以要編譯成可執行代碼,轉換成委托,這樣就要先全部載入數據到記憶體後處理了。現在的方法是採用重寫ExpressionVisitor里的VisitParameter方法來實現參數統一的。

這樣就實現了我們先要的,可是很多情況下,查詢條件也是從前端傳遞過來的。那我們如何實現這樣的需求呢。上神器:Linq 動態查詢庫,System.Linq.Dynamic

URL:http://dynamiclinq.codeplex.com/documentation

Code:

使用例子

using (ApplicationDbContext Db = new ApplicationDbContext())

{

var lala = Db.Threes.Where("Id!=2").OrderBy("Id");

}

不單單支持Where、OrderBy還有GroupBy、Selec、Ski、Take、Union等擴展方法

是不是很爽,是不是恨我沒有一開始就寫這個。

2016年:讓我們更努力一點,夢想更靠近一點,把時間更多的浪費在美好的事物上面。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Visual Studio .net從2003到現在的2008,一路走來慢慢強大……從以前的vs2003能自動改亂你的html代碼到現在在vs2008中都能直接對html代碼進行w3c標準驗證並提示了,非常不易。 論壇中也經常有從事.net開發的新手朋友問一些asp.net開發過程中與web標準之間
  • 故事背景大概是這樣的,我廠兩年前給山西晉城人民政府做了一個門戶網站(地址:http://jccq.cn/),運行了一年多固若金湯,duang的有一天市場部門過來說,新聞管理模塊帶視頻的內容播放不了了。 迅雷不及掩耳,我打開網頁F12一看,因為找不到視頻播放的一個swf文件,仔細一看這個文件竟然引用的
  • 1.如果可能儘量使用介面來編程 .NET框架包括類和介面,在編寫程式的時候,你可能知道正在用.NET的哪個類。然而,在這種情況下如果你用.NET支持的介面而不是它的類來編程時,代碼會變得更加穩定、可用性會更高。 請分析下麵的代碼: 1 private void LoadList (object []
  • //NPOIHelper 類關鍵代碼 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.IO; using NPO
  • 出處:http://zhuqil.cnblogs.com 概述 與httpwath相比,fiddler能模擬http請求、能斷點調試、http分析統計吸引了我,使用之後感覺這個工具非常不錯,這篇文章只單介紹一下fiddler工作原理,簡單介紹一下它的重要功能,以及如何使用使用fiddler模擬htt
  • 一、業務邏輯層的架構 Ninesky.Core包含兩個命名空間Ninesky.Core和 Ninesky.Core.Types. Ninesky.Core包含模型和功能實現,Ninesky.Core.Types是項目用到的一些類型的定義。 1、Ninesky.Core命名空間的結構 NineskyC...
  • //多表多行多列的情況 foreach (DataTable dt in YourDataset.Tables) //遍歷所有的datatable { foreach (DataRow dr in dt.Rows) ///遍歷所有的行 foreach (DataColumn dc in dt.Col
  • 一,哈希表(Hashtable)簡述 在.NET Framework中,Hashtable是System.Collections命名空間提供的一個容器,用於處理和表現類似keyvalue的鍵值對,其中key通常可用來快速查找,同時key是區分大小寫;value用於存儲對應於key的值。Hashtab
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...