From afef8e7d8bbbcc9cb7aca420a74f23785b37858f Mon Sep 17 00:00:00 2001 From: xuejiaming <326308290@qq.com> Date: Wed, 19 Jul 2023 15:13:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=85=E5=88=86=E5=BA=93track?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ShardingCore.sln | 7 ++ .../Controllers/WeatherForecastController.cs | 38 +++++++++ .../Domain/MyDbContext.cs | 25 ++++++ .../Domain/SysUser.cs | 8 ++ .../Domain/SysUserVirtualDataSourceRoute.cs | 55 +++++++++++++ samples/Sample.MySQLDataSourceOnly/Program.cs | 77 +++++++++++++++++++ .../Properties/launchSettings.json | 41 ++++++++++ .../Sample.MySQLDataSourceOnly.csproj | 19 +++++ .../WeatherForecast.cs | 12 +++ .../appsettings.Development.json | 8 ++ .../appsettings.json | 9 +++ .../Controllers/WeatherForecastController.cs | 13 ++++ samples/Sample.MySql/Startup.cs | 8 ++ .../RoutingRuleEngine/TableRouteRuleEngine.cs | 7 +- .../MergeQueryCompilerContext.cs | 2 +- .../Sharding/StreamMergeContext.cs | 38 ++++----- 16 files changed, 342 insertions(+), 25 deletions(-) create mode 100644 samples/Sample.MySQLDataSourceOnly/Controllers/WeatherForecastController.cs create mode 100644 samples/Sample.MySQLDataSourceOnly/Domain/MyDbContext.cs create mode 100644 samples/Sample.MySQLDataSourceOnly/Domain/SysUser.cs create mode 100644 samples/Sample.MySQLDataSourceOnly/Domain/SysUserVirtualDataSourceRoute.cs create mode 100644 samples/Sample.MySQLDataSourceOnly/Program.cs create mode 100644 samples/Sample.MySQLDataSourceOnly/Properties/launchSettings.json create mode 100644 samples/Sample.MySQLDataSourceOnly/Sample.MySQLDataSourceOnly.csproj create mode 100644 samples/Sample.MySQLDataSourceOnly/WeatherForecast.cs create mode 100644 samples/Sample.MySQLDataSourceOnly/appsettings.Development.json create mode 100644 samples/Sample.MySQLDataSourceOnly/appsettings.json diff --git a/ShardingCore.sln b/ShardingCore.sln index 234b24bb..392828bd 100644 --- a/ShardingCore.sln +++ b/ShardingCore.sln @@ -73,6 +73,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCore3", "src3\Shard EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCore2", "src2\ShardingCore2\ShardingCore2.csproj", "{F0393C32-2285-4F47-AC61-C1BA1CAC269D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.MySQLDataSourceOnly", "samples\Sample.MySQLDataSourceOnly\Sample.MySQLDataSourceOnly.csproj", "{3B5A4B03-5190-41A8-8E4B-F95A79A5C018}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -187,6 +189,10 @@ Global {F0393C32-2285-4F47-AC61-C1BA1CAC269D}.Debug|Any CPU.Build.0 = Debug|Any CPU {F0393C32-2285-4F47-AC61-C1BA1CAC269D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F0393C32-2285-4F47-AC61-C1BA1CAC269D}.Release|Any CPU.Build.0 = Release|Any CPU + {3B5A4B03-5190-41A8-8E4B-F95A79A5C018}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B5A4B03-5190-41A8-8E4B-F95A79A5C018}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B5A4B03-5190-41A8-8E4B-F95A79A5C018}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B5A4B03-5190-41A8-8E4B-F95A79A5C018}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -219,6 +225,7 @@ Global {E5E48D52-CAD3-42F0-82CD-A2A6180F3C4D} = {53D07876-A791-46AE-8381-08557593693D} {B59909AD-8885-40F3-9454-6C8433463BCC} = {51E1D067-3E81-4815-94F2-F8ABBE80881E} {F0393C32-2285-4F47-AC61-C1BA1CAC269D} = {B11D7DF7-A907-407E-8BF1-35B430413557} + {3B5A4B03-5190-41A8-8E4B-F95A79A5C018} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8C07A667-E8B4-43C7-8053-721584BAD291} diff --git a/samples/Sample.MySQLDataSourceOnly/Controllers/WeatherForecastController.cs b/samples/Sample.MySQLDataSourceOnly/Controllers/WeatherForecastController.cs new file mode 100644 index 00000000..eda32c5d --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/Controllers/WeatherForecastController.cs @@ -0,0 +1,38 @@ +using Microsoft.AspNetCore.Mvc; +using Sample.MySQLDataSourceOnly.Domain; + +namespace Sample.MySQLDataSourceOnly.Controllers; + +[ApiController] +[Route("[controller]")] +public class WeatherForecastController : ControllerBase +{ + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + private readonly MyDbContext _myDbContext; + + public WeatherForecastController(ILogger logger,MyDbContext myDbContext) + { + _logger = logger; + _myDbContext = myDbContext; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + var user = _myDbContext.Set().FirstOrDefault(o=>o.Id=="1"); + user.Name = "456"+DateTime.Now.ToString(); + _myDbContext.SaveChanges(); + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } +} \ No newline at end of file diff --git a/samples/Sample.MySQLDataSourceOnly/Domain/MyDbContext.cs b/samples/Sample.MySQLDataSourceOnly/Domain/MyDbContext.cs new file mode 100644 index 00000000..a2d7d1b6 --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/Domain/MyDbContext.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using ShardingCore.Sharding; + +namespace Sample.MySQLDataSourceOnly.Domain; + + +public class MyDbContext : AbstractShardingDbContext +{ + public MyDbContext(DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.Entity(entity => + { + entity.HasKey(o => o.Id); + entity.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(50); + entity.Property(o => o.Name).IsRequired().IsUnicode(false).HasMaxLength(50); + entity.Property(o => o.Area).IsRequired().IsUnicode(false).HasMaxLength(50); + entity.ToTable(nameof(SysUser)); + }); + } +} \ No newline at end of file diff --git a/samples/Sample.MySQLDataSourceOnly/Domain/SysUser.cs b/samples/Sample.MySQLDataSourceOnly/Domain/SysUser.cs new file mode 100644 index 00000000..67b50cd8 --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/Domain/SysUser.cs @@ -0,0 +1,8 @@ +namespace Sample.MySQLDataSourceOnly.Domain; + +public class SysUser +{ + public string Id { get; set; } + public string Name { get; set; } + public string Area { get; set; } +} \ No newline at end of file diff --git a/samples/Sample.MySQLDataSourceOnly/Domain/SysUserVirtualDataSourceRoute.cs b/samples/Sample.MySQLDataSourceOnly/Domain/SysUserVirtualDataSourceRoute.cs new file mode 100644 index 00000000..69a54846 --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/Domain/SysUserVirtualDataSourceRoute.cs @@ -0,0 +1,55 @@ +using ShardingCore.Core.EntityMetadatas; +using ShardingCore.Core.VirtualRoutes; +using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions; + +namespace Sample.MySQLDataSourceOnly.Domain; + +public class SysUserVirtualDataSourceRoute : AbstractShardingOperatorVirtualDataSourceRoute +{ + private readonly List _dataSources = new List() + { + "A", "B", "C" + }; + protected string ConvertToShardingKey(object shardingKey) + { + return shardingKey?.ToString() ?? string.Empty; + } + + //我们设置区域就是数据库 + public override string ShardingKeyToDataSourceName(object shardingKey) + { + return ConvertToShardingKey(shardingKey); + } + + public override List GetAllDataSourceNames() + { + return _dataSources; + } + + public override bool AddDataSourceName(string dataSourceName) + { + if (_dataSources.Any(o => o == dataSourceName)) + return false; + _dataSources.Add(dataSourceName); + return true; + } + + public override Func GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator) + { + + var t = ShardingKeyToDataSourceName(shardingKey); + switch (shardingOperator) + { + case ShardingOperatorEnum.Equal: return tail => tail == t; + default: + { + return tail => true; + } + } + } + + public override void Configure(EntityMetadataDataSourceBuilder builder) + { + builder.ShardingProperty(o => o.Area); + } +} \ No newline at end of file diff --git a/samples/Sample.MySQLDataSourceOnly/Program.cs b/samples/Sample.MySQLDataSourceOnly/Program.cs new file mode 100644 index 00000000..31b4d2c6 --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/Program.cs @@ -0,0 +1,77 @@ +using Microsoft.EntityFrameworkCore; +using Sample.MySQLDataSourceOnly.Domain; +using ShardingCore; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + + + +builder.Services.AddShardingDbContext() + .UseRouteConfig(o => + { + //o.CreateShardingTableOnStart = true; + //o.EnsureCreatedWithOutShardingTable = true; + o.AddShardingDataSourceRoute(); + }) + .UseConfig((sp,op) => + { + var loggerFactory = sp.ApplicationServiceProvider.GetService(); + //op.ConfigId = "c1"; + op.UseShardingQuery((conStr, builder) => + { + builder.UseMySql(conStr,new MySqlServerVersion(new Version())) + .UseLoggerFactory(loggerFactory).EnableSensitiveDataLogging(); + }); + op.UseShardingTransaction((connection, builder) => + { + builder.UseMySql(connection,new MySqlServerVersion(new Version())) + .UseLoggerFactory(loggerFactory).EnableSensitiveDataLogging();; + }); + //op.ReplaceTableEnsureManager(sp => new SqlServerTableEnsureManager()); + op.AddDefaultDataSource("A", @"server=127.0.0.1;port=3306;database=onlyds1;userid=root;password=root;"); + op.AddExtraDataSource(sp => + { + return new Dictionary() + { + { + "B", + @"server=127.0.0.1;port=3306;database=onlyds2;userid=root;password=root;" + }, + { + "C", + @"server=127.0.0.1;port=3306;database=onlyds3;userid=root;password=root;" + }, + }; + }); + }).AddShardingCore(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); +app.Services.UseAutoTryCompensateTable(); +// using (var serviceScope = app.Services.CreateScope()) +// { +// var myDbContext = serviceScope.ServiceProvider.GetService(); +// myDbContext.Database.EnsureCreated(); +// myDbContext.Add(new SysUser() { Id = "1", Area = "A", Name = "name" }); +// myDbContext.SaveChanges(); +// } +app.Run(); \ No newline at end of file diff --git a/samples/Sample.MySQLDataSourceOnly/Properties/launchSettings.json b/samples/Sample.MySQLDataSourceOnly/Properties/launchSettings.json new file mode 100644 index 00000000..f64f7f73 --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:35669", + "sslPort": 44323 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5029", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7187;http://localhost:5029", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/samples/Sample.MySQLDataSourceOnly/Sample.MySQLDataSourceOnly.csproj b/samples/Sample.MySQLDataSourceOnly/Sample.MySQLDataSourceOnly.csproj new file mode 100644 index 00000000..149adba2 --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/Sample.MySQLDataSourceOnly.csproj @@ -0,0 +1,19 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + + diff --git a/samples/Sample.MySQLDataSourceOnly/WeatherForecast.cs b/samples/Sample.MySQLDataSourceOnly/WeatherForecast.cs new file mode 100644 index 00000000..074dc624 --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/WeatherForecast.cs @@ -0,0 +1,12 @@ +namespace Sample.MySQLDataSourceOnly; + +public class WeatherForecast +{ + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } +} \ No newline at end of file diff --git a/samples/Sample.MySQLDataSourceOnly/appsettings.Development.json b/samples/Sample.MySQLDataSourceOnly/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/samples/Sample.MySQLDataSourceOnly/appsettings.json b/samples/Sample.MySQLDataSourceOnly/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/samples/Sample.MySQLDataSourceOnly/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/samples/Sample.MySql/Controllers/WeatherForecastController.cs b/samples/Sample.MySql/Controllers/WeatherForecastController.cs index 91f60b64..84e9b7f4 100644 --- a/samples/Sample.MySql/Controllers/WeatherForecastController.cs +++ b/samples/Sample.MySql/Controllers/WeatherForecastController.cs @@ -420,5 +420,18 @@ public async Task Get15() await _unShardingDbContext.SaveChangesAsync(); return Ok(); } + + + + [HttpGet] + public async Task Get16() + { + var sysUserMod = await _defaultTableDbContext.Set().FirstOrDefaultAsync(); + sysUserMod.Age = new Random().Next(1,999); + await _defaultTableDbContext.SaveChangesAsync(); + // var sysUserMods1 = await _defaultTableDbContext.Set().FromSqlRaw("select * from SysUserMod where id='2'").ToListAsync(); + // var sysUserMods2 = await _defaultTableDbContext.Set().FromSqlRaw("select * from SysTest where id='2'").ToListAsync(); + return Ok(); + } } } diff --git a/samples/Sample.MySql/Startup.cs b/samples/Sample.MySql/Startup.cs index baa005d5..ba21cd3f 100644 --- a/samples/Sample.MySql/Startup.cs +++ b/samples/Sample.MySql/Startup.cs @@ -116,6 +116,7 @@ public void ConfigureServices(IServiceCollection services) var logger = sp.ApplicationServiceProvider.GetService>(); logger.LogInformation(conStr); builder.UseMySql(conStr, new MySqlServerVersion(new Version())) + // .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) .UseLoggerFactory(loggerFactory1) .EnableSensitiveDataLogging(); //.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); @@ -124,6 +125,7 @@ public void ConfigureServices(IServiceCollection services) { builder .UseMySql(connection, new MySqlServerVersion(new Version())) + // .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) .UseLoggerFactory(loggerFactory1) .EnableSensitiveDataLogging(); //.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); @@ -247,6 +249,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // DynamicShardingHelper.DynamicAppendDataSource($"c0",$"ds{i}",$"server=127.0.0.1;port=3306;database=dbdbd{i};userid=root;password=root;"); // // } + // using (var scope = app.ApplicationServices.CreateScope()) + // { + // var defaultShardingDbContext = scope.ServiceProvider.GetRequiredService(); + // var addMonths = DateTime.Now.AddMonths(-5); + // defaultShardingDbContext.Set().Where(o => o.Time >= addMonths).Any(); + // } app.DbSeed(); } } diff --git a/src/ShardingCore/Core/VirtualRoutes/TableRoutes/RoutingRuleEngine/TableRouteRuleEngine.cs b/src/ShardingCore/Core/VirtualRoutes/TableRoutes/RoutingRuleEngine/TableRouteRuleEngine.cs index 52902ef5..f42b104e 100644 --- a/src/ShardingCore/Core/VirtualRoutes/TableRoutes/RoutingRuleEngine/TableRouteRuleEngine.cs +++ b/src/ShardingCore/Core/VirtualRoutes/TableRoutes/RoutingRuleEngine/TableRouteRuleEngine.cs @@ -103,9 +103,9 @@ public ShardingRouteResult Route(TableRouteRuleContext tableRouteRuleContext) //如果笛卡尔积 var sqlRouteUnits = new List(31); - int dataSourceCount = 0; bool isCrossTable = false; bool existCrossTableTails = false; + var dataSourceSet = new HashSet(); foreach (var dataSourceName in tableRouteRuleContext.DataSourceRouteResult.IntersectDataSources) { if (routeMaps.ContainsKey(dataSourceName)) @@ -118,7 +118,7 @@ public ShardingRouteResult Route(TableRouteRuleContext tableRouteRuleContext) var tableRouteResults = GetTableRouteResults(tableRouteRuleContext, routeResults); if (tableRouteResults.IsNotEmpty()) { - dataSourceCount++; + dataSourceSet.Add(dataSourceName); if (tableRouteResults.Length > 1) { isCrossTable = true; @@ -140,12 +140,13 @@ public ShardingRouteResult Route(TableRouteRuleContext tableRouteRuleContext) } }else if (onlyShardingDataSource) { + dataSourceSet.Add(dataSourceName); var tableRouteResult = new TableRouteResult(queryEntities.Keys.Select(o=>new TableRouteUnit(dataSourceName,String.Empty,o )).ToList()); sqlRouteUnits.Add(new SqlRouteUnit(dataSourceName, tableRouteResult)); } } - return new ShardingRouteResult(sqlRouteUnits, sqlRouteUnits.Count == 0, dataSourceCount > 1, isCrossTable, + return new ShardingRouteResult(sqlRouteUnits, sqlRouteUnits.Count == 0, dataSourceSet.Count > 1, isCrossTable, existCrossTableTails); // // var sqlRouteUnits = tableRouteRuleContext.DataSourceRouteResult.IntersectDataSources.SelectMany( diff --git a/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs b/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs index 713a4384..cebfcb44 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs @@ -246,7 +246,7 @@ public string GetQueryMethodName() /// public bool IsParallelQuery() { - return _isCrossTable || _existCrossTableTails || _queryCompilerContext.IsParallelQuery(); + return _isCrossTable || _existCrossTableTails || _isCrossDataSource || _queryCompilerContext.IsParallelQuery(); } public int? GetFixedTake() diff --git a/src/ShardingCore/Sharding/StreamMergeContext.cs b/src/ShardingCore/Sharding/StreamMergeContext.cs index 59665169..bee66b1e 100644 --- a/src/ShardingCore/Sharding/StreamMergeContext.cs +++ b/src/ShardingCore/Sharding/StreamMergeContext.cs @@ -134,23 +134,23 @@ public DbContext CreateDbContext(ISqlRouteUnit sqlRouteUnit) return dbContext; } - /// - /// 因为并发查询情况下那么你是内存就是内存你是流式就是流式 - /// 如果不是并发查询的情况下系统会将当前dbcontext进行利用起来所以只能是流式 - /// - /// - /// - public ConnectionModeEnum RealConnectionMode(ConnectionModeEnum connectionMode) - { - if (IsParallelQuery()) - { - return connectionMode; - } - else - { - return ConnectionModeEnum.MEMORY_STRICTLY; - } - } + // /// + // /// 因为并发查询情况下那么你是内存就是内存你是流式就是流式 + // /// 如果不是并发查询的情况下系统会将当前dbcontext进行利用起来所以只能是流式 + // /// + // /// + // /// + // public ConnectionModeEnum RealConnectionMode(ConnectionModeEnum connectionMode) + // { + // if (IsParallelQuery()) + // { + // return connectionMode; + // } + // else + // { + // return ConnectionModeEnum.MEMORY_STRICTLY; + // } + // } //public IRouteTail Create(TableRouteResult tableRouteResult) //{ @@ -279,10 +279,6 @@ public bool IsUseShardingTrack(Type entityType) { if (!IsParallelQuery()) { - if (IsCrossDataSource) - { - return true; - } return false; } return QueryTrack() && _trackerManager.EntityUseTrack(entityType);