第一个测试版本

This commit is contained in:
xuejiaming 2021-08-20 13:50:49 +08:00
parent 070a952bfd
commit 4accc08567
56 changed files with 841 additions and 1076 deletions

View File

@ -2,7 +2,7 @@
::定义版本 ::定义版本
set EFCORE2=2.1.0.21 set EFCORE2=2.1.0.21
set EFCORE3=3.1.0.21 set EFCORE3=3.1.0.21
set EFCORE5=5.1.0.21 set EFCORE5=5.2.0.02
::删除所有bin与obj下的文件 ::删除所有bin与obj下的文件
@echo off @echo off

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
@ -6,17 +5,15 @@ using Microsoft.Extensions.DependencyInjection;
using Sample.SqlServer.DbContexts; using Sample.SqlServer.DbContexts;
using Sample.SqlServer.Domain.Entities; using Sample.SqlServer.Domain.Entities;
using ShardingCore; using ShardingCore;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
namespace Sample.SqlServer namespace Sample.SqlServer
{ {
/* /*
* @Author: xjm * @Author: xjm
* @Description: * @Description:
* @Date: Tuesday, 26 January 2021 12:29:04 * @Date: Tuesday, 26 January 2021 12:29:04
* @Email: 326308290@qq.com * @Email: 326308290@qq.com
*/ */
public static class DIExtension public static class DIExtension
{ {
public static IApplicationBuilder UseShardingCore(this IApplicationBuilder app) public static IApplicationBuilder UseShardingCore(this IApplicationBuilder app)
@ -30,24 +27,24 @@ namespace Sample.SqlServer
{ {
using (var scope=app.ApplicationServices.CreateScope()) using (var scope=app.ApplicationServices.CreateScope())
{ {
var virtualDbContext =scope.ServiceProvider.GetService<DefaultTableDbContext>(); var virtualDbContext =scope.ServiceProvider.GetService<DefaultShardingDbContext>();
//if (!virtualDbContext.Set<SysUserMod>().ShardingAny()) if (!virtualDbContext.Set<SysUserMod>().Any())
//{ {
// var ids = Enumerable.Range(1, 1000); var ids = Enumerable.Range(1, 1000);
// var userMods = new List<SysUserMod>(); var userMods = new List<SysUserMod>();
// foreach (var id in ids) foreach (var id in ids)
// { {
// userMods.Add(new SysUserMod() userMods.Add(new SysUserMod()
// { {
// Id = id.ToString(), Id = id.ToString(),
// Age = id, Age = id,
// Name = $"name_{id}", Name = $"name_{id}",
// }); });
// } }
// virtualDbContext.AddRange(userMods); virtualDbContext.AddRange(userMods);
// virtualDbContext.SaveChanges(); virtualDbContext.SaveChanges();
//} }
} }
} }
} }

View File

@ -21,5 +21,6 @@ namespace Sample.SqlServer.DbContexts
modelBuilder.ApplyConfiguration(new SysTestMap()); modelBuilder.ApplyConfiguration(new SysTestMap());
} }
public override Type ShardingDbContextType => this.GetType();
} }
} }

View File

@ -5,4 +5,12 @@
<LangVersion>9.0</LangVersion> <LangVersion>9.0</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -1,21 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Sample.SqlServer.DbContexts; using Sample.SqlServer.DbContexts;
using Sample.SqlServer.Shardings; using Sample.SqlServer.Shardings;
using ShardingCore; using ShardingCore;
using ShardingCore.EFCores;
using ShardingCore.SqlServer;
namespace Sample.SqlServer namespace Sample.SqlServer
{ {
@ -30,31 +21,17 @@ namespace Sample.SqlServer
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddControllers(); services.AddControllers();
services.AddShardingSqlServer(o =>
{
o.EnsureCreatedWithOutShardingTable = false;
o.CreateShardingTableOnStart = false;
o.UseShardingDbContext<DefaultTableDbContext>( dbConfig =>
{
dbConfig.AddShardingTableRoute<SysUserModVirtualTableRoute>();
});
//o.AddDataSourceVirtualRoute<>();
});
services.AddDbContext<DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True")); services.AddDbContext<DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True"));
services.AddShardingDbContext<DefaultShardingDbContext, DefaultTableDbContext>(op => services.AddShardingDbContext<DefaultShardingDbContext, DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBxx;Integrated Security=True;MultipleActiveResultSets=True;")
{ ,op =>
op.UseShardingDbContextOptions((connection, builder) =>
{ {
return builder.UseSqlServer(connection).UseLoggerFactory(efLogger) op.EnsureCreatedWithOutShardingTable = true;
.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll) op.CreateShardingTableOnStart = true;
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>() op.UseShardingDbContextOptions((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger));
.ReplaceService<IModelCustomizer, ShardingModelCustomizer>().Options; op.AddShardingTableRoute<SysUserModVirtualTableRoute>();
}); });
},o =>
o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True;MultipleActiveResultSets=True;").UseSharding());
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -70,7 +47,7 @@ namespace Sample.SqlServer
app.UseRouting(); app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
//app.DbSeed(); app.DbSeed();
} }
} }
} }

View File

@ -1,83 +0,0 @@
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.Helpers;
using ShardingCore.Sharding.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/5 17:30:10
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public abstract class AbstractShardingCoreOptions : IShardingCoreOptions
{
private ShardingConfigEntry _shardingConfigEntry;
public void UseShardingDbContext<TContext>(Action<ShardingDbConfigOptions> func) where TContext : DbContext,IShardingTableDbContext
{
if (_shardingConfigEntry!=null)
{
throw new ArgumentException($"same db context inited:[{typeof(TContext)}]");
}
ShardingCoreHelper.CheckContextConstructors<TContext>();
var creator = ShardingCoreHelper.CreateActivator<TContext>();
_shardingConfigEntry = new ShardingConfigEntry(creator, typeof(TContext), func);
}
private readonly Dictionary<Type, Type> _virtualRoutes = new Dictionary<Type, Type>();
public ShardingConfigEntry GetShardingConfig()
{
return _shardingConfigEntry;
}
public ISet<Type> GetVirtualRoutes()
{
return _virtualRoutes.Select(o => o.Value).ToHashSet();
}
public Type GetVirtualRoute(Type entityType)
{
if (!_virtualRoutes.ContainsKey(entityType))
throw new ArgumentException("not found IDataSourceVirtualRoute");
return _virtualRoutes[entityType];
}
/// <summary>
/// 如果数据库不存在就创建并且创建表除了分表的
/// </summary>
public bool EnsureCreatedWithOutShardingTable { get; set; }
/// <summary>
/// 是否需要在启动时创建分表
/// </summary>
public bool? CreateShardingTableOnStart { get; set; }
public readonly List<Type> _filters = new List<Type>();
/// <summary>
/// 添加filter过滤器
/// </summary>
/// <typeparam name="TFilter"></typeparam>
public void AddDbContextCreateFilter<TFilter>() where TFilter : class, IDbContextCreateFilter
{
if (_filters.Contains(typeof(TFilter)))
throw new ArgumentException("请勿重复添加DbContextCreateFilter");
_filters.Add(typeof(TFilter));
}
public List<Type> GetFilters()
{
return _filters;
}
public bool? IgnoreCreateTableError { get; set; }
}
}

View File

@ -1,13 +0,0 @@
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 22 December 2020 15:13:44
* @Email: 326308290@qq.com
*/
public interface IShardingAccessor
{
ShardingContext ShardingContext { get; set; }
}
}

View File

@ -1,20 +0,0 @@
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 23 December 2020 07:51:00
* @Email: 326308290@qq.com
*/
/// <summary>
/// 查询scope创建
/// </summary>
public interface IShardingScopeFactory
{
/// <summary>
/// 创建查询scope
/// </summary>
/// <returns></returns>
ShardingScope CreateScope();
}
}

View File

@ -1,26 +0,0 @@
using System.Threading;
using ShardingCore.Core.VirtualTables;
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 22 December 2020 15:14:15
* @Email: 326308290@qq.com
*/
/// <summary>
/// 分表访问器
/// </summary>
public class ShardingAccessor : IShardingAccessor
{
private static AsyncLocal<ShardingContext> _shardingContext = new AsyncLocal<ShardingContext>();
/// <inheritdoc />
public ShardingContext ShardingContext
{
get => _shardingContext.Value;
set => _shardingContext.Value = value;
}
}
}

View File

@ -1,71 +0,0 @@
using System.Collections.Generic;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Extensions;
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 22 December 2020 15:04:47
* @Email: 326308290@qq.com
*/
public class ShardingContext
{
private ShardingContext(RouteResult routeResult)
{
foreach (var physicTable in routeResult.ReplaceTables)
{
_shardingTables.Add(physicTable.VirtualTable, new List<string>(1){physicTable.Tail});
}
}
/// <summary>
/// 分表操作上下文 key:物理表名 value:虚拟表和本次分表tails
/// </summary>
private readonly Dictionary<IVirtualTable, List<string>> _shardingTables = new Dictionary<IVirtualTable, List<string>>();
/// <summary>
/// 尝试添加本次操作表
/// </summary>
/// <param name="virtualTable"></param>
/// <param name="tails"></param>
/// <returns></returns>
public void TryAddShardingTable(IVirtualTable virtualTable, List<string> tails)
{
_shardingTables.Add(virtualTable, tails);
}
/// <summary>
/// 创建一个分表上下文
/// </summary>
/// <returns></returns>
public static ShardingContext Create(RouteResult routeResult)
{
return new ShardingContext(routeResult);
}
/// <summary>
/// 获取分表信息
/// </summary>
/// <param name="virtualTable"></param>
/// <returns></returns>
public List<string> GetContextQueryTails(IVirtualTable virtualTable)
{
if (_shardingTables.ContainsKey(virtualTable))
return _shardingTables[virtualTable] ?? new List<string>(0);
return new List<string>(0);
}
/// <summary>
/// 是否是空的
/// </summary>
/// <returns></returns>
public bool IsEmpty()
{
return _shardingTables.IsEmpty();
}
}
}

View File

@ -1,36 +0,0 @@
using System;
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 23 December 2020 07:51:30
* @Email: 326308290@qq.com
*/
public class ShardingScope : IDisposable
{
/// <summary>
/// 分表配置访问器
/// </summary>
public IShardingAccessor ShardingAccessor { get; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="shardingAccessor"></param>
public ShardingScope(IShardingAccessor shardingAccessor)
{
ShardingAccessor = shardingAccessor;
}
/// <summary>
/// 回收
/// </summary>
public void Dispose()
{
ShardingAccessor.ShardingContext = null;
}
}
}

View File

@ -1,34 +0,0 @@
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 23 December 2020 08:11:06
* @Email: 326308290@qq.com
*/
/// <summary>
/// 分表查询环境创建
/// </summary>
public class ShardingScopeFactory : IShardingScopeFactory
{
private readonly IShardingAccessor _shardingAccessor;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="shardingAccessor"></param>
public ShardingScopeFactory(IShardingAccessor shardingAccessor)
{
_shardingAccessor = shardingAccessor;
}
/// <summary>
/// 创建scope
/// </summary>
/// <returns></returns>
public ShardingScope CreateScope()
{
_shardingAccessor.ShardingContext = null;
return new ShardingScope(_shardingAccessor);
}
}
}

View File

@ -1,4 +1,7 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{ {
@ -10,6 +13,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
*/ */
public interface IRouteRuleEngine public interface IRouteRuleEngine
{ {
IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> routeRuleContext); IEnumerable<RouteResult> Route<T,TShardingDbContext>(RouteRuleContext<T> routeRuleContext) where TShardingDbContext:DbContext,IShardingDbContext;
IEnumerable<RouteResult> Route<T>(Type shardingDbContextType,RouteRuleContext<T> routeRuleContext);
} }
} }

View File

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{ {
@ -13,7 +16,9 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{ {
IRouteRuleEngine CreateEngine(); IRouteRuleEngine CreateEngine();
RouteRuleContext<T> CreateContext<T>(IQueryable<T> queryable); RouteRuleContext<T> CreateContext<T>(IQueryable<T> queryable);
IEnumerable<RouteResult> Route<T>(IQueryable<T> queryable); IEnumerable<RouteResult> Route<T,TShardingDbContext>(IQueryable<T> queryable) where TShardingDbContext:DbContext,IShardingDbContext;
IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> ruleContext); IEnumerable<RouteResult> Route<T, TShardingDbContext>(RouteRuleContext<T> ruleContext) where TShardingDbContext : DbContext, IShardingDbContext;
IEnumerable<RouteResult> Route<T>(Type shardingDbContextType,IQueryable<T> queryable);
IEnumerable<RouteResult> Route<T>(Type shardingDbContextType,RouteRuleContext<T> ruleContext);
} }
} }

View File

@ -1,8 +1,12 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.PhysicTables; using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualTables; using ShardingCore.Core.VirtualTables;
using ShardingCore.Extensions; using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
#if !EFCORE5 #if !EFCORE5
using ShardingCore.Extensions; using ShardingCore.Extensions;
#endif #endif
@ -24,30 +28,9 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
_virtualTableManager = virtualTableManager; _virtualTableManager = virtualTableManager;
} }
public IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> routeRuleContext) public IEnumerable<RouteResult> Route<T, TShardingDbContext>(RouteRuleContext<T> routeRuleContext) where TShardingDbContext : DbContext, IShardingDbContext
{ {
Dictionary<IVirtualTable, ISet<IPhysicTable>> routeMaps = new Dictionary<IVirtualTable, ISet<IPhysicTable>>(); return Route(typeof(TShardingDbContext), routeRuleContext);
var queryEntities = routeRuleContext.Queryable.ParseQueryableRoute();
var shardingEntities = queryEntities.Where(o => o.IsShardingTable());
foreach (var shardingEntity in shardingEntities)
{
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntity);
var physicTables = virtualTable.RouteTo(new TableRouteConfig(routeRuleContext.Queryable));
if (!routeMaps.ContainsKey(virtualTable))
{
routeMaps.Add(virtualTable, physicTables.ToHashSet());
}
else
{
foreach (var physicTable in physicTables)
{
routeMaps[virtualTable].Add(physicTable);
}
}
}
////先添加手动路由到当前上下文,之后将不再手动路由里面的自动路由添加到当前上下文 ////先添加手动路由到当前上下文,之后将不再手动路由里面的自动路由添加到当前上下文
//foreach (var kv in routeRuleContext.ManualTails) //foreach (var kv in routeRuleContext.ManualTails)
//{ //{
@ -105,8 +88,34 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
// } // }
// } // }
//} //}
}
return routeMaps.Select(o => o.Value).Cartesian().Select(o=>new RouteResult(o)); public IEnumerable<RouteResult> Route<T>(Type shardingDbContextType, RouteRuleContext<T> routeRuleContext)
{
Dictionary<IVirtualTable, ISet<IPhysicTable>> routeMaps = new Dictionary<IVirtualTable, ISet<IPhysicTable>>();
var queryEntities = routeRuleContext.Queryable.ParseQueryableRoute();
var shardingEntities = queryEntities.Where(o => o.IsShardingTable());
foreach (var shardingEntity in shardingEntities)
{
var virtualTable = _virtualTableManager.GetVirtualTable(shardingDbContextType, shardingEntity);
var physicTables = virtualTable.RouteTo(new TableRouteConfig(routeRuleContext.Queryable));
if (!routeMaps.ContainsKey(virtualTable))
{
routeMaps.Add(virtualTable, physicTables.ToHashSet());
}
else
{
foreach (var physicTable in physicTables)
{
routeMaps[virtualTable].Add(physicTable);
}
}
}
return routeMaps.Select(o => o.Value).Cartesian().Select(o => new RouteResult(o));
} }
} }
} }

View File

@ -1,21 +1,24 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.VirtualTables; using ShardingCore.Core.VirtualTables;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{ {
/* /*
* @Author: xjm * @Author: xjm
* @Description: * @Description:
* @Date: Thursday, 28 January 2021 13:31:06 * @Date: Thursday, 28 January 2021 13:31:06
* @Email: 326308290@qq.com * @Email: 326308290@qq.com
*/ */
public class RoutingRuleEngineFactory : IRoutingRuleEngineFactory public class RoutingRuleEngineFactory : IRoutingRuleEngineFactory
{ {
private readonly IRouteRuleEngine _routeRuleEngine; private readonly IRouteRuleEngine _routeRuleEngine;
private readonly IVirtualTableManager _virtualTableManager; private readonly IVirtualTableManager _virtualTableManager;
public RoutingRuleEngineFactory(IRouteRuleEngine routeRuleEngine,IVirtualTableManager virtualTableManager) public RoutingRuleEngineFactory(IRouteRuleEngine routeRuleEngine, IVirtualTableManager virtualTableManager)
{ {
_routeRuleEngine = routeRuleEngine; _routeRuleEngine = routeRuleEngine;
_virtualTableManager = virtualTableManager; _virtualTableManager = virtualTableManager;
@ -31,17 +34,30 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
return new RouteRuleContext<T>(queryable, _virtualTableManager); return new RouteRuleContext<T>(queryable, _virtualTableManager);
} }
public IEnumerable<RouteResult> Route<T>(IQueryable<T> queryable) public IEnumerable<RouteResult> Route<T, TShardingDbContext>(IQueryable<T> queryable) where TShardingDbContext : DbContext, IShardingDbContext
{ {
var engine = CreateEngine(); var engine = CreateEngine();
var ruleContext = CreateContext<T>(queryable); var ruleContext = CreateContext<T>(queryable);
return engine.Route(ruleContext); return engine.Route<T,TShardingDbContext>(ruleContext);
} }
public IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> ruleContext) public IEnumerable<RouteResult> Route<T, TShardingDbContext>(RouteRuleContext<T> ruleContext) where TShardingDbContext : DbContext, IShardingDbContext
{ {
var engine = CreateEngine(); var engine = CreateEngine();
return engine.Route(ruleContext); return engine.Route<T, TShardingDbContext>(ruleContext);
}
public IEnumerable<RouteResult> Route<T>(Type shardingDbContextType, IQueryable<T> queryable)
{
var engine = CreateEngine();
var ruleContext = CreateContext<T>(queryable);
return engine.Route(shardingDbContextType,ruleContext);
}
public IEnumerable<RouteResult> Route<T>(Type shardingDbContextType, RouteRuleContext<T> ruleContext)
{
var engine = CreateEngine();
return engine.Route(shardingDbContextType,ruleContext);
} }
} }
} }

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.PhysicTables; using ShardingCore.Core.PhysicTables;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualTables namespace ShardingCore.Core.VirtualTables
{ {
@ -18,58 +20,70 @@ namespace ShardingCore.Core.VirtualTables
/// <summary> /// <summary>
/// 添加虚拟表应用启动时 add virtual table when app start /// 添加虚拟表应用启动时 add virtual table when app start
/// </summary> /// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="virtualTable">虚拟表</param> /// <param name="virtualTable">虚拟表</param>
void AddVirtualTable(IVirtualTable virtualTable); void AddVirtualTable(Type shardingDbContextType,IVirtualTable virtualTable);
/// <summary> /// <summary>
/// 获取虚拟表 get virtual table by sharding entity type /// 获取虚拟表 get virtual table by sharding entity type
/// </summary> /// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="shardingEntityType"></param> /// <param name="shardingEntityType"></param>
/// <returns></returns> /// <returns></returns>
IVirtualTable GetVirtualTable(Type shardingEntityType); IVirtualTable GetVirtualTable(Type shardingDbContextType, Type shardingEntityType);
/// <summary> /// <summary>
/// 获取虚拟表 get virtual table by sharding entity type /// 获取虚拟表 get virtual table by sharding entity type
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
IVirtualTable<T> GetVirtualTable<T>() where T : class, IShardingTable; IVirtualTable<T> GetVirtualTable<TDbContext,T>() where T : class, IShardingTable where TDbContext : DbContext, IShardingDbContext;
/// <summary> /// <summary>
/// 获取虚拟表 get virtual table by original table name /// 获取虚拟表 get virtual table by original table name
/// </summary> /// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="originalTableName"></param> /// <param name="originalTableName"></param>
/// <returns></returns> /// <returns></returns>
IVirtualTable GetVirtualTable(string originalTableName); IVirtualTable GetVirtualTable(Type shardingDbContextType, string originalTableName);
IVirtualTable GetVirtualTable<TDbContext>(string originalTableName) where TDbContext : DbContext, IShardingDbContext;
/// <summary> /// <summary>
/// 尝试获取虚拟表没有返回null /// 尝试获取虚拟表没有返回null
/// </summary> /// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="originalTableName"></param> /// <param name="originalTableName"></param>
/// <returns></returns> /// <returns></returns>
IVirtualTable TryGetVirtualTable(string originalTableName); IVirtualTable TryGetVirtualTable(Type shardingDbContextType, string originalTableName);
IVirtualTable TryGetVirtualTablee<TDbContext>(string originalTableName) where TDbContext : DbContext, IShardingDbContext;
/// <summary> /// <summary>
/// 获取所有的虚拟表 get all virtual table /// 获取所有的虚拟表 get all virtual table
/// </summary> /// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <returns></returns> /// <returns></returns>
List<IVirtualTable> GetAllVirtualTables(); List<IVirtualTable> GetAllVirtualTables(Type shardingDbContextType);
List<IVirtualTable> GetAllVirtualTables<TDbContext>() where TDbContext : DbContext, IShardingDbContext;
/// <summary> /// <summary>
/// 添加物理表 add physic table /// 添加物理表 add physic table
/// </summary> /// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="virtualTable"></param> /// <param name="virtualTable"></param>
/// <param name="physicTable"></param> /// <param name="physicTable"></param>
void AddPhysicTable(IVirtualTable virtualTable, IPhysicTable physicTable); void AddPhysicTable(Type shardingDbContextType,IVirtualTable virtualTable, IPhysicTable physicTable);
void AddPhysicTable<TDbContext>(IVirtualTable virtualTable, IPhysicTable physicTable) where TDbContext : DbContext, IShardingDbContext;
/// <summary> /// <summary>
/// 添加物理表 add physic table /// 添加物理表 add physic table
/// </summary> /// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="shardingEntityType"></param> /// <param name="shardingEntityType"></param>
/// <param name="physicTable"></param> /// <param name="physicTable"></param>
void AddPhysicTable(Type shardingEntityType, IPhysicTable physicTable); void AddPhysicTable(Type shardingDbContextType,Type shardingEntityType, IPhysicTable physicTable);
void AddPhysicTable<TDbContext>(Type shardingEntityType, IPhysicTable physicTable) where TDbContext : DbContext, IShardingDbContext;
///// <summary> ///// <summary>
///// 添加物理表 add physic table ///// 添加物理表 add physic table

View File

@ -2,25 +2,29 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.PhysicTables; using ShardingCore.Core.PhysicTables;
using ShardingCore.Exceptions; using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualTables namespace ShardingCore.Core.VirtualTables
{ {
/* /*
* @Author: xjm * @Author: xjm
* @Description: * @Description:
* @Date: Friday, 18 December 2020 14:52:42 * @Date: Friday, 18 December 2020 14:52:42
* @Email: 326308290@qq.com * @Email: 326308290@qq.com
*/ */
/// <summary> /// <summary>
/// 同一个数据库下的虚拟表管理者 /// 同一个数据库下的虚拟表管理者
/// </summary> /// </summary>
public class OneDbVirtualTableManager : IVirtualTableManager public class OneDbVirtualTableManager : IVirtualTableManager
{ {
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly ConcurrentDictionary<Type, IVirtualTable> _shardingVirtualTables = new ConcurrentDictionary<Type, IVirtualTable>(); //{sharidngDbContextType:{entityType,virtualTableType}}
private readonly ConcurrentDictionary<string, IVirtualTable> _shardingOriginalTaleVirtualTales = new ConcurrentDictionary<string, IVirtualTable>(); private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, IVirtualTable>> _shardingVirtualTables = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, IVirtualTable>>();
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, IVirtualTable>> _shardingOriginalTaleVirtualTales = new ConcurrentDictionary<Type, ConcurrentDictionary<string, IVirtualTable>>();
public OneDbVirtualTableManager(IServiceProvider serviceProvider) public OneDbVirtualTableManager(IServiceProvider serviceProvider)
{ {
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
@ -38,62 +42,135 @@ namespace ShardingCore.Core.VirtualTables
//} //}
} }
public void AddVirtualTable(IVirtualTable virtualTable) private void CheckShardingDbContextType(Type shardingDbContextType)
{ {
if (!_shardingVirtualTables.ContainsKey(virtualTable.EntityType)) if (!shardingDbContextType.IsShardingDbContext())
throw new ShardingCoreException(
$"{shardingDbContextType.FullName} must impl {nameof(IShardingDbContext)}");
}
private void CheckShardingTableEntityType(Type shardingEntityType)
{
if (!shardingEntityType.IsShardingTable())
throw new ShardingCoreException(
$"{shardingEntityType.FullName} must impl {nameof(IShardingTable)}");
}
private string CreateShardingEntityTypeKey(Type shardingDbContextType, Type entityType)
{
return $"{shardingDbContextType.FullName}{entityType.FullName}";
}
private string CreateShardingTableNameKey(Type shardingDbContextType, string originalTableName)
{
return $"{shardingDbContextType.FullName}{originalTableName}";
}
public void AddVirtualTable(Type shardingDbContextType, IVirtualTable virtualTable)
{
CheckShardingDbContextType(shardingDbContextType);
var innerShardingVirtualTables = _shardingVirtualTables.GetOrAdd(shardingDbContextType,
key => new ConcurrentDictionary<Type, IVirtualTable>());
if (!innerShardingVirtualTables.ContainsKey(virtualTable.EntityType))
{ {
_shardingVirtualTables.TryAdd(virtualTable.EntityType, virtualTable); innerShardingVirtualTables.TryAdd(virtualTable.EntityType, virtualTable);
} }
if (!_shardingOriginalTaleVirtualTales.ContainsKey(virtualTable.GetOriginalTableName())) var innerShardingOriginalTableVirtualTables = _shardingOriginalTaleVirtualTales.GetOrAdd(shardingDbContextType,type=>new ConcurrentDictionary<string, IVirtualTable>());
if (!innerShardingOriginalTableVirtualTables.ContainsKey(virtualTable.GetOriginalTableName()))
{ {
_shardingOriginalTaleVirtualTales.TryAdd(virtualTable.GetOriginalTableName(), virtualTable); innerShardingOriginalTableVirtualTables.TryAdd(virtualTable.GetOriginalTableName(), virtualTable);
} }
} }
public IVirtualTable GetVirtualTable(Type shardingEntityType) public IVirtualTable GetVirtualTable(Type shardingDbContextType, Type shardingEntityType)
{ {
if (!_shardingVirtualTables.TryGetValue(shardingEntityType, out var virtualTable)) CheckShardingDbContextType(shardingDbContextType);
CheckShardingTableEntityType(shardingEntityType);
var shardingKey = CreateShardingEntityTypeKey(shardingDbContextType, shardingEntityType);
if(!_shardingVirtualTables.TryGetValue(shardingDbContextType,out var innerShardingVirtualTables) || innerShardingVirtualTables.IsEmpty())
throw new ShardingVirtualTableNotFoundException(shardingDbContextType.FullName);
if (!innerShardingVirtualTables.TryGetValue(shardingEntityType, out var virtualTable)||virtualTable==null)
throw new ShardingVirtualTableNotFoundException(shardingEntityType.FullName); throw new ShardingVirtualTableNotFoundException(shardingEntityType.FullName);
return virtualTable; return virtualTable;
} }
public IVirtualTable<T> GetVirtualTable<T>() where T : class, IShardingTable public IVirtualTable<T> GetVirtualTable<TDbContext, T>() where T : class, IShardingTable where TDbContext : DbContext, IShardingDbContext
{ {
return (IVirtualTable<T>)GetVirtualTable(typeof(T)); return (IVirtualTable<T>)GetVirtualTable(typeof(TDbContext), typeof(T));
} }
public IVirtualTable GetVirtualTable(string originalTableName) public IVirtualTable GetVirtualTable(Type shardingDbContextType, string originalTableName)
{ {
if (!_shardingOriginalTaleVirtualTales.TryGetValue(originalTableName, out var virtualTable)||virtualTable==null) CheckShardingDbContextType(shardingDbContextType);
if (!_shardingOriginalTaleVirtualTales.TryGetValue(shardingDbContextType, out var innerShardingOriginalTableVirtualTables) || innerShardingOriginalTableVirtualTables.IsEmpty())
throw new ShardingVirtualTableNotFoundException(shardingDbContextType.FullName);
if(!innerShardingOriginalTableVirtualTables.TryGetValue(originalTableName,out var virtualTable)|| virtualTable==null)
throw new ShardingVirtualTableNotFoundException(originalTableName); throw new ShardingVirtualTableNotFoundException(originalTableName);
return virtualTable; return virtualTable;
} }
public IVirtualTable TryGetVirtualTable(string originalTableName) public IVirtualTable GetVirtualTable<TDbContext>(string originalTableName) where TDbContext : DbContext, IShardingDbContext
{ {
if (!_shardingOriginalTaleVirtualTales.TryGetValue(originalTableName, out var virtualTable)) return GetVirtualTable(typeof(TDbContext), originalTableName);
}
public IVirtualTable TryGetVirtualTable(Type shardingDbContextType, string originalTableName)
{
CheckShardingDbContextType(shardingDbContextType);
if (!_shardingOriginalTaleVirtualTales.TryGetValue(shardingDbContextType,
out var innerShardingOriginalTableVirtualTables) || innerShardingOriginalTableVirtualTables.IsEmpty())
return null;
if (!innerShardingOriginalTableVirtualTables.TryGetValue(originalTableName, out var virtualTable) || virtualTable == null)
return null; return null;
return virtualTable; return virtualTable;
} }
public List<IVirtualTable> GetAllVirtualTables() public IVirtualTable TryGetVirtualTablee<TDbContext>(string originalTableName) where TDbContext : DbContext, IShardingDbContext
{ {
return _shardingVirtualTables.Values.ToList(); return TryGetVirtualTable(typeof(TDbContext), originalTableName);
} }
public void AddPhysicTable(IVirtualTable virtualTable, IPhysicTable physicTable) public List<IVirtualTable> GetAllVirtualTables(Type shardingDbContextType)
{ {
AddPhysicTable(virtualTable.EntityType, physicTable); if (!_shardingOriginalTaleVirtualTales.TryGetValue(shardingDbContextType,
out var innerShardingOriginalTableVirtualTables) || innerShardingOriginalTableVirtualTables.IsEmpty())
return new List<IVirtualTable>();
var keyPrefix = shardingDbContextType.FullName;
return innerShardingOriginalTableVirtualTables.Values.ToList();
} }
public void AddPhysicTable(Type shardingEntityType, IPhysicTable physicTable) public List<IVirtualTable> GetAllVirtualTables<TDbContext>() where TDbContext : DbContext, IShardingDbContext
{ {
var virtualTable = GetVirtualTable(shardingEntityType); return GetAllVirtualTables(typeof(TDbContext));
}
public void AddPhysicTable(Type shardingDbContextType, IVirtualTable virtualTable, IPhysicTable physicTable)
{
AddPhysicTable(shardingDbContextType, virtualTable.EntityType, physicTable);
}
public void AddPhysicTable<TDbContext>(IVirtualTable virtualTable, IPhysicTable physicTable) where TDbContext : DbContext, IShardingDbContext
{
AddPhysicTable(typeof(TDbContext), virtualTable.EntityType, physicTable);
}
public void AddPhysicTable(Type shardingDbContextType, Type shardingEntityType, IPhysicTable physicTable)
{
var virtualTable = GetVirtualTable(shardingDbContextType, shardingEntityType);
virtualTable.AddPhysicTable(physicTable); virtualTable.AddPhysicTable(physicTable);
} }
public void AddPhysicTable<TDbContext>(Type shardingEntityType, IPhysicTable physicTable) where TDbContext : DbContext, IShardingDbContext
{
var virtualTable = GetVirtualTable(typeof(TDbContext), shardingEntityType);
virtualTable.AddPhysicTable(physicTable);
}
///// <summary> ///// <summary>
///// 是否是分表字段 ///// 是否是分表字段
@ -103,7 +180,7 @@ namespace ShardingCore.Core.VirtualTables
///// <returns></returns> ///// <returns></returns>
//public bool IsShardingKey(Type shardingEntityType, string shardingField) //public bool IsShardingKey(Type shardingEntityType, string shardingField)
//{ //{
// return _virtualTables.TryGetValue(shardingEntityType, out var virtualTable) && virtualTable.ShardingConfig.ShardingField == shardingField; // return _virtualTables.TryGetValue(shardingEntityType, out var virtualTable) && virtualTable.ShardingConfigOption.ShardingField == shardingField;
//} //}
} }
} }

View File

@ -1,17 +1,17 @@
using System;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Core.Internal.StreamMerge;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.Core.VirtualTables; using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts; using ShardingCore.DbContexts;
using ShardingCore.DbContexts.Abstractions; using ShardingCore.EFCores;
using ShardingCore.DbContexts.ShardingDbContexts; using ShardingCore.Helpers;
using ShardingCore.Sharding; using ShardingCore.Sharding;
using ShardingCore.Sharding.Abstractions; using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Enumerators;
using ShardingCore.TableCreator; using ShardingCore.TableCreator;
using System;
namespace ShardingCore namespace ShardingCore
{ {
@ -24,9 +24,48 @@ namespace ShardingCore
public static class DIExtension public static class DIExtension
{ {
public static IServiceCollection AddShardingCore(this IServiceCollection services)
public static IServiceCollection AddShardingDbContext<TShardingDbContext, TActualDbContext>(this IServiceCollection services,
Action<DbContextOptionsBuilder> optionsAction = null,
Action<ShardingConfigOption<TShardingDbContext,TActualDbContext>> configure=null,
ServiceLifetime contextLifetime = ServiceLifetime.Scoped,
ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
where TActualDbContext : DbContext, IShardingTableDbContext
where TShardingDbContext : DbContext, IShardingTableDbContext<TActualDbContext>
{
if (configure == null)
throw new ArgumentNullException($"AddShardingDbContext params is null :{nameof(configure)}");
ShardingCoreHelper.CheckContextConstructors<TActualDbContext>();
var shardingConfigOptions = new ShardingConfigOption<TShardingDbContext,TActualDbContext>();
configure?.Invoke(shardingConfigOptions);
services.AddSingleton<IShardingConfigOption, ShardingConfigOption<TShardingDbContext, TActualDbContext>>(sp=> shardingConfigOptions);
//添加创建TActualDbContext 的 创建者
var config = new ShardingDbContextOptionsBuilderConfig<TShardingDbContext>(shardingConfigOptions.ShardingDbContextOptionsCreator);
services.AddSingleton<IShardingDbContextOptionsBuilderConfig, ShardingDbContextOptionsBuilderConfig<TShardingDbContext>>(sp=> config);
//添加创建TActualDbContext创建者
services.AddSingleton<IShardingDbContextCreatorConfig,DefaultShardingDbContextCreatorConfig<TShardingDbContext, TActualDbContext>>(sp=> new DefaultShardingDbContextCreatorConfig<TShardingDbContext, TActualDbContext>(typeof(TActualDbContext)));
Action<DbContextOptionsBuilder> shardingOptionAction = option =>
{
optionsAction?.Invoke(option);
option.UseSharding();
};
services.AddDbContext<TShardingDbContext>(shardingOptionAction, contextLifetime, optionsLifetime);
services.AddInternalShardingCore();
services.AddSingleton<IShardingBootstrapper, ShardingBootstrapper>();
return services;
}
internal static IServiceCollection AddInternalShardingCore(this IServiceCollection services)
{ {
services.AddSingleton<IDbContextCreateFilterManager, DbContextCreateFilterManager>();
services.AddSingleton<IStreamMergeContextFactory, StreamMergeContextFactory>(); services.AddSingleton<IStreamMergeContextFactory, StreamMergeContextFactory>();
services.AddSingleton<IShardingDbContextFactory, ShardingDbContextFactory>(); services.AddSingleton<IShardingDbContextFactory, ShardingDbContextFactory>();
@ -38,33 +77,20 @@ namespace ShardingCore
//分表引擎 //分表引擎
services.AddSingleton<IRouteRuleEngine, QueryRouteRuleEngines>(); services.AddSingleton<IRouteRuleEngine, QueryRouteRuleEngines>();
//services.AddSingleton(typeof(IVirtualTable<>), typeof(OneDbVirtualTable<>)); //services.AddSingleton(typeof(IVirtualTable<>), typeof(OneDbVirtualTable<>));
services.AddSingleton<IShardingAccessor, ShardingAccessor>(); //services.AddSingleton<IShardingAccessor, ShardingAccessor>();
services.AddSingleton<IShardingScopeFactory, ShardingScopeFactory>(); //services.AddSingleton<IShardingScopeFactory, ShardingScopeFactory>();
return services; return services;
} }
internal static DbContextOptionsBuilder UseSharding(this DbContextOptionsBuilder optionsBuilder)
public static IServiceCollection AddShardingDbContext<TShardingDbContext, TActualDbContext>(this IServiceCollection services,
Action<ShardingConfig<TActualDbContext>> configure,
Action<DbContextOptionsBuilder> optionsAction = null,
ServiceLifetime contextLifetime = ServiceLifetime.Scoped,
ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
where TActualDbContext : DbContext, IShardingTableDbContext
where TShardingDbContext : DbContext
{ {
if (configure == null) return optionsBuilder.ReplaceService<IDbSetSource, ShardingDbSetSource>()
throw new ArgumentNullException($"AddScfSqlServerProvider 参数不能为空:{nameof(configure)}"); .ReplaceService<IQueryCompiler, ShardingQueryCompiler>();
var shardingConfig = new ShardingConfig<TActualDbContext>(); }
configure?.Invoke(shardingConfig); internal static DbContextOptionsBuilder UseInnerDbContextSharding<TShardingDbContext>(this DbContextOptionsBuilder optionsBuilder) where TShardingDbContext:DbContext,IShardingDbContext
services.AddSingleton(shardingConfig); {
return optionsBuilder.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
services.AddDbContext<TShardingDbContext>(optionsAction, contextLifetime, optionsLifetime); .ReplaceService<IModelCustomizer, ShardingModelCustomizer<TShardingDbContext>>();
services.AddShardingCore();
services.AddSingleton<IShardingBootstrapper, ShardingBootstrapper>();
return services;
} }
} }
} }

View File

@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ShardingCore.DbContexts.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/13 8:19:26
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class DbContextCreateFilterManager: IDbContextCreateFilterManager
{
private readonly List<IDbContextCreateFilter> _filters = new List<IDbContextCreateFilter>();
public void RegisterFilter(IDbContextCreateFilter filter)
{
if (null == filter)
throw new ArgumentNullException(nameof(filter));
if(!_filters.Contains(filter))
_filters.Add(filter);
}
public List<IDbContextCreateFilter> GetFilters()
{
return _filters;
}
}
}

View File

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/13 8:17:41
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IDbContextCreateFilter
{
/// <summary>
/// dbContext创建完成后
/// </summary>
/// <param name="dbContext"></param>
/// <param name="s"></param>
void CreateAfter(DbContext dbContext);
}
}

View File

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
namespace ShardingCore.DbContexts.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 12 March 2021 22:25:10
* @Email: 326308290@qq.com
*/
public interface IDbContextCreateFilterManager
{
void RegisterFilter(IDbContextCreateFilter filter);
List<IDbContextCreateFilter> GetFilters();
}
}

View File

@ -1,47 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.Extensions.Logging;
using ShardingCore.EFCores;
namespace ShardingCore.DbContexts.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: Sunday, 07 February 2021 15:25:36
* @Email: 326308290@qq.com
*/
public class ShardingDbContextOptionBuilder
{
private readonly DbContextOptionsBuilder _builder;
public ShardingDbContextOptionBuilder():this(new DbContextOptionsBuilder())
{
}
public ShardingDbContextOptionBuilder(DbContextOptionsBuilder optionsBuilder)
{
_builder = optionsBuilder
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
.ReplaceService<IModelCustomizer, ShardingModelCustomizer>();
}
public ShardingDbContextOptionBuilder UseLoggerFactory(ILoggerFactory loggerFactory)
{
_builder.UseLoggerFactory(loggerFactory);
return this;
}
public DbContextOptionsBuilder GetOptionsBuilder()
{
return _builder;
}
}
public class ShardingDbContextOptionBuilder<T>:ShardingDbContextOptionBuilder where T:DbContext
{
}
}

View File

@ -3,6 +3,7 @@ using System.Data.Common;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.ShardingDbContexts; using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.DbContexts.VirtualDbContexts; using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.DbContexts namespace ShardingCore.DbContexts
{ {
@ -14,7 +15,8 @@ namespace ShardingCore.DbContexts
*/ */
public interface IShardingDbContextFactory public interface IShardingDbContextFactory
{ {
DbContext Create(ShardingDbContextOptions shardingDbContextOptions); DbContext Create(Type shardingDbContextType,ShardingDbContextOptions shardingDbContextOptions);
DbContext Create<TShardingDbContext>(ShardingDbContextOptions shardingDbContextOptions) where TShardingDbContext:DbContext,IShardingDbContext;
//DbContext Create(DbConnection dbConnection,string tail); //DbContext Create(DbConnection dbConnection,string tail);
} }
} }

View File

@ -1,16 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 29 December 2020 15:22:06
* @Email: 326308290@qq.com
*/
public interface IShardingParallelDbContextFactory
{
DbContext Create(string tail);
}
}

View File

@ -1,16 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts
{
/*
* @Author: xjm
* @Description:
* @Date: Saturday, 20 February 2021 15:04:25
* @Email: 326308290@qq.com
*/
public interface IShardingParallelDbContextFactoryManager
{
public DbContext CreateDbContext(string connectKey, string tail);
}
}

View File

@ -1,64 +1,54 @@
using System;
using System.Data.Common;
using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.DbContexts.ShardingDbContexts; using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.DbContexts.VirtualDbContexts; using ShardingCore.Exceptions;
using ShardingCore.Extensions; using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions; using ShardingCore.Sharding.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ShardingCore.DbContexts namespace ShardingCore.DbContexts
{ {
/* /*
* @Author: xjm * @Author: xjm
* @Description: * @Description:
* @Date: Thursday, 24 December 2020 08:22:48 * @Date: Thursday, 24 December 2020 08:22:48
* @Email: 326308290@qq.com * @Email: 326308290@qq.com
*/ */
public class ShardingDbContextFactory:IShardingDbContextFactory public class ShardingDbContextFactory:IShardingDbContextFactory
{ {
private readonly IShardingCoreOptions _shardingCoreOptions; private readonly IEnumerable<IShardingDbContextCreatorConfig> _shardingDbContextCreatorConfigs;
private readonly IDbContextCreateFilterManager _dbContextCreateFilterManager;
private readonly IDbContextOptionsProvider _dbContextOptionsProvider;
public ShardingDbContextFactory(IShardingCoreOptions shardingCoreOptions, IDbContextCreateFilterManager dbContextCreateFilterManager,IDbContextOptionsProvider dbContextOptionsProvider) public ShardingDbContextFactory(IEnumerable<IShardingDbContextCreatorConfig> shardingDbContextCreatorConfigs)
{ {
_shardingCoreOptions = shardingCoreOptions; _shardingDbContextCreatorConfigs = shardingDbContextCreatorConfigs;
_dbContextCreateFilterManager = dbContextCreateFilterManager;
_dbContextOptionsProvider = dbContextOptionsProvider;
} }
public DbContext Create(ShardingDbContextOptions shardingDbContextOptions) public DbContext Create(Type shardingDbContextType, ShardingDbContextOptions shardingDbContextOptions)
{ {
if (!shardingDbContextType.IsShardingDbContext())
throw new ShardingCoreException(
$"{shardingDbContextType.FullName} must impl {nameof(IShardingDbContext)}");
var shardingDbContextCreatorConfig = _shardingDbContextCreatorConfigs.FirstOrDefault(o=>o.ShardingDbContextType==shardingDbContextType);
if (shardingDbContextCreatorConfig == null)
{
throw new ShardingCoreException(
$"{shardingDbContextType.FullName} cant found DefaultShardingDbContextCreatorConfig<{shardingDbContextType.Name}> should use {nameof(DIExtension.AddShardingDbContext)}");
}
var tail=shardingDbContextOptions.Tail; var tail=shardingDbContextOptions.Tail;
var shardingConfigEntry = _shardingCoreOptions.GetShardingConfig();
var dbContext = shardingConfigEntry.Creator(shardingDbContextOptions); var dbContext = shardingDbContextCreatorConfig.Creator(shardingDbContextOptions);
if (!string.IsNullOrWhiteSpace(tail) && dbContext is IShardingTableDbContext shardingTableDbContext) if (!string.IsNullOrWhiteSpace(tail) && dbContext is IShardingTableDbContext shardingTableDbContext)
{ {
shardingTableDbContext.SetShardingTableDbContextTail(tail); shardingTableDbContext.SetShardingTableDbContextTail(tail);
} }
var filters = _dbContextCreateFilterManager.GetFilters();
if (filters.Any())
{
foreach (var dbContextCreateFilter in filters)
{
dbContextCreateFilter.CreateAfter(dbContext);
}
}
var dbContextModel = dbContext.Model; var dbContextModel = dbContext.Model;
return dbContext; return dbContext;
} }
//public DbContext Create(DbConnection dbConnection,string tail) public DbContext Create<TShardingDbContext>(ShardingDbContextOptions shardingDbContextOptions) where TShardingDbContext : DbContext, IShardingDbContext
//{ {
// var shardingDbContextOptions = return Create(typeof(TShardingDbContext), shardingDbContextOptions);
// new ShardingDbContextOptions(_dbContextOptionsProvider.GetDbContextOptions(dbConnection), tail); }
// return Create(shardingDbContextOptions);
//}
} }
} }

View File

@ -1,26 +0,0 @@
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
namespace ShardingCore.DbContexts.Transactions
{
/*
* @Author: xjm
* @Description:
* @Date: Saturday, 14 August 2021 04:19:53
* @Email: 326308290@qq.com
*/
public interface IShardingTransaction:IDisposable
{
bool IsOpened { get; }
bool IsUsed { get; }
void Use(DbContext dbContext);
void Open();
void Rollback();
Task RollbackAsync();
void Commit();
Task CommitAsync();
IDbContextTransaction GetDbContextTransaction();
}
}

View File

@ -1,102 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Exceptions;
namespace ShardingCore.DbContexts.Transactions
{
/*
* @Author: xjm
* @Description:
* @Date: Saturday, 14 August 2021 04:20:53
* @Email: 326308290@qq.com
*/
public class ShardingTransaction: IShardingTransaction
{
private IDbContextTransaction _dbTransaction;
private bool _isOpened;
public bool IsOpened => _isOpened;
public bool IsUsed => _dbTransaction != null;
private readonly ISet<DbContext> _dbContextUseTransactions = new HashSet<DbContext>();
public void Use(DbContext dbContext)
{
if (!_isOpened)
throw new ShardingTransactionException($"{nameof(ShardingTransaction)} is not open");
if (!_dbContextUseTransactions.Contains(dbContext))
{
if (!IsUsed)
_dbTransaction = dbContext.Database.BeginTransaction();
else
dbContext.Database.UseTransaction(_dbTransaction.GetDbTransaction());
_dbContextUseTransactions.Add(dbContext);
}
}
public void Open()
{
_isOpened = true;
}
private void Close()
{
_isOpened = false;
_dbContextUseTransactions.Clear();
}
public void Rollback()
{
_dbTransaction?.Rollback();
}
#if EFCORE2
public Task RollbackAsync()
{
_dbTransaction?.Rollback();
return Task.CompletedTask;
}
#endif
#if !EFCORE2
public async Task RollbackAsync()
{
if (_dbTransaction != null)
await _dbTransaction.RollbackAsync();
}
#endif
public void Commit()
{
_dbTransaction?.Commit();
}
#if EFCORE2
public Task CommitAsync()
{
_dbTransaction?.Commit();
return Task.CompletedTask;
}
#endif
#if !EFCORE2
public async Task CommitAsync()
{
if (_dbTransaction != null)
await _dbTransaction.CommitAsync();
}
#endif
public IDbContextTransaction GetDbContextTransaction()
{
return _dbTransaction;
}
public void Dispose()
{
Close();
_dbTransaction?.Dispose();
_dbTransaction = null;
}
}
}

View File

@ -1,23 +0,0 @@
using System;
using System.Data.Common;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts.VirtualDbContexts
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 24 December 2020 10:32:07
* @Email: 326308290@qq.com
*/
public interface IDbContextOptionsProvider
{
/// <summary>
/// 创建数据库链接配置
/// </summary>
/// <param name="dbConnection"></param>
/// <returns></returns>
DbContextOptions GetDbContextOptions(DbConnection dbConnection);
}
}

View File

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.Helpers;
using ShardingCore.Sharding.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.DbContexts.ShardingDbContexts;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/5 17:30:10
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class DefaultShardingDbContextCreatorConfig<TShardingDbContext,TActualDbContext> : IShardingDbContextCreatorConfig
where TShardingDbContext : DbContext, IShardingDbContext
where TActualDbContext : DbContext, IShardingTableDbContext
{
private readonly Func<ShardingDbContextOptions, DbContext> _creator;
public DefaultShardingDbContextCreatorConfig(Type actualDbContextType)
{
ActualDbContextType = actualDbContextType;
_creator = ShardingCoreHelper.CreateActivator<TActualDbContext>();
}
public Type ShardingDbContextType => typeof(TShardingDbContext);
public Type ActualDbContextType { get; }
public DbContext Creator(ShardingDbContextOptions shardingDbContextOptions)
{
return _creator(shardingDbContextOptions);
}
}
}

View File

@ -20,8 +20,9 @@ namespace ShardingCore.EFCores
* @Ver: 1.0 * @Ver: 1.0
* @Email: 326308290@qq.com * @Email: 326308290@qq.com
*/ */
public class ShardingModelCustomizer: ModelCustomizer public class ShardingModelCustomizer<TShardingDbContext>: ModelCustomizer where TShardingDbContext:DbContext,IShardingDbContext
{ {
private Type _shardingDbContextType => typeof(TShardingDbContext);
public ShardingModelCustomizer(ModelCustomizerDependencies dependencies) : base(dependencies) public ShardingModelCustomizer(ModelCustomizerDependencies dependencies) : base(dependencies)
{ {
} }
@ -36,7 +37,7 @@ namespace ShardingCore.EFCores
if (!string.IsNullOrWhiteSpace(tail)) if (!string.IsNullOrWhiteSpace(tail))
{ {
var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>(); var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>();
var typeMap = virtualTableManager.GetAllVirtualTables().Where(o => o.GetTaleAllTails().Contains(tail)).Select(o => o.EntityType).ToHashSet(); var typeMap = virtualTableManager.GetAllVirtualTables(_shardingDbContextType).Where(o => o.GetTaleAllTails().Contains(tail)).Select(o => o.EntityType).ToHashSet();
//设置分表 //设置分表
var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o => o.ClrType.IsShardingTable() && typeMap.Contains(o.ClrType)); var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o => o.ClrType.IsShardingTable() && typeMap.Contains(o.ClrType));

View File

@ -21,6 +21,32 @@ namespace ShardingCore.Extensions
*/ */
public static class CommonExtension public static class CommonExtension
{ {
/// <summary>
/// IShardingDbContext
/// </summary>
/// <param name="dbContext"></param>
/// <returns></returns>
public static bool IsShardingDbContext(this DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException(nameof(dbContext));
return dbContext is IShardingDbContext;
}
/// <summary>
/// IShardingDbContext
/// </summary>
/// <param name="dbContextType"></param>
/// <returns></returns>
public static bool IsShardingDbContext(this Type dbContextType)
{
if (dbContextType == null)
throw new ArgumentNullException(nameof(dbContextType));
if (!typeof(DbContext).IsAssignableFrom(dbContextType))
return false;
return typeof(IShardingDbContext).IsAssignableFrom(dbContextType);
}
/// <summary> /// <summary>
/// IShardingTableDbContext /// IShardingTableDbContext
/// </summary> /// </summary>
@ -41,6 +67,8 @@ namespace ShardingCore.Extensions
{ {
if (dbContextType == null) if (dbContextType == null)
throw new ArgumentNullException(nameof(dbContextType)); throw new ArgumentNullException(nameof(dbContextType));
if (!typeof(DbContext).IsAssignableFrom(dbContextType))
return false;
return typeof(IShardingTableDbContext).IsAssignableFrom(dbContextType); return typeof(IShardingTableDbContext).IsAssignableFrom(dbContextType);
} }
/// <summary> /// <summary>
@ -64,7 +92,7 @@ namespace ShardingCore.Extensions
{ {
if (entity == null) if (entity == null)
throw new ArgumentNullException(nameof(entity)); throw new ArgumentNullException(nameof(entity));
return typeof(IShardingTable).IsAssignableFrom(entity.GetType()); return entity is IShardingTable;
} }
// /// <summary> // /// <summary>
// /// 虚拟表转换成对应的db配置 // /// 虚拟表转换成对应的db配置
@ -73,7 +101,7 @@ namespace ShardingCore.Extensions
// /// <returns></returns> // /// <returns></returns>
// public static List<VirtualTableDbContextConfig> GetVirtualTableDbContextConfigs(this List<IVirtualTable> virtualTables) // public static List<VirtualTableDbContextConfig> GetVirtualTableDbContextConfigs(this List<IVirtualTable> virtualTables)
// { // {
// return virtualTables.Select(o => new VirtualTableDbContextConfig(o.EntityType, o.GetOriginalTableName(), o.ShardingConfig.TailPrefix)).ToList(); // return virtualTables.Select(o => new VirtualTableDbContextConfig(o.EntityType, o.GetOriginalTableName(), o.ShardingConfigOption.TailPrefix)).ToList();
// } // }
/// <summary> /// <summary>
/// 是否是集合contains方法 /// 是否是集合contains方法

View File

@ -26,9 +26,7 @@ namespace ShardingCore.Extensions
/// <returns></returns> /// <returns></returns>
public static string GetShardingTableDbContextTail(this IShardingTableDbContext dbContext) public static string GetShardingTableDbContextTail(this IShardingTableDbContext dbContext)
{ {
if (string.IsNullOrWhiteSpace(dbContext.ModelChangeKey)) return dbContext.ModelChangeKey?.Replace(ShardingTableDbContextFormat, string.Empty)??string.Empty;
throw new ShardingCoreException($"cant found ModelChangeKey in {dbContext.GetType().FullName}");
return dbContext.ModelChangeKey.Replace(ShardingTableDbContextFormat, string.Empty);
} }
/// <summary> /// <summary>

View File

@ -6,23 +6,26 @@ using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.ShardingDbContexts; using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.Exceptions; using ShardingCore.Exceptions;
using ShardingCore.Extensions; using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Helpers namespace ShardingCore.Helpers
{ {
/* /*
* @Author: xjm * @Author: xjm
* @Description: * @Description:
* @Date: Friday, 22 January 2021 13:32:08 * @Date: Friday, 22 January 2021 13:32:08
* @Email: 326308290@qq.com * @Email: 326308290@qq.com
*/ */
public class ShardingCoreHelper public class ShardingCoreHelper
{ {
private ShardingCoreHelper(){} private ShardingCoreHelper() { }
public static int GetStringHashCode(string value) public static int GetStringHashCode(string value)
{ {
int h = 0; // 默认值是0 int h = 0; // 默认值是0
if (value.Length > 0) { if (value.Length > 0)
for (int i = 0; i < value.Length; i++) { {
for (int i = 0; i < value.Length; i++)
{
h = 31 * h + value[i]; // val[0]*31^(n-1) + val[1]*31^(n-2) + ... + val[n-1] h = 31 * h + value[i]; // val[0]*31^(n-1) + val[1]*31^(n-2) + ... + val[n-1]
} }
} }
@ -36,7 +39,7 @@ namespace ShardingCore.Helpers
} }
public static long ConvertDateTimeToLong(DateTime time) public static long ConvertDateTimeToLong(DateTime time)
{ {
return (long) (time.AddHours(-8) - UtcStartTime).TotalMilliseconds; return (long)(time.AddHours(-8) - UtcStartTime).TotalMilliseconds;
} }
/// <summary> /// <summary>
@ -61,7 +64,7 @@ namespace ShardingCore.Helpers
public static DateTime GetCurrentMonday(DateTime time) public static DateTime GetCurrentMonday(DateTime time)
{ {
DateTime dateTime1 = new DateTime(time.Year, time.Month, time.Day); DateTime dateTime1 = new DateTime(time.Year, time.Month, time.Day);
int num = (int) (time.DayOfWeek - 1); int num = (int)(time.DayOfWeek - 1);
if (num == -1) if (num == -1)
num = 6; num = 6;
return dateTime1.AddDays(-num); return dateTime1.AddDays(-num);
@ -88,7 +91,7 @@ namespace ShardingCore.Helpers
} }
var paramType = declaredConstructors[0].GetParameters()[0].ParameterType; var paramType = declaredConstructors[0].GetParameters()[0].ParameterType;
if (paramType != typeof(ShardingDbContextOptions) && paramType != typeof(DbContextOptions) && paramType!= typeof(DbContextOptions<TContext>)) if (paramType != typeof(ShardingDbContextOptions) && paramType != typeof(DbContextOptions) && paramType != typeof(DbContextOptions<TContext>))
{ {
throw new ArgumentException($"dbcontext : {contextType} declared constructor parameters should use {typeof(ShardingDbContextOptions)} or {typeof(DbContextOptions)} or {typeof(DbContextOptions<TContext>)} "); throw new ArgumentException($"dbcontext : {contextType} declared constructor parameters should use {typeof(ShardingDbContextOptions)} or {typeof(DbContextOptions)} or {typeof(DbContextOptions<TContext>)} ");
} }
@ -103,8 +106,7 @@ namespace ShardingCore.Helpers
//} //}
} }
public static Func<ShardingDbContextOptions, DbContext> CreateActivator<TContext>() where TContext : DbContext, IShardingTableDbContext
public static Func<ShardingDbContextOptions, DbContext> CreateActivator<TContext>() where TContext : DbContext
{ {
var constructors var constructors
= typeof(TContext).GetTypeInfo().DeclaredConstructors = typeof(TContext).GetTypeInfo().DeclaredConstructors
@ -118,7 +120,7 @@ namespace ShardingCore.Helpers
if (parameterType == typeof(ShardingDbContextOptions)) if (parameterType == typeof(ShardingDbContextOptions))
{ {
return CreateShardingDbContextOptionsActivator<TContext>(constructors[0],parameterType); return CreateShardingDbContextOptionsActivator<TContext>(constructors[0], parameterType);
} }
else if (typeof(DbContextOptions).IsAssignableFrom(parameterType)) else if (typeof(DbContextOptions).IsAssignableFrom(parameterType))
{ {
@ -147,7 +149,7 @@ namespace ShardingCore.Helpers
/// <param name="constructor"></param> /// <param name="constructor"></param>
/// <param name="paramType"></param> /// <param name="paramType"></param>
/// <returns></returns> /// <returns></returns>
private static Func<ShardingDbContextOptions, DbContext> CreateShardingDbContextOptionsActivator<TContext>(ConstructorInfo constructor,Type paramType) where TContext : DbContext private static Func<ShardingDbContextOptions, DbContext> CreateShardingDbContextOptionsActivator<TContext>(ConstructorInfo constructor, Type paramType) where TContext : DbContext, IShardingTableDbContext
{ {
var po = Expression.Parameter(paramType, "o"); var po = Expression.Parameter(paramType, "o");
var newExpression = Expression.New(constructor, po); var newExpression = Expression.New(constructor, po);
@ -166,7 +168,7 @@ namespace ShardingCore.Helpers
/// <param name="constructor"></param> /// <param name="constructor"></param>
/// <param name="paramType"></param> /// <param name="paramType"></param>
/// <returns></returns> /// <returns></returns>
private static Func<ShardingDbContextOptions, DbContext> CreateDbContextOptionsGenericActivator<TContext>(ConstructorInfo constructor,Type paramType) where TContext : DbContext private static Func<ShardingDbContextOptions, DbContext> CreateDbContextOptionsGenericActivator<TContext>(ConstructorInfo constructor, Type paramType) where TContext : DbContext, IShardingTableDbContext
{ {
var parameterExpression = Expression.Parameter(typeof(ShardingDbContextOptions), "o"); var parameterExpression = Expression.Parameter(typeof(ShardingDbContextOptions), "o");
//o.DbContextOptions //o.DbContextOptions

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Threading.Tasks;
namespace ShardingCore namespace ShardingCore
{ {

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/20 6:56:49
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingConfigOption
{
Type ShardingDbContextType { get;}
Type ActualDbContextType { get;}
void AddShardingTableRoute<TRoute>() where TRoute : IVirtualTableRoute;
Type GetVirtualRouteType(Type entityType);
/// <summary>
/// 如果数据库不存在就创建并且创建表除了分表的
/// </summary>
public bool EnsureCreatedWithOutShardingTable { get; set; }
/// <summary>
/// 是否需要在启动时创建分表
/// </summary>
public bool? CreateShardingTableOnStart { get; set; }
/// <summary>
/// 忽略建表时的错误
/// </summary>
public bool? IgnoreCreateTableError { get; set; }
}
}

View File

@ -1,50 +0,0 @@
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.Abstractions;
using System;
using System.Collections.Generic;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/4 13:11:16
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingCoreOptions
{
void UseShardingDbContext<T>(
Action<ShardingDbConfigOptions> func) where T : DbContext, IShardingTableDbContext;
ShardingConfigEntry GetShardingConfig();
ISet<Type> GetVirtualRoutes();
Type GetVirtualRoute(Type entityType);
/// <summary>
/// 如果数据库不存在就创建并且创建表除了分表的
/// </summary>
bool EnsureCreatedWithOutShardingTable { get; set; }
/// <summary>
/// 是否需要在启动时创建分表
/// </summary>
bool? CreateShardingTableOnStart { get; set; }
/// <summary>
/// 添加filter过滤器
/// </summary>
/// <typeparam name="TFilter"></typeparam>
public void AddDbContextCreateFilter<TFilter>() where TFilter : class, IDbContextCreateFilter;
public List<Type> GetFilters();
bool? IgnoreCreateTableError { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.Abstractions;
using System;
using System.Collections.Generic;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/4 13:11:16
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingDbContextCreatorConfig
{
Type ShardingDbContextType { get; }
Type ActualDbContextType { get; }
DbContext Creator(ShardingDbContextOptions shardingDbContextOptions);
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/20 11:34:55
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingDbContextOptionsBuilderConfig
{
Type ShardingDbContextType { get; }
DbContextOptionsBuilder UseDbContextOptionsBuilder(DbConnection dbConnection, DbContextOptionsBuilder dbContextOptionsBuilder);
}
}

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -30,13 +31,13 @@ namespace ShardingCore.Sharding
/// 分表分库的dbcontext /// 分表分库的dbcontext
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
public abstract class AbstractShardingDbContext<T> : DbContext, IShardingDbContext where T : DbContext, IShardingTableDbContext public abstract class AbstractShardingDbContext<T> : DbContext, IShardingTableDbContext<T> where T : DbContext, IShardingTableDbContext
{ {
private readonly string EMPTY_SHARDING_TAIL_ID = Guid.NewGuid().ToString("n"); private readonly string EMPTY_SHARDING_TAIL_ID = Guid.NewGuid().ToString("n");
private readonly ConcurrentDictionary<string, DbContext> _dbContextCaches = new ConcurrentDictionary<string, DbContext>(); private readonly ConcurrentDictionary<string, DbContext> _dbContextCaches = new ConcurrentDictionary<string, DbContext>();
private readonly IVirtualTableManager _virtualTableManager; private readonly IVirtualTableManager _virtualTableManager;
private readonly IShardingDbContextFactory _shardingDbContextFactory; private readonly IShardingDbContextFactory _shardingDbContextFactory;
private readonly ShardingConfig<T> _shardingConfig; private readonly IShardingDbContextOptionsBuilderConfig _shardingDbContextOptionsBuilderConfig;
private DbContextOptions<T> _dbContextOptions; private DbContextOptions<T> _dbContextOptions;
private readonly object CREATELOCK = new object(); private readonly object CREATELOCK = new object();
@ -45,10 +46,13 @@ namespace ShardingCore.Sharding
{ {
_shardingDbContextFactory = ShardingContainer.GetService<IShardingDbContextFactory>(); _shardingDbContextFactory = ShardingContainer.GetService<IShardingDbContextFactory>();
_virtualTableManager = ShardingContainer.GetService<IVirtualTableManager>(); _virtualTableManager = ShardingContainer.GetService<IVirtualTableManager>();
_shardingConfig = ShardingContainer.GetService<ShardingConfig<T>>(); _shardingDbContextOptionsBuilderConfig = ShardingContainer
.GetService<IEnumerable<IShardingDbContextOptionsBuilderConfig>>()
.FirstOrDefault(o => o.ShardingDbContextType == ShardingDbContextType);
} }
public abstract Type ShardingDbContextType { get; }
public Type ActualDbContextType => typeof(T); public Type ActualDbContextType => typeof(T);
@ -64,8 +68,8 @@ namespace ShardingCore.Sharding
{ {
var dbContextOptionBuilder = CreateDbContextOptionBuilder(); var dbContextOptionBuilder = CreateDbContextOptionBuilder();
var dbConnection = Database.GetDbConnection(); var dbConnection = Database.GetDbConnection();
dbConnection.Open(); _shardingDbContextOptionsBuilderConfig.UseDbContextOptionsBuilder(dbConnection, dbContextOptionBuilder);
return _shardingConfig.ShardingDbContextOptionsCreator(dbConnection, dbContextOptionBuilder); return dbContextOptionBuilder.Options;
} }
private ShardingDbContextOptions CreateSameShardingDbContextOptions(string tail) private ShardingDbContextOptions CreateSameShardingDbContextOptions(string tail)
@ -87,7 +91,7 @@ namespace ShardingCore.Sharding
{ {
if (!_dbContextCaches.TryGetValue(tail, out var dbContext)) if (!_dbContextCaches.TryGetValue(tail, out var dbContext))
{ {
dbContext = _shardingDbContextFactory.Create(CreateSameShardingDbContextOptions(tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail)); dbContext = _shardingDbContextFactory.Create(ShardingDbContextType,CreateSameShardingDbContextOptions(tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail));
_dbContextCaches.TryAdd(tail, dbContext); _dbContextCaches.TryAdd(tail, dbContext);
} }
@ -101,13 +105,25 @@ namespace ShardingCore.Sharding
var tail = EMPTY_SHARDING_TAIL_ID; var tail = EMPTY_SHARDING_TAIL_ID;
if (entity.IsShardingTable()) if (entity.IsShardingTable())
{ {
var physicTable = _virtualTableManager.GetVirtualTable(entity.GetType()).RouteTo(new TableRouteConfig(null, entity as IShardingTable, null))[0]; var physicTable = _virtualTableManager.GetVirtualTable(ShardingDbContextType,entity.GetType()).RouteTo(new TableRouteConfig(null, entity as IShardingTable, null))[0];
tail = physicTable.Tail; tail = physicTable.Tail;
} }
return GetDbContext(true, tail); return GetDbContext(true, tail);
} }
public bool TryOpen()
{
var dbConnection = Database.GetDbConnection();
if (dbConnection.State != ConnectionState.Open)
{
dbConnection.Open();
return true;
}
return false;
}
public override EntityEntry Add(object entity) public override EntityEntry Add(object entity)
{ {
return CreateGenericDbContext(entity).Add(entity); return CreateGenericDbContext(entity).Add(entity);
@ -380,12 +396,14 @@ namespace ShardingCore.Sharding
finally finally
{ {
if (!isBeginTransaction) if (!isBeginTransaction)
Database.CurrentTransaction?.Dispose();
foreach (var dbContextCache in _dbContextCaches)
{ {
dbContextCache.Value.Database.UseTransaction(null); Database.CurrentTransaction?.Dispose();
foreach (var dbContextCache in _dbContextCaches)
{
dbContextCache.Value.Database.UseTransaction(null);
}
} }
} }
return i; return i;
} }
@ -415,11 +433,12 @@ namespace ShardingCore.Sharding
finally finally
{ {
if (!isBeginTransaction) if (!isBeginTransaction)
Database.CurrentTransaction?.Dispose();
foreach (var dbContextCache in _dbContextCaches)
{ {
dbContextCache.Value.Database.UseTransaction(null); Database.CurrentTransaction?.Dispose();
foreach (var dbContextCache in _dbContextCaches)
{
dbContextCache.Value.Database.UseTransaction(null);
}
} }
} }
return i; return i;
@ -451,12 +470,14 @@ namespace ShardingCore.Sharding
{ {
if (!isBeginTransaction) { } if (!isBeginTransaction) { }
if (Database.CurrentTransaction != null) if (Database.CurrentTransaction != null)
await Database.CurrentTransaction.DisposeAsync();
foreach (var dbContextCache in _dbContextCaches)
{ {
await dbContextCache.Value.Database.UseTransactionAsync(null, cancellationToken: cancellationToken); await Database.CurrentTransaction.DisposeAsync();
foreach (var dbContextCache in _dbContextCaches)
{
await dbContextCache.Value.Database.UseTransactionAsync(null, cancellationToken: cancellationToken);
}
} }
} }
return i; return i;
} }
@ -487,12 +508,15 @@ namespace ShardingCore.Sharding
{ {
if (!isBeginTransaction) if (!isBeginTransaction)
if (Database.CurrentTransaction != null) if (Database.CurrentTransaction != null)
{
await Database.CurrentTransaction.DisposeAsync(); await Database.CurrentTransaction.DisposeAsync();
foreach (var dbContextCache in _dbContextCaches) foreach (var dbContextCache in _dbContextCaches)
{ {
await dbContextCache.Value.Database.UseTransactionAsync(null, cancellationToken: cancellationToken); await dbContextCache.Value.Database.UseTransactionAsync(null, cancellationToken: cancellationToken);
} }
}
} }
return i; return i;
} }

View File

@ -13,14 +13,15 @@ namespace ShardingCore.Sharding.Abstractions
*/ */
public interface IShardingDbContext public interface IShardingDbContext
{ {
Type ShardingDbContextType { get; }
/// <summary> /// <summary>
/// 真实的DbContext 类型 /// 真实的DbContext 类型
/// </summary> /// </summary>
Type ActualDbContextType { get;} Type ActualDbContextType { get;}
/// <summary> /// <summary>
/// 创建DbContext /// 创建DbContext
/// </summary> /// </summary>
/// <param name="track"></param> /// <param name="track">true表示创建的dbcontext挂在当前的shardingdbcontext下无需管理生命周期false需要手动释放true not care dbcontext life, false need call dispose()</param>
/// <param name="tail"></param> /// <param name="tail"></param>
/// <returns></returns> /// <returns></returns>
DbContext GetDbContext(bool track,string tail); DbContext GetDbContext(bool track,string tail);
@ -33,5 +34,12 @@ namespace ShardingCore.Sharding.Abstractions
DbContext CreateGenericDbContext<T>(T entity) where T : class; DbContext CreateGenericDbContext<T>(T entity) where T : class;
bool TryOpen();
}
public interface IShardingTableDbContext<T> : IShardingDbContext where T : DbContext, IShardingTableDbContext
{
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.Sharding.Abstractions namespace ShardingCore.Sharding.Abstractions
{ {

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Sharding
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/19 20:57:52
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingDbContextOptionsBuilderConfig<TShardingDbContext> : IShardingDbContextOptionsBuilderConfig where TShardingDbContext : DbContext, IShardingDbContext
{
public ShardingDbContextOptionsBuilderConfig(Action<DbConnection, DbContextOptionsBuilder> shardingDbContextOptionsCreator)
{
ShardingDbContextOptionsCreator = shardingDbContextOptionsCreator;
}
public Action<DbConnection, DbContextOptionsBuilder> ShardingDbContextOptionsCreator { get; }
public Type ShardingDbContextType => typeof(TShardingDbContext);
public DbContextOptionsBuilder UseDbContextOptionsBuilder(DbConnection dbConnection, DbContextOptionsBuilder dbContextOptionsBuilder)
{
ShardingDbContextOptionsCreator(dbConnection, dbContextOptionsBuilder);
dbContextOptionsBuilder.UseInnerDbContextSharding<TShardingDbContext>();
return dbContextOptionsBuilder;
}
}
}

View File

@ -1,27 +1,24 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.Internal.StreamMerge.ReWrite; using ShardingCore.Core.Internal.StreamMerge.ReWrite;
using ShardingCore.Core.Internal.Visitors; using ShardingCore.Core.Internal.Visitors;
using ShardingCore.Core.Internal.Visitors.GroupBys; using ShardingCore.Core.Internal.Visitors.GroupBys;
using ShardingCore.Core.Internal.Visitors.Selects; using ShardingCore.Core.Internal.Visitors.Selects;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.DbContexts;
using ShardingCore.Sharding.Abstractions; using ShardingCore.Sharding.Abstractions;
using System.Collections.Generic;
using System.Linq;
namespace ShardingCore.Sharding namespace ShardingCore.Sharding
{ {
/* /*
* @Author: xjm * @Author: xjm
* @Description: * @Description:
* @Date: Monday, 25 January 2021 11:38:27 * @Date: Monday, 25 January 2021 11:38:27
* @Email: 326308290@qq.com * @Email: 326308290@qq.com
*/ */
public class StreamMergeContext<T> public class StreamMergeContext<T>
{ {
private readonly IShardingParallelDbContextFactory _shardingParallelDbContextFactory;
//private readonly IShardingScopeFactory _shardingScopeFactory; //private readonly IShardingScopeFactory _shardingScopeFactory;
private readonly IQueryable<T> _source; private readonly IQueryable<T> _source;
private readonly IShardingDbContext _shardingDbContext; private readonly IShardingDbContext _shardingDbContext;
@ -37,10 +34,8 @@ namespace ShardingCore.Sharding
public SelectContext SelectContext { get;} public SelectContext SelectContext { get;}
public GroupByContext GroupByContext { get; } public GroupByContext GroupByContext { get; }
public StreamMergeContext(IQueryable<T> source,IShardingDbContext shardingDbContext,IRoutingRuleEngineFactory tableRoutingRuleEngineFactory, public StreamMergeContext(IQueryable<T> source,IShardingDbContext shardingDbContext,IRoutingRuleEngineFactory tableRoutingRuleEngineFactory)
IShardingParallelDbContextFactory shardingParallelDbContextFactory,IShardingScopeFactory shardingScopeFactory)
{ {
_shardingParallelDbContextFactory = shardingParallelDbContextFactory;
//_shardingScopeFactory = shardingScopeFactory; //_shardingScopeFactory = shardingScopeFactory;
_source = source; _source = source;
_shardingDbContext = shardingDbContext; _shardingDbContext = shardingDbContext;
@ -69,13 +64,17 @@ namespace ShardingCore.Sharding
// _reWriteSource = reWriteResult.ReWriteQueryable; // _reWriteSource = reWriteResult.ReWriteQueryable;
//} //}
public bool TryOpen()
{
return _shardingDbContext.TryOpen();
}
public DbContext CreateDbContext(string tail) public DbContext CreateDbContext(string tail)
{ {
return _shardingDbContext.GetDbContext(true,tail); return _shardingDbContext.GetDbContext(true,tail);
} }
public IEnumerable<RouteResult> GetRouteResults() public IEnumerable<RouteResult> GetRouteResults()
{ {
return _tableRoutingRuleEngineFactory.Route(_source); return _tableRoutingRuleEngineFactory.Route(_shardingDbContext.GetType(),_source);
} }
//public ShardingScope CreateScope() //public ShardingScope CreateScope()

View File

@ -1,8 +1,6 @@
using System.Linq;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.DbContexts;
using ShardingCore.Sharding.Abstractions; using ShardingCore.Sharding.Abstractions;
using System.Linq;
namespace ShardingCore.Sharding namespace ShardingCore.Sharding
{ {
@ -14,21 +12,16 @@ namespace ShardingCore.Sharding
*/ */
public class StreamMergeContextFactory:IStreamMergeContextFactory public class StreamMergeContextFactory:IStreamMergeContextFactory
{ {
private readonly IShardingParallelDbContextFactory _shardingParallelDbContextFactory;
private readonly IShardingScopeFactory _shardingScopeFactory;
private readonly IRoutingRuleEngineFactory _routingRuleEngineFactory; private readonly IRoutingRuleEngineFactory _routingRuleEngineFactory;
public StreamMergeContextFactory(IShardingParallelDbContextFactory shardingParallelDbContextFactory, public StreamMergeContextFactory(
IShardingScopeFactory shardingScopeFactory,
IRoutingRuleEngineFactory routingRuleEngineFactory) IRoutingRuleEngineFactory routingRuleEngineFactory)
{ {
_shardingParallelDbContextFactory = shardingParallelDbContextFactory;
_shardingScopeFactory = shardingScopeFactory;
_routingRuleEngineFactory = routingRuleEngineFactory; _routingRuleEngineFactory = routingRuleEngineFactory;
} }
public StreamMergeContext<T> Create<T>(IQueryable<T> queryable,IShardingDbContext shardingDbContext) public StreamMergeContext<T> Create<T>(IQueryable<T> queryable,IShardingDbContext shardingDbContext)
{ {
return new StreamMergeContext<T>(queryable,shardingDbContext, _routingRuleEngineFactory, _shardingParallelDbContextFactory, _shardingScopeFactory); return new StreamMergeContext<T>(queryable,shardingDbContext, _routingRuleEngineFactory);
} }
} }
} }

View File

@ -46,6 +46,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions
} }
_mergeContext = ShardingContainer.GetService<IStreamMergeContextFactory>().Create(_queryable, shardingDbContext); _mergeContext = ShardingContainer.GetService<IStreamMergeContextFactory>().Create(_queryable, shardingDbContext);
_mergeContext.TryOpen();
} }
protected abstract IQueryable<TEntity> ProcessSecondExpression(IQueryable<TEntity> queryable, Expression secondExpression); protected abstract IQueryable<TEntity> ProcessSecondExpression(IQueryable<TEntity> queryable, Expression secondExpression);

View File

@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -12,6 +13,7 @@ using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts; using ShardingCore.DbContexts;
using ShardingCore.DbContexts.Abstractions; using ShardingCore.DbContexts.Abstractions;
using ShardingCore.Extensions; using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.TableCreator; using ShardingCore.TableCreator;
namespace ShardingCore namespace ShardingCore
@ -25,66 +27,58 @@ namespace ShardingCore
public class ShardingBootstrapper : IShardingBootstrapper public class ShardingBootstrapper : IShardingBootstrapper
{ {
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly IShardingCoreOptions _shardingCoreOptions; private readonly IEnumerable<IShardingConfigOption> _shardingConfigOptions;
private readonly IVirtualTableManager _virtualTableManager; private readonly IVirtualTableManager _virtualTableManager;
private readonly IShardingTableCreator _tableCreator; private readonly IShardingTableCreator _tableCreator;
private readonly ILogger<ShardingBootstrapper> _logger; private readonly ILogger<ShardingBootstrapper> _logger;
private readonly IShardingDbContextFactory _shardingDbContextFactory; private readonly IShardingDbContextFactory _shardingDbContextFactory;
private readonly IDbContextCreateFilterManager _dbContextCreateFilterManager;
public ShardingBootstrapper(IServiceProvider serviceProvider, IShardingCoreOptions shardingCoreOptions, public ShardingBootstrapper(IServiceProvider serviceProvider, IEnumerable<IShardingConfigOption> shardingConfigOptions,
IVirtualTableManager virtualTableManager IVirtualTableManager virtualTableManager
, IShardingTableCreator tableCreator, ILogger<ShardingBootstrapper> logger, , IShardingTableCreator tableCreator, ILogger<ShardingBootstrapper> logger,
IShardingDbContextFactory shardingDbContextFactory,IDbContextCreateFilterManager dbContextCreateFilterManager) IShardingDbContextFactory shardingDbContextFactory)
{ {
ShardingContainer.SetServices(serviceProvider); ShardingContainer.SetServices(serviceProvider);
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_shardingCoreOptions = shardingCoreOptions; _shardingConfigOptions = shardingConfigOptions;
_virtualTableManager = virtualTableManager; _virtualTableManager = virtualTableManager;
_tableCreator = tableCreator; _tableCreator = tableCreator;
_logger = logger; _logger = logger;
_shardingDbContextFactory = shardingDbContextFactory; _shardingDbContextFactory = shardingDbContextFactory;
_dbContextCreateFilterManager = dbContextCreateFilterManager;
} }
public void Start() public void Start()
{ {
foreach (var filter in _shardingCoreOptions.GetFilters())
{
_dbContextCreateFilterManager.RegisterFilter((IDbContextCreateFilter)Activator.CreateInstance(filter));
}
var shardingConfig= _shardingCoreOptions.GetShardingConfig();
using var scope = _serviceProvider.CreateScope(); using (var scope = _serviceProvider.CreateScope())
using var context =(DbContext)scope.ServiceProvider.GetService(shardingConfig.DbContextType);
#if EFCORE5
shardingConfig.ConnectionString = context.Database.GetConnectionString();
#endif
#if !EFCORE5
shardingConfig.ConnectionString = context.Database.GetDbConnection().ConnectionString;
#endif
EnsureCreated(context);
foreach (var entity in context.Model.GetEntityTypes())
{ {
if (entity.ClrType.IsShardingTable()) foreach (var shardingConfigOption in _shardingConfigOptions)
{ {
var routeType = shardingConfig.DbConfigOptions.GetVirtualRoute(entity.ClrType); using var context =
var virtualRoute = CreateVirtualRoute(routeType); (DbContext) scope.ServiceProvider.GetService(shardingConfigOption.ShardingDbContextType);
var virtualTable = CreateVirtualTable(entity.ClrType, virtualRoute); EnsureCreated(context);
foreach (var entity in context.Model.GetEntityTypes())
{
if (entity.ClrType.IsShardingTable())
{
var routeType = shardingConfigOption.GetVirtualRouteType(entity.ClrType);
var virtualRoute = CreateVirtualRoute(routeType);
var virtualTable = CreateVirtualTable(entity.ClrType, virtualRoute);
//获取ShardingEntity的实际表名 //获取ShardingEntity的实际表名
#if !EFCORE2 #if !EFCORE2
var tableName = context.Model.FindEntityType(virtualTable.EntityType).GetTableName(); var tableName = context.Model.FindEntityType(virtualTable.EntityType).GetTableName();
#endif #endif
#if EFCORE2 #if EFCORE2
var tableName = context.Model.FindEntityType(virtualTable.EntityType).Relational().TableName; var tableName = context.Model.FindEntityType(virtualTable.EntityType).Relational().TableName;
#endif #endif
virtualTable.SetOriginalTableName(tableName); virtualTable.SetOriginalTableName(tableName);
_virtualTableManager.AddVirtualTable(virtualTable); _virtualTableManager.AddVirtualTable(shardingConfigOption.ShardingDbContextType,virtualTable);
CreateDataTable(virtualTable); CreateDataTable(shardingConfigOption.ShardingDbContextType,virtualTable, shardingConfigOption);
}
}
} }
} }
} }
@ -124,50 +118,51 @@ namespace ShardingCore
return (IVirtualTable) o; return (IVirtualTable) o;
} }
private void EnsureCreated(DbContext context) private void EnsureCreated(DbContext context)
{ {
if (_shardingCoreOptions.EnsureCreatedWithOutShardingTable) if (context is IShardingDbContext shardingDbContext)
{ {
var modelCacheSyncObject = context.GetModelCacheSyncObject(); var dbContext = shardingDbContext.GetDbContext(true,string.Empty);
var modelCacheSyncObject = dbContext.GetModelCacheSyncObject();
lock (modelCacheSyncObject) lock (modelCacheSyncObject)
{ {
context.RemoveDbContextRelationModelThatIsShardingTable(); dbContext.RemoveDbContextRelationModelThatIsShardingTable();
context.Database.EnsureCreated(); dbContext.Database.EnsureCreated();
context.RemoveModelCache(); dbContext.RemoveModelCache();
} }
} }
} }
private bool NeedCreateTable(ShardingTableConfig config) private bool NeedCreateTable(ShardingTableConfig config, IShardingConfigOption shardingConfigOption)
{ {
if (config.AutoCreateTable.HasValue) if (config.AutoCreateTable.HasValue)
{ {
return config.AutoCreateTable.Value; return config.AutoCreateTable.Value;
} }
return _shardingCoreOptions.CreateShardingTableOnStart.GetValueOrDefault(); return shardingConfigOption.CreateShardingTableOnStart.GetValueOrDefault();
} }
private void CreateDataTable(IVirtualTable virtualTable) private void CreateDataTable(Type shardingDbContextType,IVirtualTable virtualTable,IShardingConfigOption shardingConfigOption)
{ {
var shardingConfig = virtualTable.ShardingConfig; var shardingConfig = virtualTable.ShardingConfig;
foreach (var tail in virtualTable.GetVirtualRoute().GetAllTails()) foreach (var tail in virtualTable.GetVirtualRoute().GetAllTails())
{ {
if (NeedCreateTable(shardingConfig)) if (NeedCreateTable(shardingConfig, shardingConfigOption))
{ {
try try
{ {
//添加物理表 //添加物理表
virtualTable.AddPhysicTable(new DefaultPhysicTable(virtualTable, tail)); virtualTable.AddPhysicTable(new DefaultPhysicTable(virtualTable, tail));
_tableCreator.CreateTable(virtualTable.EntityType, tail); _tableCreator.CreateTable(shardingDbContextType,virtualTable.EntityType, tail);
} }
catch (Exception) catch (Exception e)
{ {
if (!_shardingCoreOptions.IgnoreCreateTableError.GetValueOrDefault()) if (!shardingConfigOption.IgnoreCreateTableError.GetValueOrDefault())
{ {
_logger.LogWarning( _logger.LogWarning(
$"table :{virtualTable.GetOriginalTableName()}{shardingConfig.TailPrefix}{tail} will created"); $"table :{virtualTable.GetOriginalTableName()}{shardingConfig.TailPrefix}{tail} will created.",e);
} }
} }
} }

View File

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/16 15:18:37
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingConfig<T> where T:DbContext,IShardingTableDbContext
{
public Func<DbConnection, DbContextOptionsBuilder<T>, DbContextOptions<T>> ShardingDbContextOptionsCreator { get; private set; }
public void UseShardingDbContextOptions(Func<DbConnection, DbContextOptionsBuilder<T>, DbContextOptions<T>> shardingDbContextOptions)
{
ShardingDbContextOptionsCreator = shardingDbContextOptions ?? throw new ArgumentNullException(nameof(shardingDbContextOptions));
}
}
}

View File

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.EFCores;
using ShardingCore.Sharding;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/16 15:18:37
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingConfigOption<TShardingDbContext, TActualDbContext> : IShardingConfigOption
where TActualDbContext : DbContext, IShardingTableDbContext
where TShardingDbContext : DbContext, IShardingTableDbContext<TActualDbContext>
{
private readonly Dictionary<Type, Type> _virtualRoutes = new Dictionary<Type, Type>();
public Action<DbConnection, DbContextOptionsBuilder> ShardingDbContextOptionsCreator { get; set; }
public void UseShardingDbContextOptions(Action<DbConnection, DbContextOptionsBuilder> shardingDbContextOptionsCreator)
{
ShardingDbContextOptionsCreator = shardingDbContextOptionsCreator ?? throw new ArgumentNullException(nameof(shardingDbContextOptionsCreator));
}
public Type ShardingDbContextType => typeof(TShardingDbContext);
public Type ActualDbContextType => typeof(TActualDbContext);
/// <summary>
/// 添加分表路由
/// </summary>
/// <typeparam name="TRoute"></typeparam>
public void AddShardingTableRoute<TRoute>() where TRoute : IVirtualTableRoute
{
var routeType = typeof(TRoute);
//获取类型
var genericVirtualRoute = routeType.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IVirtualTableRoute<>)
&& it.GetGenericArguments().Any());
if (genericVirtualRoute == null)
throw new ArgumentException("add sharding route type error not assignable from IVirtualTableRoute<>.");
var shardingEntityType = genericVirtualRoute.GetGenericArguments()[0];
if (shardingEntityType == null)
throw new ArgumentException("add sharding table route type error not assignable from IVirtualTableRoute<>");
if (!_virtualRoutes.ContainsKey(shardingEntityType))
{
_virtualRoutes.Add(shardingEntityType, routeType);
}
}
public Type GetVirtualRouteType(Type entityType)
{
if (!_virtualRoutes.ContainsKey(entityType))
throw new ArgumentException($"{entityType} not found IVirtualTableRoute");
return _virtualRoutes[entityType];
}
/// <summary>
/// 如果数据库不存在就创建并且创建表除了分表的
/// </summary>
public bool EnsureCreatedWithOutShardingTable { get; set; }
/// <summary>
/// 是否需要在启动时创建分表
/// </summary>
public bool? CreateShardingTableOnStart { get; set; }
/// <summary>
/// 忽略建表时的错误
/// </summary>
public bool? IgnoreCreateTableError { get; set; }
}
}

View File

@ -29,5 +29,9 @@ namespace ShardingCore
{ {
return Services.GetService<T>(); return Services.GetService<T>();
} }
public static object GetService(Type serviceType)
{
return Services.GetService(serviceType);
}
} }
} }

View File

@ -1,6 +1,8 @@
using System; using System;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core; using ShardingCore.Core;
using ShardingCore.Exceptions; using ShardingCore.Exceptions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.TableCreator namespace ShardingCore.TableCreator
{ {
@ -20,13 +22,14 @@ namespace ShardingCore.TableCreator
/// </summary> /// </summary>
/// <param name="tail"></param> /// <param name="tail"></param>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
void CreateTable<T>(string tail) where T : class, IShardingTable; void CreateTable<TShardingDbContext,T>(string tail) where T : class, IShardingTable where TShardingDbContext:DbContext,IShardingDbContext;
/// <summary> /// <summary>
/// 创建表 /// 创建表
/// </summary> /// </summary>
/// <param name="shardingDbContextType"></param>
/// <param name="shardingEntityType"></param> /// <param name="shardingEntityType"></param>
/// <param name="tail"></param> /// <param name="tail"></param>
/// <exception cref="ShardingCreateException"></exception> /// <exception cref="ShardingCreateException"></exception>
void CreateTable(Type shardingEntityType,string tail); void CreateTable(Type shardingDbContextType,Type shardingEntityType,string tail);
} }
} }

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -7,10 +9,12 @@ using Microsoft.Extensions.Logging;
using ShardingCore.Core; using ShardingCore.Core;
using ShardingCore.Core.VirtualTables; using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts; using ShardingCore.DbContexts;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.DbContexts.ShardingDbContexts; using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.DbContexts.VirtualDbContexts; using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Exceptions; using ShardingCore.Exceptions;
using ShardingCore.Extensions; using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.TableCreator namespace ShardingCore.TableCreator
{ {
@ -26,50 +30,60 @@ namespace ShardingCore.TableCreator
private readonly IShardingDbContextFactory _shardingDbContextFactory; private readonly IShardingDbContextFactory _shardingDbContextFactory;
private readonly IVirtualTableManager _virtualTableManager; private readonly IVirtualTableManager _virtualTableManager;
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly IShardingCoreOptions _shardingCoreOptions; private readonly IEnumerable<IShardingConfigOption> _shardingConfigOptions;
public ShardingTableCreator(ILogger<ShardingTableCreator> logger, IShardingDbContextFactory shardingDbContextFactory, public ShardingTableCreator(ILogger<ShardingTableCreator> logger, IShardingDbContextFactory shardingDbContextFactory,
IVirtualTableManager virtualTableManager, IServiceProvider serviceProvider,IShardingCoreOptions shardingCoreOptions) IVirtualTableManager virtualTableManager, IServiceProvider serviceProvider, IEnumerable<IShardingConfigOption> shardingConfigOptions)
{ {
_logger = logger; _logger = logger;
_shardingDbContextFactory = shardingDbContextFactory; _shardingDbContextFactory = shardingDbContextFactory;
_virtualTableManager = virtualTableManager; _virtualTableManager = virtualTableManager;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_shardingCoreOptions = shardingCoreOptions; _shardingConfigOptions = shardingConfigOptions;
} }
public void CreateTable<T>(string tail) where T : class, IShardingTable public void CreateTable<TShardingDbContext, T>(string tail) where TShardingDbContext : DbContext, IShardingDbContext where T : class, IShardingTable
{ {
CreateTable(typeof(T), tail); CreateTable(typeof(TShardingDbContext),typeof(T), tail);
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="shardingDbContextType"></param>
/// <param name="shardingEntityType"></param> /// <param name="shardingEntityType"></param>
/// <param name="tail"></param> /// <param name="tail"></param>
/// <exception cref="ShardingCreateException"></exception> /// <exception cref="ShardingCreateException"></exception>
public void CreateTable(Type shardingEntityType, string tail) public void CreateTable(Type shardingDbContextType,Type shardingEntityType, string tail)
{ {
if (!shardingDbContextType.IsShardingDbContext())
throw new ShardingCoreException(
$"{shardingDbContextType.FullName} must impl {nameof(IShardingDbContext)}");
var shardingConfigOptions = _shardingConfigOptions.FirstOrDefault(o => o.ShardingDbContextType == shardingDbContextType);
if (shardingConfigOptions == null)
throw new ShardingCoreException(
"not found sharding config options db context is {shardingDbContextType.FullName}");
using (var serviceScope = _serviceProvider.CreateScope()) using (var serviceScope = _serviceProvider.CreateScope())
{ {
var dbContextOptionsProvider = serviceScope.ServiceProvider.GetService<IDbContextOptionsProvider>(); var virtualTable = _virtualTableManager.GetVirtualTable(shardingDbContextType, shardingEntityType);
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntityType); var dbContext = (DbContext)serviceScope.ServiceProvider.GetService(shardingDbContextType);
var shardingDbContext = (IShardingDbContext)dbContext;
var context = shardingDbContext.GetDbContext(true,tail);
using (var dbContext = _shardingDbContextFactory.Create(new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(null), tail))) var modelCacheSyncObject = context.GetModelCacheSyncObject();
{
var modelCacheSyncObject = dbContext.GetModelCacheSyncObject();
lock (modelCacheSyncObject) lock (modelCacheSyncObject)
{ {
dbContext.RemoveDbContextRelationModelSaveOnlyThatIsNamedType(shardingEntityType); context.RemoveDbContextRelationModelSaveOnlyThatIsNamedType(shardingEntityType);
var databaseCreator = dbContext.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator; var databaseCreator = context.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator;
try try
{ {
databaseCreator.CreateTables(); databaseCreator.CreateTables();
} }
catch (Exception ex) catch (Exception ex)
{ {
if (!_shardingCoreOptions.IgnoreCreateTableError.GetValueOrDefault()) if (!shardingConfigOptions.IgnoreCreateTableError.GetValueOrDefault())
{ {
_logger.LogWarning( _logger.LogWarning(
$"create table error maybe table:[{virtualTable.GetOriginalTableName()}{virtualTable.ShardingConfig.TailPrefix}{tail}]"); $"create table error maybe table:[{virtualTable.GetOriginalTableName()}{virtualTable.ShardingConfig.TailPrefix}{tail}]");
@ -78,11 +92,10 @@ namespace ShardingCore.TableCreator
} }
finally finally
{ {
dbContext.RemoveModelCache(); context.RemoveModelCache();
} }
} }
}
} }
} }
} }

View File

@ -7,6 +7,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.2" /> <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Xunit.DependencyInjection" Version="7.1.0" /> <PackageReference Include="Xunit.DependencyInjection" Version="7.1.0" />
@ -22,5 +23,8 @@
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -28,5 +28,7 @@ namespace ShardingCore.Test50
modelBuilder.ApplyConfiguration(new SysUserModMap()); modelBuilder.ApplyConfiguration(new SysUserModMap());
modelBuilder.ApplyConfiguration(new SysUserSalaryMap()); modelBuilder.ApplyConfiguration(new SysUserSalaryMap());
} }
public override Type ShardingDbContextType => this.GetType();
} }
} }

View File

@ -1,17 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
using ShardingCore.Sharding;
using ShardingCore.SqlServer;
using ShardingCore.Test50.Domain.Entities; using ShardingCore.Test50.Domain.Entities;
using ShardingCore.Test50.Shardings; using ShardingCore.Test50.Shardings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
#if EFCORE5SQLSERVER #if EFCORE5SQLSERVER
using ShardingCore.SqlServer; using ShardingCore.SqlServer;
@ -22,14 +19,18 @@ using ShardingCore.MySql;
namespace ShardingCore.Test50 namespace ShardingCore.Test50
{ {
/* /*
* @Author: xjm * @Author: xjm
* @Description: * @Description:
* @Date: Friday, 15 January 2021 15:37:46 * @Date: Friday, 15 January 2021 15:37:46
* @Email: 326308290@qq.com * @Email: 326308290@qq.com
*/ */
public class Startup public class Startup
{ {
public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder =>
{
builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole();
});
// // 自定义 host 构建 // // 自定义 host 构建
public void ConfigureHost(IHostBuilder hostBuilder) public void ConfigureHost(IHostBuilder hostBuilder)
{ {
@ -47,33 +48,18 @@ namespace ShardingCore.Test50
public void ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext) public void ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
{ {
services.AddShardingSqlServer(o => services.AddDbContext<DefaultDbContext>(o =>
{
o.EnsureCreatedWithOutShardingTable = false;
o.CreateShardingTableOnStart = false;
o.UseShardingDbContext<DefaultDbContext>( dbConfig =>
{
dbConfig.AddShardingTableRoute<SysUserModVirtualTableRoute>();
dbConfig.AddShardingTableRoute<SysUserSalaryVirtualTableRoute>();
});
//o.AddDataSourceVirtualRoute<>();
});
//services.AddShardingSqlServer(o =>
//{
// o.ConnectionString = hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"];
// o.AddSharding<SysUserModVirtualTableRoute>();
// o.AddSharding<SysUserSalaryVirtualTableRoute>();
// o.UseShardingCoreConfig((provider, config) =>
// {
// config.EnsureCreated = true;
// config.CreateShardingTableOnStart = true;
// });
//});
services.AddDbContext<DefaultDbContext>(o=>
o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"])); o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]));
services.AddDbContext<ShardingDefaultDbContext>(o=> services.AddShardingDbContext<ShardingDefaultDbContext, DefaultDbContext>(o =>
o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]).UseSharding()); o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]), op =>
{
op.EnsureCreatedWithOutShardingTable = true;
op.CreateShardingTableOnStart = true;
op.UseShardingDbContextOptions((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger));
op.AddShardingTableRoute<SysUserModVirtualTableRoute>();
op.AddShardingTableRoute<SysUserSalaryVirtualTableRoute>();
});
} }
// 可以添加要用到的方法参数,会自动从注册的服务中获取服务实例,类似于 asp.net core 里 Configure 方法 // 可以添加要用到的方法参数,会自动从注册的服务中获取服务实例,类似于 asp.net core 里 Configure 方法
@ -90,50 +76,50 @@ namespace ShardingCore.Test50
/// </summary> /// </summary>
/// <param name="serviceProvider"></param> /// <param name="serviceProvider"></param>
/// <returns></returns> /// <returns></returns>
private async Task InitData(IServiceProvider serviceProvider) private async Task InitData(IServiceProvider serviceProvider)
{ {
using (var scope = serviceProvider.CreateScope()) using (var scope = serviceProvider.CreateScope())
{ {
var virtualDbContext = scope.ServiceProvider.GetService<ShardingDefaultDbContext>(); var virtualDbContext = scope.ServiceProvider.GetService<ShardingDefaultDbContext>();
var ids = Enumerable.Range(1, 1000); var ids = Enumerable.Range(1, 1000);
var userMods = new List<SysUserMod>(); var userMods = new List<SysUserMod>();
var userSalaries = new List<SysUserSalary>(); var userSalaries = new List<SysUserSalary>();
var beginTime = new DateTime(2020, 1, 1); var beginTime = new DateTime(2020, 1, 1);
var endTime = new DateTime(2021, 12, 1); var endTime = new DateTime(2021, 12, 1);
foreach (var id in ids) foreach (var id in ids)
{
userMods.Add(new SysUserMod()
{ {
userMods.Add(new SysUserMod() Id = id.ToString(),
Age = id,
Name = $"name_{id}",
AgeGroup = Math.Abs(id % 10)
});
var tempTime = beginTime;
var i = 0;
while (tempTime <= endTime)
{
var dateOfMonth = $@"{tempTime:yyyyMM}";
userSalaries.Add(new SysUserSalary()
{ {
Id = id.ToString(), Id = $@"{id}{dateOfMonth}",
Age = id, UserId = id.ToString(),
Name = $"name_{id}", DateOfMonth = int.Parse(dateOfMonth),
AgeGroup=Math.Abs(id%10) Salary = 700000 + id * 100 * i,
SalaryLong = 700000 + id * 100 * i,
SalaryDecimal = (700000 + id * 100 * i) / 100m,
SalaryDouble = (700000 + id * 100 * i) / 100d,
SalaryFloat = (700000 + id * 100 * i) / 100f
}); });
var tempTime = beginTime; tempTime = tempTime.AddMonths(1);
var i = 0; i++;
while (tempTime<=endTime)
{
var dateOfMonth = $@"{tempTime:yyyyMM}";
userSalaries.Add(new SysUserSalary()
{
Id = $@"{id}{dateOfMonth}",
UserId = id.ToString(),
DateOfMonth = int.Parse(dateOfMonth),
Salary = 700000+id*100*i,
SalaryLong = 700000+id*100*i,
SalaryDecimal = (700000+id*100*i)/100m,
SalaryDouble = (700000+id*100*i)/100d,
SalaryFloat = (700000+id*100*i)/100f
});
tempTime=tempTime.AddMonths(1);
i++;
}
} }
}
await virtualDbContext.AddRangeAsync(userMods); await virtualDbContext.AddRangeAsync(userMods);
await virtualDbContext.AddRangeAsync(userSalaries); await virtualDbContext.AddRangeAsync(userSalaries);
await virtualDbContext.SaveChangesAsync(); await virtualDbContext.SaveChangesAsync();
} }
} }
} }