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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...