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

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

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

前言

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

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

最近自己發(fā)的Nuget包有個國外的程序員朋友提了一個Issue,以至于我馬上行動起來

EFCore9中, 以前兼容的好好的ROW_NUMBER()代碼,升級嘗鮮后發(fā)現(xiàn)跑不起來了,這主要是因為新版本的EFCore9做了很多破壞性更新,以至于我們不得不研究新的底層代碼!

兼容實現(xiàn)

之前發(fā)布過一個Nuget包,代碼主要是基于以前道友兼容EFCore7適配到EFCore8的兼容,代碼也不多變化也不大,不過呢,升級到EFCore9后發(fā)現(xiàn)底層的API全變了,不得不重新再實現(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,將子查詢作為來源
                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

最后

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

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

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

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

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

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

相關(guān)文章

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

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

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

    asp.net 虛方法、抽象方法、接口疑問

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評論

五家渠市| 大石桥市| 象山县| 井冈山市| 栾城县| 永善县| 邢台市| 宁安市| 克什克腾旗| 西青区| 色达县| 页游| 寻甸| 称多县| 隆德县| 荆州市| 沙河市| 高雄市| 黑河市| 曲阜市| 凤城市| 博白县| 休宁县| 攀枝花市| 邹平县| 白银市| 乌拉特后旗| 山阳县| 平凉市| 靖州| 邮箱| 浠水县| 彭州市| 青川县| 古田县| 乐平市| 墨脱县| 沅陵县| 靖安县| 海兴县| 嵊泗县|