【橙子老哥】C# 硬核ShardingCore执行流程源码解读

hello,好久不见,大家好,欢迎来到橙子老哥的分享时刻,希望大家一起学习,一起进步。

欢迎加入.net意社区,第一时间了解我们的动态,文章第一时间分享至社区

社区官方地址:https://ccnetcore.com (上千.neter聚集地)(注册人数:1691人)

官方微信公众号:公众号搜索 意.Net

官方微信小程序:小程序搜索 意.Net

添加橙子老哥微信加入官方微信群:chengzilaoge520

1、引言

首先在这里,非常感谢薛家明前辈,本章分享的内容,就是他的开源巨作

sharding-core:https://github.com/dotnetcore/sharding-core

我很佩服的他的愿意有三个:

  1. sharding-core已被NCC收编,足以证明项目的质量,薛家明先生一直在主力维护着,为EFCore在分表分库下提供一个成熟的解决方案
  2. 薛家明先生撰写了非常多的有深度的文章博客,每一篇都可以学到很多东西,可以看出,是真心把知识分享了出去,但是本人却非常低调
  3. 薛家明先生不仅仅局限于.net,在java领域,同样开源了一个重量级优雅ORM项目:easy-query,设计方式与我想法不谋而同

献给转java的c#和java程序员的数据库orm框架
easy-query:https://github.com/dromara/easy-query

另外附上shardingcore的官方qq群:771630778 ,非常推荐大家加入,可以学习很多,备注橙子老哥推荐进群

本篇文章,比较硬核,就一起来探究下ShardingCore的源码吧

2、入口

众所皆知,efcore的代码出了名的难啃,不光量大,而且东西也特别抽象

对应的shardingcore的内容也非常非常多,而且很多地方借鉴了efcore的设计,所以阅读起来会比较有难度

本章只是对它的执行流程做一个大概的解读,不会精细到每一行

不过知道了大概的流程原理,等想看的时候或者出问题的时候,再去排查也是一个不错的选择

ShardingCore 一款efcore下高性能、轻量级针对分表分库读写分离的解决方案,具有零依赖、零学习成本、零业务代码入侵。

既然是基于EFcore的零业务代码入侵,那肯定要对Efcore进行扩展替换,我们直接从入口找找

在ShardingCoreExtension中,我们新增了shardingcode的服务,这里做了大量的依赖注入,其中UseDefaultSharding是对EFCORE的扩展


 services.AddDbContext<TShardingDbContext>(UseDefaultSharding<TShardingDbContext>, contextLifetime,
                optionsLifetime);
最终,我们执行到:

 public static DbContextOptionsBuilder UseSharding(
            this DbContextOptionsBuilder optionsBuilder, IShardingRuntimeContext shardingRuntimeContext)
        {
   
            return optionsBuilder
                .UseShardingWrapMark()
                .UseShardingMigrator()
                .UseShardingOptions(shardingRuntimeContext)
                .ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
                .ReplaceService<IDbSetInitializer, ShardingDbSetInitializer>()
                .ReplaceService<IChangeTrackerFactory, ShardingChangeTrackerFactory>()
                .ReplaceService<IDbContextTransactionManager,ShardingRelationalTransactionManager>()
                .ReplaceService<IStateManager,ShardingStateManager>()
                .ReplaceService<IRelationalTransactionFactory,ShardingRelationalTransactionFactory>();
        }

这里可以看到,替换了EfCore的非常多的服务,而今天,我们讲最核心的对象:IQueryCompiler

这个对象,是Efcore查询进行编译执行的内容,所以我们想知道具体shardingcode在查询的时候执行了什么,就看看ShardingQueryCompiler

3、ShardingQueryCompiler

EfCore对外提供了,IQueryCompiler接口,ShardingQueryCompiler是他的实现

所以,请记住,无论做了什么,最终返回的结果,就是为了Execute方法返回的

public interface IQueryCompiler
    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    TResult Execute<TResult>(Expression query);

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    TResult ExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken);

ShardingQueryCompiler包了一层,我们继续:

private readonly IShardingCompilerExecutor _shardingCompilerExecutor;
public override TResult Execute<TResult>(Expression query)
        {
   
            return _shardingCompilerExecutor.Execute<TResult>(_shardingDbContext, query);
        }

看看IShardingCompilerExecutor

  public TResult Execute<TResult>(IShardingDbContext shardingDbContext, Expression query)
        {
   
            //预解析表达式,通过ShardingQueryPrepareVisitor解析Expression query
            var prepareParseResult = _prepareParser.Parse(shardingDbContext,query);
            _logger.LogDebug($"compile parameter:{
     prepareParseResult}");
            using (new CustomerQueryScope(prepareParseResult,_shardingRouteManager))
            {
   
            //根据上面预解析表达式,获取出上下文
            //这里可以解析出QueryCompilerContext、MergeQueryCompilerContext两种类型
            //后面会根据类型的不一样,选择对应的处理逻辑
                var queryCompilerContext = _queryCompilerContextFactory.Create(prepareParseResult);
                //再包一层,IShardingTrackQueryExecutor,把解析的上下文给了它
                return _shardingTrackQueryExecutor.Execute<TResult>(queryCompilerContext);
            }
        }

4、IShardingTrackQueryExecutor

上面,我们可以看到,将解析的结果上下文传入IShardingTrackQueryExecutor,它的实现是:DefaultShardingTrackQueryExecutor,我们看看做了什么

 public TResult Execute<TResult>(IQueryCompilerContext queryCompilerContext)
        {
   
            var queryCompilerExecutor = queryCompilerContext.GetQueryCompilerExecutor();
            if (queryCompilerExecutor == null)
            {
   
            	//上下文类型是需要合并的
                if (queryCompilerContext is IMergeQueryCompilerContext mergeQueryCompilerContext)
                {
   
                   //走IShardingQueryExecutor的处理逻辑
                    return _shardingQueryExecutor.Execute<TResult>(mergeQueryCompilerContext);
                }
                throw new ShardingCoreNotFoundException(queryCompilerContext.GetQueryExpression().ShardingPrint());
            }

			//如果有原生的queryCompilerExecutor,直接走原生的EFCORE,不需要走shardingcode了
			//由于上面有return,上面的逻辑和下面的逻辑只会走一个
            //native query
            var result = queryCompilerExecutor.GetQueryCompiler().Execute<TResult>(queryCompilerExecutor.GetReplaceQueryExpression());
            //native query track
            return ResultTrackExecute(result, queryCompilerContext, TrackEnumerable, Track);

        }

到这里,我们需要处理的合并表的逻辑,就要看IShardingTrackQueryExecutor内,做了什么

        public TResult 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值