添加mysql的支持

This commit is contained in:
xuejmnet 2021-01-26 14:39:56 +08:00
parent b8e97a1cd3
commit b0ab0815e2
31 changed files with 880 additions and 12 deletions

View File

@ -22,6 +22,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CC2C88C0-6
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.Test50", "test\ShardingCore.Test50\ShardingCore.Test50.csproj", "{7EE133B6-5A02-41B7-9D89-41D9EA14184E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.SqlServer", "samples\Sample.SqlServer\Sample.SqlServer.csproj", "{D48E5EC2-CF83-4B17-8BBA-BDE52ADFAB1F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.MySql", "src\ShardingCore.MySql\ShardingCore.MySql.csproj", "{10308339-FF5C-43AB-9208-627B6E2FBBDB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.MySql.3x", "src3x\ShardingCore.MySql.3x\ShardingCore.MySql.3x.csproj", "{954C4CA2-9CF4-4C2C-8DE6-180DD8202E38}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.MySql.2x", "src2x\ShardingCore.MySql.2x\ShardingCore.MySql.2x.csproj", "{0CF88F0B-6CCB-49B5-B41D-CDC193B51581}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -35,6 +45,10 @@ Global
{FB92A4BE-A43E-4755-8132-EC38E9650B80} = {679E6084-0C45-4807-BFEE-D2FDA44B2188}
{73B802A7-3DDE-4B02-9E3D-D6B9EE42DE5D} = {679E6084-0C45-4807-BFEE-D2FDA44B2188}
{7EE133B6-5A02-41B7-9D89-41D9EA14184E} = {CC2C88C0-65F2-445D-BE78-973B840FE281}
{D48E5EC2-CF83-4B17-8BBA-BDE52ADFAB1F} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73}
{10308339-FF5C-43AB-9208-627B6E2FBBDB} = {490FAE47-4476-4508-B216-505FC850447F}
{954C4CA2-9CF4-4C2C-8DE6-180DD8202E38} = {62AAE0FE-4099-4A48-AA3C-F76F14C62655}
{0CF88F0B-6CCB-49B5-B41D-CDC193B51581} = {679E6084-0C45-4807-BFEE-D2FDA44B2188}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3CAF09A6-6ABD-41D9-BA57-9A822B8095F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -65,5 +79,21 @@ Global
{7EE133B6-5A02-41B7-9D89-41D9EA14184E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7EE133B6-5A02-41B7-9D89-41D9EA14184E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7EE133B6-5A02-41B7-9D89-41D9EA14184E}.Release|Any CPU.Build.0 = Release|Any CPU
{D48E5EC2-CF83-4B17-8BBA-BDE52ADFAB1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D48E5EC2-CF83-4B17-8BBA-BDE52ADFAB1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D48E5EC2-CF83-4B17-8BBA-BDE52ADFAB1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D48E5EC2-CF83-4B17-8BBA-BDE52ADFAB1F}.Release|Any CPU.Build.0 = Release|Any CPU
{10308339-FF5C-43AB-9208-627B6E2FBBDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{10308339-FF5C-43AB-9208-627B6E2FBBDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{10308339-FF5C-43AB-9208-627B6E2FBBDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{10308339-FF5C-43AB-9208-627B6E2FBBDB}.Release|Any CPU.Build.0 = Release|Any CPU
{954C4CA2-9CF4-4C2C-8DE6-180DD8202E38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{954C4CA2-9CF4-4C2C-8DE6-180DD8202E38}.Debug|Any CPU.Build.0 = Debug|Any CPU
{954C4CA2-9CF4-4C2C-8DE6-180DD8202E38}.Release|Any CPU.ActiveCfg = Release|Any CPU
{954C4CA2-9CF4-4C2C-8DE6-180DD8202E38}.Release|Any CPU.Build.0 = Release|Any CPU
{0CF88F0B-6CCB-49B5-B41D-CDC193B51581}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0CF88F0B-6CCB-49B5-B41D-CDC193B51581}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0CF88F0B-6CCB-49B5-B41D-CDC193B51581}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0CF88F0B-6CCB-49B5-B41D-CDC193B51581}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,30 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sample.SqlServer.Domain.Entities;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
namespace Sample.SqlServer.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class ValuesController : ControllerBase
{
private readonly IVirtualDbContext _virtualDbContext;
public ValuesController(IVirtualDbContext virtualDbContext)
{
_virtualDbContext = virtualDbContext;
}
[HttpGet]
public async Task<IActionResult> Get()
{
return Ok(await _virtualDbContext.Set<SysUserMod>().ToShardingListAsync());
}
}
}

View File

@ -0,0 +1,23 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore;
namespace Sample.SqlServer
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 26 January 2021 12:29:04
* @Email: 326308290@qq.com
*/
public static class DIExtension
{
public static IApplicationBuilder UseShardingCore(this IApplicationBuilder app)
{
var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();
shardingBootstrapper.Start();
return app;
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using ShardingCore.Core;
namespace Sample.SqlServer.Domain.Entities
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 26 January 2021 12:25:39
* @Email: 326308290@qq.com
*/
public class SysUserMod:IShardingEntity
{
/// <summary>
/// 用户Id用于分表
/// </summary>
[ShardingKey(TailPrefix = "_",AutoCreateTableOnStart = true)]
public string Id { get; set; }
/// <summary>
/// 用户名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 用户姓名
/// </summary>
public int Age { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Sample.SqlServer.Domain.Entities;
namespace Sample.SqlServer.Domain.Maps
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 14 January 2021 15:37:33
* @Email: 326308290@qq.com
*/
public class SysUserModMap:IEntityTypeConfiguration<SysUserMod>
{
public void Configure(EntityTypeBuilder<SysUserMod> builder)
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Id).IsRequired().HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128);
builder.ToTable(nameof(SysUserMod));
}
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Sample.SqlServer
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}
}

View File

@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:8784",
"sslPort": 44352
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Sample.SqlServer": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ShardingCore.SqlServer\ShardingCore.SqlServer.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Sample.SqlServer.Domain.Entities;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.VirtualRoutes;
namespace Sample.SqlServer.Shardings
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 14 January 2021 15:39:27
* @Email: 326308290@qq.com
*/
public class SysUserModVirtualRoute : AbstractSimpleShardingModVirtualRoute<SysUserMod, string>
{
public SysUserModVirtualRoute() : base(3)
{
}
protected override string ConvertToShardingKey(object shardingKey)
{
return shardingKey.ToString();
}
public override List<string> GetAllTails()
{
return new() { "0","1","2"};
}
protected override Expression<Func<string, bool>> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
{
var t = ShardingKeyToTail(shardingKey);
switch (shardingOperator)
{
case ShardingOperatorEnum.Equal: return tail => tail == t;
default:
{
Console.WriteLine($"shardingOperator is not equal scan all table tail");
return tail => true;
}
}
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Sample.SqlServer.Shardings;
using ShardingCore.SqlServer;
namespace Sample.SqlServer
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddShardingSqlServer(o =>
{
o.ConnectionString = "";
o.AddSharding<SysUserModVirtualRoute>();
o.CreateIfNotExists((provider, config) =>
{
//如果是development就判断并且新建数据库如果不存在的话
config.EnsureCreated = provider.GetService<IHostEnvironment>().IsDevelopment();
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseShardingCore();
app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); });
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,81 @@
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
using ShardingCore.MySql.EFCores;
using ShardingCore.TableCreator;
#if EFCORE2
using Microsoft.EntityFrameworkCore.Query.Sql;
#endif
#if !EFCORE2
using Microsoft.EntityFrameworkCore.Query;
#endif
namespace ShardingCore.MySql
{
/*
* @Author: xjm
* @Description:
* @Date: 202047 9:30:18
* @Email: 326308290@qq.com
*/
public static class DIExtension
{
public static IServiceCollection AddShardingSqlServer(this IServiceCollection services, Action<MySqlOptions> configure)
{
if (configure == null)
throw new ArgumentNullException($"AddScfSqlServerProvider :{nameof(configure)}");
var options = new MySqlOptions();
configure(options);
services.AddSingleton(options);
services.AddScoped<IVirtualDbContext, VirtualDbContext>();
services.AddScoped<IDbContextOptionsProvider, SqlServerDbContextOptionsProvider>();
services.AddSingleton<IShardingDbContextFactory, ShardingDbContextFactory>();
services.AddSingleton<IShardingTableCreator, ShardingTableCreator>();
services.AddSingleton<IVirtualTableManager, OneDbVirtualTableManager>();
services.AddSingleton(typeof(IVirtualTable<>), typeof(OneDbVirtualTable<>));
services.AddSingleton<IShardingAccessor, ShardingAccessor>();
services.AddSingleton<IShardingScopeFactory, ShardingScopeFactory>();
services.AddSingleton<IShardingParallelDbContextFactory, ShardingMySqlParallelDbContextFactory>();
if (options.HasSharding)
{
foreach (var shardingRoute in options.ShardingRoutes)
{
var genericVirtualRoute = shardingRoute.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IVirtualRoute<>)
&& it.GetGenericArguments().Any());
if (genericVirtualRoute == null)
throw new ArgumentException("add sharding route type error not assignable from IVirtualRoute<>.");
var shardingEntity=genericVirtualRoute.GetGenericArguments()[0];
if(!shardingEntity.IsShardingEntity())
throw new ArgumentException("add sharding route type error generic arguments first not assignable from IShardingEntity.");
Type genericType = typeof(IVirtualRoute<>);
Type interfaceType = genericType.MakeGenericType(shardingEntity);
services.AddSingleton(interfaceType, shardingRoute);
}
}
services.AddSingleton(sp =>
{
var shardingCoreConfig = new ShardingCoreConfig();
options.ShardingCoreConfigConfigure?.Invoke(sp,shardingCoreConfig);
return shardingCoreConfig;
});
services.AddSingleton<IShardingBootstrapper,ShardingBootstrapper>();
return services;
}
public static DbContextOptionsBuilder UseShardingSqlServerQuerySqlGenerator(this DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ReplaceService<IQuerySqlGeneratorFactory, ShardingMySqlQuerySqlGeneratorFactory>();
return optionsBuilder;
}
}
}

View File

@ -0,0 +1,213 @@
#if !EFCORE2
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal;
using Pomelo.EntityFrameworkCore.MySql.Query.ExpressionVisitors.Internal;
using Pomelo.EntityFrameworkCore.MySql.Query.Internal;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Extensions;
namespace ShardingCore.MySql.EFCores
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 22 December 2020 09:47:59
* @Email: 326308290@qq.com
*/
public class ShardingMySqlQuerySqlGeneratorFactory : IQuerySqlGeneratorFactory
{
private readonly QuerySqlGeneratorDependencies _dependencies;
private readonly MySqlSqlExpressionFactory _sqlExpressionFactory;
private readonly IMySqlOptions _options;
public ShardingMySqlQuerySqlGeneratorFactory(
QuerySqlGeneratorDependencies dependencies,
ISqlExpressionFactory sqlExpressionFactory,
IMySqlOptions options)
{
this._dependencies = dependencies;
this._sqlExpressionFactory = (MySqlSqlExpressionFactory) sqlExpressionFactory;
this._options = options;
}
public virtual QuerySqlGenerator Create() => (QuerySqlGenerator) new ShardingMySqlQuerySqlGenerator(this._dependencies, this._sqlExpressionFactory, this._options);
}
public class ShardingMySqlQuerySqlGenerator :MySqlQuerySqlGenerator
{
public ShardingMySqlQuerySqlGenerator(QuerySqlGeneratorDependencies dependencies, MySqlSqlExpressionFactory sqlExpressionFactory, IMySqlOptions options) : base(dependencies, sqlExpressionFactory, options)
{
}
protected override Expression VisitTable(TableExpression tableExpression)
{
return OverrideVisitTable(tableExpression);
// this._relationalCommandBuilder.Append((object) this._sqlGenerationHelper.DelimitIdentifier(tableExpression.Name, tableExpression.Schema)).Append((object) this.AliasSeparator).Append((object) this._sqlGenerationHelper.DelimitIdentifier(tableExpression.Alias));
// return (Expression) tableExpression;
// typeof(TableExpression)
// .GetFields( BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(o=>o.Name.Contains(nameof(tableExpression.Name)))
// .SetValue(tableExpression,"(select * from Log_1Message union all select * from Log_1Message)");
// base will append schema, table and alias
}
private Expression OverrideVisitTable(TableExpression tableExpression)
{
var shardingAccessor = ShardingContainer.Services.GetService<IShardingAccessor>();
if (shardingAccessor?.ShardingContext != null)
{
var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>();
var virtualTable = virtualTableManager.GetAllVirtualTables().FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Name);
if(virtualTable!=null)
{
var tails = shardingAccessor.ShardingContext.GetContextQueryTails(virtualTable);
var tailPrefix = virtualTable.ShardingConfig.TailPrefix;
string newTableName = null;
var sqlGenerationHelper = typeof(QuerySqlGenerator).GetTypeFieldValue(this, "_sqlGenerationHelper") as ISqlGenerationHelper;
if (tails.IsEmpty())
{
var firstTail = virtualTableManager.GetVirtualTable(tableExpression.Name).GetAllPhysicTables()[0].Tail;
newTableName = $"( select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Name}{tailPrefix}{firstTail}", tableExpression.Schema)} where 1=2 )";
}
else if (tails.Count == 1)
{
//对tableExpresion进行重写
//typeof(TableExpression)
// .GetFields( BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(o=>o.Name==$"<{nameof(tableExpression.Name)}>k__BackingField")
// .SetValue(tableExpression,$"{tableExpression.Name}{tailPrefix}{entry.Tails[0]}");
newTableName = sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Name}{tailPrefix}{tails[0]}", tableExpression.Schema);
}
else
{
newTableName = "(" + string.Join(" union all ", tails.Select(tail => $"select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Name}{tailPrefix}{tail}", tableExpression.Schema)}")) + ")";
}
var relationalCommandBuilder = typeof(QuerySqlGenerator).GetTypeFieldValue(this, "_relationalCommandBuilder") as IRelationalCommandBuilder;
relationalCommandBuilder.Append(newTableName).Append(this.AliasSeparator).Append(sqlGenerationHelper.DelimitIdentifier(tableExpression.Alias));
return tableExpression;
}
}
var result = base.VisitTable(tableExpression);
return result;
}
}
}
#endif
#if EFCORE2
using System.Linq;
using System.Linq.Expressions;
using ShardingCore;
using ShardingCore.Extensions;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.VirtualTables;
using Microsoft.EntityFrameworkCore.Query.Expressions;
using Microsoft.EntityFrameworkCore.Query.Sql;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal;
using Pomelo.EntityFrameworkCore.MySql.Query.Sql.Internal;
namespace ShardingCore.MySql.EFCores
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 22 December 2020 09:47:59
* @Email: 326308290@qq.com
*/
public class ShardingMySqlQuerySqlGeneratorFactory :QuerySqlGeneratorFactoryBase
{
private readonly IMySqlOptions _options;
public ShardingMySqlQuerySqlGeneratorFactory(QuerySqlGeneratorDependencies dependencies, IMySqlOptions options)
: base(dependencies)
{
_options = options;
}
public override IQuerySqlGenerator CreateDefault(SelectExpression selectExpression)
=> new ShardingMySqlQuerySqlGenerator(
Dependencies,
selectExpression, _options);
}
public class ShardingMySqlQuerySqlGenerator : MySqlQuerySqlGenerator
{
public ShardingMySqlQuerySqlGenerator(QuerySqlGeneratorDependencies dependencies, SelectExpression selectExpression, IMySqlOptions options) : base(dependencies, selectExpression, options)
{
}
public override Expression VisitTable(TableExpression tableExpression)
{
return OverrideVisitTable(tableExpression);
}
// protected override Expression VisitTable(TableExpression tableExpression)
// {
// return OverrideVisitTable(tableExpression);
// // this._relationalCommandBuilder.Append((object) this._sqlGenerationHelper.DelimitIdentifier(tableExpression.Name, tableExpression.Schema)).Append((object) this.AliasSeparator).Append((object) this._sqlGenerationHelper.DelimitIdentifier(tableExpression.Alias));
// // return (Expression) tableExpression;
//
// // typeof(TableExpression)
// // .GetFields( BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(o=>o.Name.Contains(nameof(tableExpression.Name)))
// // .SetValue(tableExpression,"(select * from Log_1Message union all select * from Log_1Message)");
//
// // base will append schema, table and alias
// }
private Expression OverrideVisitTable(TableExpression tableExpression)
{
var shardingAccessor = ShardingContainer.Services.GetService<IShardingAccessor>();
if (shardingAccessor?.ShardingContext != null)
{
var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>();
var virtualTable = virtualTableManager.GetAllVirtualTables().FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Table);
if(virtualTable!=null)
{
var tails = shardingAccessor.ShardingContext.GetContextQueryTails(virtualTable);
var tailPrefix = virtualTable.ShardingConfig.TailPrefix;
string newTableName = null;
var sqlGenerationHelper = typeof(DefaultQuerySqlGenerator).GetTypeFieldValue(this, "_sqlGenerationHelper") as ISqlGenerationHelper;
if (tails.IsEmpty())
{
var firstTail = virtualTableManager.GetVirtualTable(tableExpression.Table).GetAllPhysicTables()[0].Tail;
newTableName = $"( select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Table}{tailPrefix}{firstTail}", tableExpression.Schema)} where 1=2 )";
}
else if (tails.Count == 1)
{
//对tableExpresion进行重写
//typeof(TableExpression)
// .GetFields( BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(o=>o.Name==$"<{nameof(tableExpression.Name)}>k__BackingField")
// .SetValue(tableExpression,$"{tableExpression.Name}{tailPrefix}{entry.Tails[0]}");
newTableName = sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Table}{tailPrefix}{tails[0]}", tableExpression.Schema);
}
else
{
newTableName = "(" + string.Join(" union all ", tails.Select(tail => $"select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Table}{tailPrefix}{tail}", tableExpression.Schema)}")) + ")";
}
var relationalCommandBuilder = typeof(DefaultQuerySqlGenerator).GetTypeFieldValue(this, "_relationalCommandBuilder") as IRelationalCommandBuilder;
relationalCommandBuilder.Append(newTableName).Append(this.AliasSeparator).Append(sqlGenerationHelper.DelimitIdentifier(tableExpression.Alias));
return tableExpression;
}
}
var result = base.VisitTable(tableExpression);
return result;
}
}
}
#endif

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
namespace ShardingCore.MySql
{
/*
* @Author: xjm
* @Description:
* @Date: 202047 8:34:04
* @Email: 326308290@qq.com
*/
public class MySqlOptions
{
public LinkedList<Type> ShardingRoutes=new LinkedList<Type>();
public string ConnectionString { get; set; }
#if EFCORE5
public MySqlServerVersion ServerVersion { get; set; }
#endif
public Action<MySqlDbContextOptionsBuilder> MySqlOptionsAction { get; set; }
public void AddSharding<TRoute>()where TRoute:IVirtualRoute
{
ShardingRoutes.AddLast(typeof(TRoute));
}
public bool HasSharding => ShardingRoutes.IsNotEmpty();
public Action<IServiceProvider, ShardingCoreConfig> ShardingCoreConfigConfigure { get; private set; }
public void SetMySqlOptions(Action<MySqlDbContextOptionsBuilder> action)
{
MySqlOptionsAction = action;
}
public void CreateIfNotExists(Action<IServiceProvider, ShardingCoreConfig> action)
{
ShardingCoreConfigConfigure = action;
}
}
}

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Version>$(EFCORE5)</Version>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<DefineConstants>TRACE;DEBUG;EFCORE5;</DefineConstants>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.MySql.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.0-alpha.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ShardingCore\ShardingCore.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,53 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query.Internal;
using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.EFCores;
using ShardingCore.Extensions;
namespace ShardingCore.MySql
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 29 December 2020 15:22:50
* @Email: 326308290@qq.com
*/
public class ShardingMySqlParallelDbContextFactory : IShardingParallelDbContextFactory
{
private readonly IVirtualTableManager _virtualTableManager;
private readonly MySqlOptions _mySqlOptions;
public ShardingMySqlParallelDbContextFactory(IVirtualTableManager virtualTableManager, MySqlOptions mySqlOptions)
{
_virtualTableManager = virtualTableManager;
_mySqlOptions = mySqlOptions;
}
public ShardingDbContext Create(string tail)
{
var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables().GetVirtualTableDbContextConfigs();
var shardingDbContextOptions = new ShardingDbContextOptions(CreateOptions(), tail, virtualTableConfigs);
return new ShardingDbContext(shardingDbContextOptions);
}
private DbContextOptions CreateOptions()
{
return new DbContextOptionsBuilder()
#if EFCORE5
.UseMySql(_mySqlOptions.ConnectionString,_mySqlOptions.ServerVersion,_mySqlOptions.MySqlOptionsAction)
#endif
#if !EFCORE5
.UseMySql(_mySqlOptions.ConnectionString,_mySqlOptions.MySqlOptionsAction)
#endif
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
.UseShardingSqlServerQuerySqlGenerator()
.Options;
}
}
}

View File

@ -0,0 +1,55 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.Extensions.Logging;
#if !EFCORE5
using MySql.Data.MySqlClient;
#endif
#if EFCORE5
using MySqlConnector;
#endif
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.EFCores;
namespace ShardingCore.MySql
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 24 December 2020 10:33:51
* @Email: 326308290@qq.com
*/
public class SqlServerDbContextOptionsProvider:IDbContextOptionsProvider
{
private DbContextOptions _dbContextOptions;
private MySqlConnection _connection;
public SqlServerDbContextOptionsProvider(MySqlOptions mySqlOptions,ILoggerFactory loggerFactory)
{
_connection=new MySqlConnection(mySqlOptions.ConnectionString);
_dbContextOptions = new DbContextOptionsBuilder()
#if EFCORE5
.UseMySql(_connection,mySqlOptions.ServerVersion,mySqlOptions.MySqlOptionsAction)
#endif
#if !EFCORE5
.UseMySql(_connection,mySqlOptions.MySqlOptionsAction)
#endif
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.UseLoggerFactory(loggerFactory)
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
.UseShardingSqlServerQuerySqlGenerator()
.Options;
}
public DbContextOptions GetDbContextOptions()
{
return _dbContextOptions;
}
public void Dispose()
{
_connection?.Dispose();
}
}
}

View File

@ -60,10 +60,13 @@ namespace ShardingCore.SqlServer
services.AddSingleton(interfaceType, shardingRoute);
}
}
var shardingCoreConfig = new ShardingCoreConfig();
shardingCoreConfig.EnsureCreated = options.EnsureCreated;
services.AddSingleton(sp => shardingCoreConfig);
services.AddSingleton<ShardingBootstrapper>();
services.AddSingleton(sp =>
{
var shardingCoreConfig = new ShardingCoreConfig();
options.ShardingCoreConfigConfigure?.Invoke(sp,shardingCoreConfig);
return shardingCoreConfig;
});
services.AddSingleton<IShardingBootstrapper,ShardingBootstrapper>();
return services;
}

View File

@ -10,6 +10,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.SqlServer.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>

View File

@ -22,9 +22,10 @@ namespace ShardingCore.SqlServer
}
public bool HasSharding => ShardingRoutes.IsNotEmpty();
/// <summary>
/// 创建表如果数据库不存在的话创建的表是非sharding表
/// </summary>
public bool EnsureCreated { get; set; }
public Action<IServiceProvider, ShardingCoreConfig> ShardingCoreConfigConfigure { get; private set; }
public void CreateIfNotExists(Action<IServiceProvider, ShardingCoreConfig> function)
{
ShardingCoreConfigConfigure = function;
}
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 26 January 2021 12:15:27
* @Email: 326308290@qq.com
*/
public interface IShardingBootstrapper
{
void Start();
}
}

View File

@ -19,7 +19,7 @@ namespace ShardingCore
* @Date: Monday, 21 December 2020 09:10:07
* @Email: 326308290@qq.com
*/
public class ShardingBootstrapper
public class ShardingBootstrapper:IShardingBootstrapper
{
private readonly IServiceProvider _serviceProvider;
private readonly IVirtualTableManager _virtualTableManager;
@ -63,7 +63,7 @@ namespace ShardingCore
}
}
public void EnsureCreated()
private void EnsureCreated()
{
if (_shardingCoreConfig.EnsureCreated)
{

View File

@ -10,6 +10,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>

View File

@ -11,6 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.2x.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>

View File

@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>$(EFCORE2)</Version>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<DefineConstants>TRACE;DEBUG;EFCORE2;</DefineConstants>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.MySql.2x.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\src\ShardingCore.MySql\**\*.cs" />
<Compile Remove="..\..\src\ShardingCore.MySql\obj\**" />
<Compile Remove="..\..\src\ShardingCore.MySql\bin\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.6" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ShardingCore.2x\ShardingCore.2x.csproj" />
</ItemGroup>
</Project>

View File

@ -11,6 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.SqlServer.2x.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>

View File

@ -11,6 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.3x.xml</DocumentationFile>
</PropertyGroup>

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>$(EFCORE3)</Version>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<DefineConstants>TRACE;DEBUG;EFCORE3;</DefineConstants>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.MySql.3x.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\src\ShardingCore.MySql\**\*.cs" />
<Compile Remove="..\..\src\ShardingCore.MySql\obj\**" />
<Compile Remove="..\..\src\ShardingCore.MySql\bin\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.2.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ShardingCore.3x\ShardingCore.3x.csproj" />
</ItemGroup>
</Project>

View File

@ -11,6 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\Release\ShardingCore.SqlServer.3x.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>

View File

@ -42,14 +42,17 @@ namespace ShardingCore.Test50
o.ConnectionString = hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"];
o.AddSharding<SysUserModVirtualRoute>();
o.AddSharding<SysUserRangeVirtualRoute>();
o.EnsureCreated = true;
o.CreateIfNotExists((provider, config) =>
{
config.EnsureCreated = true;
});
});
}
// 可以添加要用到的方法参数,会自动从注册的服务中获取服务实例,类似于 asp.net core 里 Configure 方法
public void Configure(IServiceProvider serviceProvider)
{
var shardingBootstrapper = serviceProvider.GetService<ShardingBootstrapper>();
var shardingBootstrapper = serviceProvider.GetService<IShardingBootstrapper>();
shardingBootstrapper.Start();
// 有一些测试数据要初始化可以放在这里
InitData(serviceProvider).GetAwaiter().GetResult();