完成efcore 5.x的启动新增表结构和独立新增表结构

This commit is contained in:
xuejiaming 2021-03-08 17:33:04 +08:00
parent 06d9e8f7a7
commit b052861b9d
14 changed files with 191 additions and 73 deletions

View File

@ -25,7 +25,7 @@ namespace Sample.SqlServer.Controllers
public async Task<IActionResult> Get()
{
var result = await _virtualDbContext.Set<SysUserMod>().ToShardingListAsync();
var result1 = await _virtualDbContext.Set<SysUserMod>().Where(o=>o.Id=="2").ToShardingListAsync();
var result1 = await _virtualDbContext.Set<SysUserMod>().Where(o=>o.Id=="2"||o.Id=="3").ToShardingListAsync();
return Ok(result1);
}
}

View File

@ -1,7 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Sample.SqlServer.Domain.Entities;
using ShardingCore;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
namespace Sample.SqlServer
{
@ -19,5 +24,30 @@ namespace Sample.SqlServer
shardingBootstrapper.Start();
return app;
}
public static void DbSeed(this IApplicationBuilder app)
{
using (var scope=app.ApplicationServices.CreateScope())
{
var virtualDbContext =scope.ServiceProvider.GetService<IVirtualDbContext>();
if (!virtualDbContext.Set<SysUserMod>().ShardingAny())
{
var ids = Enumerable.Range(1, 1000);
var userMods = new List<SysUserMod>();
foreach (var id in ids)
{
userMods.Add(new SysUserMod()
{
Id = id.ToString(),
Age = id,
Name = $"name_{id}",
});
}
virtualDbContext.InsertRange(userMods);
virtualDbContext.SaveChanges();
}
}
}
}
}

View File

@ -4,19 +4,19 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Sample.SqlServer.Domain.Maps;
using ShardingCore.DbContexts.ShardingDbContexts;
namespace Sample.SqlServer.DbContexts
{
public class DefaultDbContext: DbContext
public class DefaultTableDbContext: AbstractShardingTableDbContext
{
public DefaultDbContext(DbContextOptions<DefaultDbContext> options):base(options)
public DefaultTableDbContext(ShardingDbContextOptions shardingDbContextOptions):base(shardingDbContextOptions)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
protected override void OnShardingModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new SysUserModMap());
modelBuilder.ApplyConfiguration(new SysTestMap());
}

View File

@ -24,7 +24,7 @@ namespace Sample.SqlServer
{
o.EnsureCreatedWithOutShardingTable = true;
o.CreateShardingTableOnStart = true;
o.AddShardingDbContext<DefaultDbContext>("conn1", "Data Source=localhost;Initial Catalog=ShardingCoreDB123;Integrated Security=True", dbConfig =>
o.AddShardingDbContextWithShardingTable<DefaultTableDbContext>("conn1", "Data Source=localhost;Initial Catalog=ShardingCoreDB123;Integrated Security=True", dbConfig =>
{
dbConfig.AddShardingTableRoute<SysUserModVirtualRoute>();
});
@ -46,6 +46,7 @@ namespace Sample.SqlServer
app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
app.DbSeed();
}
}
}

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
@ -21,7 +22,22 @@ namespace ShardingCore
{
private readonly IDictionary<string, ShardingConfigEntry> _shardingConfigs = new Dictionary<string, ShardingConfigEntry>();
public void AddShardingDbContext<TContext>(string connectKey, string connectString, Action<ShardingDbConfigOptions> func) where TContext : DbContext
public void AddShardingDbContext<TContext>(string connectKey, string connectString) where TContext : DbContext
{
if (_shardingConfigs.ContainsKey(connectKey))
{
throw new ArgumentException($"same connect key:[{connectKey}]");
}
ShardingCoreHelper.CheckContextConstructors<TContext>();
var creator = ShardingCoreHelper.CreateActivator<TContext>();
var config = new ShardingConfigEntry(connectKey, connectString, creator, typeof(TContext), null);
_shardingConfigs.Add(connectKey, config);
}
public void AddShardingDbContextWithShardingTable<TContext>(string connectKey, string connectString, Action<ShardingDbConfigOptions> func) where TContext : AbstractShardingTableDbContext
{
if (_shardingConfigs.ContainsKey(connectKey))
{
@ -34,11 +50,6 @@ namespace ShardingCore
_shardingConfigs.Add(connectKey, config);
}
public void AddShardingDbContext<T>(string connectKey, string connectString) where T : DbContext
{
AddShardingDbContext<T>(connectKey, connectString, null);
}
private readonly Dictionary<Type, Type> _virtualRoutes = new Dictionary<Type, Type>();
public void AddDataSourceVirtualRoute<TRoute>() where TRoute : IDataSourceVirtualRoute

View File

@ -1,58 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts.ShardingDbContexts
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/4 16:11:18
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public abstract class AbstractShardingDbContext : DbContext
{
public string Tail { get; }
public Dictionary<Type, VirtualTableDbContextConfig> VirtualTableConfigs { get; }
protected AbstractShardingDbContext(ShardingDbContextOptions options)
{
Tail = options.Tail;
VirtualTableConfigs = options.VirtualTableDbContextConfigs.ToDictionary(o => o.ShardingEntityType, o => o);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
OnShardingModelCreating(modelBuilder);
OnModelCreatingAfter(modelBuilder);
}
protected abstract void OnShardingModelCreating(ModelBuilder modelBuilder);
protected virtual void OnModelCreatingAfter(ModelBuilder modelBuilder)
{
if (!string.IsNullOrWhiteSpace(Tail))
{
var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o => VirtualTableConfigs.ContainsKey(o.ClrType));
foreach (var entityType in mutableEntityTypes)
{
var virtualTableConfig = VirtualTableConfigs[entityType.ClrType];
var shardingEntity = virtualTableConfig.ShardingEntityType;
var tailPrefix = virtualTableConfig.TailPrefix;
var entity = modelBuilder.Entity(shardingEntity);
var tableName = virtualTableConfig.OriginalTableName;
if (string.IsNullOrWhiteSpace(tableName))
throw new ArgumentNullException($"{shardingEntity}: not found original table name。");
#if DEBUG
Console.WriteLine($"映射表:[tableName]-->[{tableName}{tailPrefix}{Tail}]");
#endif
entity.ToTable($"{tableName}{tailPrefix}{Tail}");
}
}
}
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Extensions;
namespace ShardingCore.DbContexts.ShardingDbContexts
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/4 16:11:18
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public abstract class AbstractShardingTableDbContext : DbContext
{
public string Tail { get; }
public Dictionary<Type, VirtualTableDbContextConfig> VirtualTableConfigs { get; }
protected AbstractShardingTableDbContext(ShardingDbContextOptions options):base(options.DbContextOptions)
{
Tail = options.Tail;
VirtualTableConfigs = options.VirtualTableDbContextConfigs.ToDictionary(o => o.ShardingEntityType, o => o);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
OnShardingModelCreating(modelBuilder);
OnModelCreatingAfter(modelBuilder);
}
protected abstract void OnShardingModelCreating(ModelBuilder modelBuilder);
protected virtual void OnModelCreatingAfter(ModelBuilder modelBuilder)
{
if (!string.IsNullOrWhiteSpace(Tail))
{
if (VirtualTableConfigs.IsNotEmpty())
{
var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o => VirtualTableConfigs.ContainsKey(o.ClrType));
foreach (var entityType in mutableEntityTypes)
{
var virtualTableConfig = VirtualTableConfigs[entityType.ClrType];
var shardingEntity = virtualTableConfig.ShardingEntityType;
var tailPrefix = virtualTableConfig.TailPrefix;
var entity = modelBuilder.Entity(shardingEntity);
var tableName = virtualTableConfig.OriginalTableName;
if (string.IsNullOrWhiteSpace(tableName))
throw new ArgumentNullException($"{shardingEntity}: not found original table name。");
#if DEBUG
Console.WriteLine($"映射表:[tableName]-->[{tableName}{tailPrefix}{Tail}]");
#endif
entity.ToTable($"{tableName}{tailPrefix}{Tail}");
}
}
}
}
}
}

View File

@ -15,7 +15,7 @@ namespace ShardingCore.EFCores
{
public object Create(DbContext context)
{
if (context is AbstractShardingDbContext shardingDbContext)
if (context is AbstractShardingTableDbContext shardingDbContext)
{
//当出现尾巴不一样,本次映射的数据库实体数目不一样就需要重建ef model
var tail = shardingDbContext.Tail;

View File

@ -45,7 +45,7 @@ namespace ShardingCore.Extensions
{
if (entityType == null)
throw new ArgumentNullException(nameof(entityType));
return typeof(AbstractShardingDbContext).IsAssignableFrom(entityType);
return typeof(AbstractShardingTableDbContext).IsAssignableFrom(entityType);
}
/// <summary>
/// 是否基继承至IShardingEntity

View File

@ -0,0 +1,31 @@
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace ShardingCore.Extensions
{
public static class DbContextExtension
{
public static void RemoveDbContextRelationModelThatIsShardingTable(this DbContext dbContext)
{
var contextModel = dbContext.Model as Model;
var contextModelRelationalModel = contextModel.RelationalModel as RelationalModel;
var valueTuples = contextModelRelationalModel.Tables.Where(o=>o.Value.EntityTypeMappings.Any(m=>m.EntityType.ClrType.IsShardingTable())).Select(o=>o.Key).ToList();
for (int i = 0; i < valueTuples.Count; i++)
{
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
}
}
public static void RemoveDbContextRelationModelSaveOnlyThatIsShardingTable(this DbContext dbContext,Type shardingType)
{
var contextModel = dbContext.Model as Model;
var contextModelRelationalModel = contextModel.RelationalModel as RelationalModel;
var valueTuples = contextModelRelationalModel.Tables.Where(o=> o.Value.EntityTypeMappings.All(m => m.EntityType.ClrType != shardingType)).Select(o=>o.Key).ToList();
for (int i = 0; i < valueTuples.Count; i++)
{
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
}
}
}
}

View File

@ -25,11 +25,49 @@ namespace ShardingCore.Extensions
{
return ShardingQueryable<T>.Create(source);
}
/// <summary>
/// 是否存在待条件
/// </summary>
/// <param name="source"></param>
/// <param name="predicate"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static async Task<bool> ShardingAnyAsync<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate)
{
return await ShardingQueryable<T>.Create(source.Where(predicate)).AnyAsync();
}
/// <summary>
/// 是否存在待条件
/// </summary>
/// <param name="source"></param>
/// <param name="predicate"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static bool ShardingAny<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate)
{
return ShardingQueryable<T>.Create(source.Where(predicate)).Any();
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="source"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static async Task<bool> ShardingAnyAsync<T>(this IQueryable<T> source)
{
return await ShardingQueryable<T>.Create(source).AnyAsync();
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="source"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static bool ShardingAny<T>(this IQueryable<T> source)
{
return ShardingQueryable<T>.Create(source).Any();
}
/// <summary>
/// 分页
/// </summary>
/// <param name="source"></param>

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
using ShardingCore.DbContexts.ShardingDbContexts;
namespace ShardingCore
{
@ -15,7 +16,7 @@ namespace ShardingCore
*/
public interface IShardingCoreOptions
{
void AddShardingDbContext<T>(string connectKey, string connectString, Action<ShardingDbConfigOptions> func) where T : DbContext;
void AddShardingDbContextWithShardingTable<T>(string connectKey, string connectString, Action<ShardingDbConfigOptions> func) where T : AbstractShardingTableDbContext;
void AddShardingDbContext<T>(string connectKey, string connectString) where T : DbContext;

View File

@ -167,7 +167,7 @@ namespace ShardingCore
using var scope = _serviceProvider.CreateScope();
var dbContextOptionsProvider = scope.ServiceProvider.GetService<IDbContextOptionsProvider>();
using var context = _shardingDbContextFactory.Create(shardingConfig.ConnectKey,new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(shardingConfig.ConnectKey), string.Empty, new List<VirtualTableDbContextConfig>()));
var contextModel = context.Model as Model;
context.RemoveDbContextRelationModelThatIsShardingTable();
context.Database.EnsureCreated();
}
}

View File

@ -10,6 +10,7 @@ using ShardingCore.DbContexts;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
namespace ShardingCore.TableCreator
{
@ -55,6 +56,7 @@ namespace ShardingCore.TableCreator
using (var dbContext = _shardingDbContextFactory.Create(connectKey,new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(connectKey), tail,
new List<VirtualTableDbContextConfig>() {new VirtualTableDbContextConfig(shardingEntityType, virtualTable.GetOriginalTableName(), virtualTable.ShardingConfig.TailPrefix)})))
{
dbContext.RemoveDbContextRelationModelSaveOnlyThatIsShardingTable(shardingEntityType);
var databaseCreator = dbContext.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator;
try
{