最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

.NET9?EFcore支持早期MSSQL數(shù)據(jù)庫(kù)?ROW_NUMBER()分頁(yè)功能

 更新時(shí)間:2024年11月27日 09:58:03   作者:萬(wàn)雅虎  
文章介紹了如何在.NET?9中使用EF?Core實(shí)現(xiàn)對(duì)早期MSSQL數(shù)據(jù)庫(kù)的ROW_NUMBER()分頁(yè)兼容,由于EF?Core?9對(duì)底層API進(jìn)行了重大更新,原有的兼容代碼需要重新實(shí)現(xiàn),具體實(shí)現(xiàn)代碼跟隨小編一起看看吧

前言

NET程序員是很幸福的,MS在上個(gè)月發(fā)布了NET9.0RTM,帶來(lái)了不少的新特性,但是呢,還有很多同學(xué)軟硬件都還沒(méi)跟上時(shí)代的步伐,比如,自己的電腦還在跑Win7,公司服務(wù)器還在跑MSSQL2005-2008的!

這不就引入了我們本文要探索的問(wèn)題,因?yàn)镸S早在EFcore3.1后就不再內(nèi)置支持ROW_NUMBER()了,以至于需要兼容分頁(yè)的代碼都需要自行處理,當(dāng)然同學(xué)們?nèi)绻麑?duì)EFCore沒(méi)有依賴度也可以使用其他的ORM選型,當(dāng)然如果不想折騰EFCore也能使用萬(wàn)能的RawSql拼接執(zhí)行也是可以的 ??

最近自己發(fā)的Nuget包有個(gè)國(guó)外的程序員朋友提了一個(gè)Issue,以至于我馬上行動(dòng)起來(lái)

EFCore9中, 以前兼容的好好的ROW_NUMBER()代碼,升級(jí)嘗鮮后發(fā)現(xiàn)跑不起來(lái)了,這主要是因?yàn)樾掳姹镜腅FCore9做了很多破壞性更新,以至于我們不得不研究新的底層代碼!

兼容實(shí)現(xiàn)

之前發(fā)布過(guò)一個(gè)Nuget包,代碼主要是基于以前道友兼容EFCore7適配到EFCore8的兼容,代碼也不多變化也不大,不過(guò)呢,升級(jí)到EFCore9后發(fā)現(xiàn)底層的API全變了,不得不重新再實(shí)現(xiàn)一遍!

以下是兼容EFCore9的代碼部分:

#if NET9_0_OR_GREATER
#pragma warning disable EF1001 // Internal EF Core API usage.
namespace Biwen.EFCore.UseRowNumberForPaging;
using Microsoft.EntityFrameworkCore.Query;
using System.Collections.Generic;
public class SqlServer2008QueryTranslationPostprocessorFactory(
    QueryTranslationPostprocessorDependencies dependencies,
    RelationalQueryTranslationPostprocessorDependencies relationalDependencies) : IQueryTranslationPostprocessorFactory
{
    private readonly QueryTranslationPostprocessorDependencies _dependencies = dependencies;
    private readonly RelationalQueryTranslationPostprocessorDependencies _relationalDependencies = relationalDependencies;
    public virtual QueryTranslationPostprocessor Create(QueryCompilationContext queryCompilationContext)
        => new SqlServer2008QueryTranslationPostprocessor(
            _dependencies,
            _relationalDependencies,
            queryCompilationContext);
    public class SqlServer2008QueryTranslationPostprocessor(QueryTranslationPostprocessorDependencies dependencies, RelationalQueryTranslationPostprocessorDependencies relationalDependencies, QueryCompilationContext queryCompilationContext) :
        RelationalQueryTranslationPostprocessor(dependencies, relationalDependencies, (RelationalQueryCompilationContext)queryCompilationContext)
    {
        public override Expression Process(Expression query)
        {
            query = base.Process(query);
            query = new Offset2RowNumberConvertVisitor(query, RelationalDependencies.SqlExpressionFactory).Visit(query);
            return query;
        }
        internal class Offset2RowNumberConvertVisitor(
            Expression root,
            ISqlExpressionFactory sqlExpressionFactory) : ExpressionVisitor
        {
            private readonly Expression root = root;
            private readonly ISqlExpressionFactory sqlExpressionFactory = sqlExpressionFactory;
            private const string SubTableName = "subTbl";
            private const string RowColumnName = "_Row_";//下標(biāo)避免數(shù)據(jù)表存在字段
            protected override Expression VisitExtension(Expression node) => node switch
            {
                ShapedQueryExpression shapedQueryExpression => shapedQueryExpression.Update(Visit(shapedQueryExpression.QueryExpression), shapedQueryExpression.ShaperExpression),
                SelectExpression se => VisitSelect(se),
                _ => base.VisitExtension(node)
            };
            private SelectExpression VisitSelect(SelectExpression selectExpression)
            {
                var oldOffset = selectExpression.Offset;
                if (oldOffset == null)
                    return selectExpression;
                var oldLimit = selectExpression.Limit;
                var oldOrderings = selectExpression.Orderings;
                var newOrderings = oldOrderings switch
                {
                    { Count: > 0 } when oldLimit != null || selectExpression == root => oldOrderings.ToList(),
                    _ => []
                };
                var rowOrderings = oldOrderings.Any() switch
                {
                    true => oldOrderings,
                    false => [new OrderingExpression(new SqlFragmentExpression("(SELECT 1)"), true)]
                };
                var oldSelect = selectExpression;
                var rowNumberExpression = new RowNumberExpression([], rowOrderings, oldOffset.TypeMapping);
                // 創(chuàng)建子查詢
                IList<ProjectionExpression> projections = [new ProjectionExpression(rowNumberExpression, RowColumnName),];
                var subquery = new SelectExpression(
                    SubTableName,
                    oldSelect.Tables,
                    oldSelect.Predicate,
                    oldSelect.GroupBy,
                    oldSelect.Having,
                    [.. oldSelect.Projection, .. projections],
                    oldSelect.IsDistinct,
                    [],//排序已經(jīng)在rowNumber中了
                    null,
                    null,
                    null,
                    null);
                //構(gòu)造新的條件:
                var and1 = sqlExpressionFactory.GreaterThan(
                    new ColumnExpression(RowColumnName, SubTableName, typeof(int), null, true),
                    oldOffset);
                var and2 = sqlExpressionFactory.LessThanOrEqual(
                    new ColumnExpression(RowColumnName, SubTableName, typeof(int), null, true),
                    sqlExpressionFactory.Add(oldOffset, oldLimit));
                var newPredicate = sqlExpressionFactory.AndAlso(and1, and2);
                //新的Projection:
                var newProjections = oldSelect.Projection.Select(e =>
                {
                    if (e is { Expression: ColumnExpression col })
                    {
                        var newCol = new ColumnExpression(col.Name, SubTableName, col.Type, col.TypeMapping, col.IsNullable);
                        return new ProjectionExpression(newCol, e.Alias);
                    }
                    return e;
                });
                // 創(chuàng)建新的 SelectExpression,將子查詢作為來(lái)源
                var newSelect = new SelectExpression(
                    oldSelect.Alias,
                    [subquery],
                    newPredicate,
                    oldSelect.GroupBy,
                    oldSelect.Having,
                    [.. newProjections],
                    oldSelect.IsDistinct,
                    [],
                    null,
                    null,
                    null,
                    null);
                // projectionMapping replace
                var pm = new ProjectionMember();
                var projectionMapping = new Dictionary<ProjectionMember, Expression>
                {
                    {
                        pm,
                        oldSelect.GetProjection(new ProjectionBindingExpression(null,pm,null))
                    }
                };
                newSelect.ReplaceProjection(projectionMapping);
                return newSelect;
            }
        }
    }
}
#pragma warning restore EF1001 // Internal EF Core API usage.
#endif

最后

實(shí)現(xiàn)上邏輯還是一致的,反正都是將Offset轉(zhuǎn)換為ROW_NUMBER()子查詢中,取行號(hào)數(shù)據(jù)

只是代碼實(shí)現(xiàn)區(qū)別有一些,以前的EFCore底層代碼很多已經(jīng)不在可用比如直接使用PushdownIntoSubquery()會(huì)報(bào)錯(cuò),GenerateOuterColumn()內(nèi)部的擴(kuò)展方法發(fā)生了破壞性更新導(dǎo)致不能再使用等!

如果你的程序需要升級(jí)到NET9并還在使用早期數(shù)據(jù)庫(kù)的話,可以引用我實(shí)現(xiàn)的代碼部分,或者直接引用我發(fā)布的Nuget包

<PackageReference Include="Biwen.EFCore.UseRowNumberForPaging" Version="2.1.1" />

代碼我放在了GitHub,任何問(wèn)題歡迎Issue https://github.com/vipwan/Biwen.EFCore.UseRowNumberForPaging

到此這篇關(guān)于.NET9 EFcore支持早期MSSQL數(shù)據(jù)庫(kù) ROW_NUMBER()分頁(yè)的文章就介紹到這了,更多相關(guān).NET9 EFcore MSSQL數(shù)據(jù)庫(kù) ROW_NUMBER()分頁(yè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • .Net Core日志記錄之自定義日志組件

    .Net Core日志記錄之自定義日志組件

    這篇文章介紹了.Net Core日志記錄之自定義日志組件,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • asp.net 虛方法、抽象方法、接口疑問(wèn)

    asp.net 虛方法、抽象方法、接口疑問(wèn)

    asp.net 虛方法、抽象方法、接口疑問(wèn)等說(shuō)明。
    2009-06-06
  • asp.net 處理F5刷新頁(yè)面重復(fù)提交頁(yè)面的一個(gè)思路

    asp.net 處理F5刷新頁(yè)面重復(fù)提交頁(yè)面的一個(gè)思路

    當(dāng)提交完一個(gè)頁(yè)面后,如果我們?cè)俅吸c(diǎn)擊F5刷新該頁(yè)面的話,會(huì)彈出一個(gè)提示,提示我們?nèi)绻^續(xù),則會(huì)重新發(fā)送提交我們剛才提交的內(nèi)容,要是類似付款或一次性的操作,我們不應(yīng)該這樣操作,否則會(huì)造成重復(fù)提交的問(wèn)題。
    2010-02-02
  • ASP.NET MVC中設(shè)置跨域訪問(wèn)問(wèn)題

    ASP.NET MVC中設(shè)置跨域訪問(wèn)問(wèn)題

    這篇文章主要介紹了ASP.NET MVC中設(shè)置跨域訪問(wèn)問(wèn)題,需要的朋友可以參考下
    2018-06-06
  • 詳解如何在ASP.NET Core中使用IHttpClientFactory

    詳解如何在ASP.NET Core中使用IHttpClientFactory

    這篇文章主要介紹了詳解如何在ASP.NET Core中使用IHttpClientFactory,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • ASP.NET泛型二之泛型的使用方法

    ASP.NET泛型二之泛型的使用方法

    這篇文章介紹了ASP.NET泛型的使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • Visual Studio 2017正式版發(fā)布 亮點(diǎn)看這里

    Visual Studio 2017正式版發(fā)布 亮點(diǎn)看這里

    終于等到你,最強(qiáng) IDE Visual Studio 2017 正式版發(fā)布,這篇文章主要為大家詳細(xì)解析了Visual Studio 2017正式版發(fā)布的細(xì)節(jié),亮點(diǎn)看這里
    2017-03-03
  • ASP.NET設(shè)置404頁(yè)面返回302HTTP狀態(tài)碼的解決方法

    ASP.NET設(shè)置404頁(yè)面返回302HTTP狀態(tài)碼的解決方法

    訪問(wèn)網(wǎng)站時(shí)錯(cuò)誤頁(yè)面可正常顯示,但HTTP狀態(tài)碼卻是302,對(duì)SEO很不友好,按下列步驟修改使錯(cuò)誤頁(yè)面返回正確的利于SEO的404狀態(tài)碼,感興趣的朋友可以了解下
    2013-09-09
  • ASP.NET實(shí)現(xiàn)偽靜態(tài)網(wǎng)頁(yè)方法小結(jié)

    ASP.NET實(shí)現(xiàn)偽靜態(tài)網(wǎng)頁(yè)方法小結(jié)

    這篇文章主要介紹了ASP.NET實(shí)現(xiàn)偽靜態(tài)網(wǎng)頁(yè)方法小結(jié),主要包括了利用Httphandler實(shí)現(xiàn)URL重寫、地址重寫、利用Mircosoft URLRewriter.dll實(shí)現(xiàn)頁(yè)面?zhèn)戊o態(tài)等,需要的朋友可以參考下
    2014-09-09
  • asp.net中Response.Redirect與Server.Transfer的區(qū)別分析

    asp.net中Response.Redirect與Server.Transfer的區(qū)別分析

    一般來(lái)說(shuō)如果需要在兩個(gè)頁(yè)面間共享數(shù)據(jù),而且數(shù)據(jù)量比較大的時(shí)候,用transfer會(huì)比較合適,在第二個(gè)頁(yè)面中可以直接使用前一頁(yè)面的數(shù)據(jù)。
    2010-10-10

最新評(píng)論

丹寨县| 扶沟县| 凤冈县| 来安县| 库尔勒市| 河东区| 体育| 台南市| 县级市| 连城县| 景德镇市| 肇州县| 中超| 高平市| 鄂州市| 绿春县| 延川县| 西乌珠穆沁旗| 稷山县| 北流市| 丹巴县| 玛沁县| 莫力| 北宁市| 建平县| 丹凤县| 同仁县| 古浪县| 林芝县| 旺苍县| 钟山县| 建瓯市| 凤城市| 屯昌县| 新绛县| 玛曲县| 廉江市| 淄博市| 凌海市| 虞城县| 柳河县|