diff --git a/samples/Sample.SqlServer/Controllers/ValuesController.cs b/samples/Sample.SqlServer/Controllers/ValuesController.cs index f2a016c1..ee97c200 100644 --- a/samples/Sample.SqlServer/Controllers/ValuesController.cs +++ b/samples/Sample.SqlServer/Controllers/ValuesController.cs @@ -25,7 +25,7 @@ namespace Sample.SqlServer.Controllers public async Task Get() { var result = await _virtualDbContext.Set().ToShardingListAsync(); - var result1 = await _virtualDbContext.Set().Where(o=>o.Id=="2").ToShardingListAsync(); + var result1 = await _virtualDbContext.Set().Where(o=>o.Id=="2"||o.Id=="3").ToShardingListAsync(); return Ok(result1); } } diff --git a/samples/Sample.SqlServer/DIExtension.cs b/samples/Sample.SqlServer/DIExtension.cs index eed1bb37..345a01bb 100644 --- a/samples/Sample.SqlServer/DIExtension.cs +++ b/samples/Sample.SqlServer/DIExtension.cs @@ -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(); + if (!virtualDbContext.Set().ShardingAny()) + { + var ids = Enumerable.Range(1, 1000); + var userMods = new List(); + foreach (var id in ids) + { + userMods.Add(new SysUserMod() + { + Id = id.ToString(), + Age = id, + Name = $"name_{id}", + }); + } + + virtualDbContext.InsertRange(userMods); + virtualDbContext.SaveChanges(); + } + } + } } } \ No newline at end of file diff --git a/samples/Sample.SqlServer/DbContexts/DefaultDbContext.cs b/samples/Sample.SqlServer/DbContexts/DefaultTableDbContext.cs similarity index 55% rename from samples/Sample.SqlServer/DbContexts/DefaultDbContext.cs rename to samples/Sample.SqlServer/DbContexts/DefaultTableDbContext.cs index 402c9ef7..d52ca2fd 100644 --- a/samples/Sample.SqlServer/DbContexts/DefaultDbContext.cs +++ b/samples/Sample.SqlServer/DbContexts/DefaultTableDbContext.cs @@ -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 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()); } diff --git a/samples/Sample.SqlServer/Startup.cs b/samples/Sample.SqlServer/Startup.cs index 66f2d47d..c4583923 100644 --- a/samples/Sample.SqlServer/Startup.cs +++ b/samples/Sample.SqlServer/Startup.cs @@ -24,7 +24,7 @@ namespace Sample.SqlServer { o.EnsureCreatedWithOutShardingTable = true; o.CreateShardingTableOnStart = true; - o.AddShardingDbContext("conn1", "Data Source=localhost;Initial Catalog=ShardingCoreDB123;Integrated Security=True", dbConfig => + o.AddShardingDbContextWithShardingTable("conn1", "Data Source=localhost;Initial Catalog=ShardingCoreDB123;Integrated Security=True", dbConfig => { dbConfig.AddShardingTableRoute(); }); @@ -46,6 +46,7 @@ namespace Sample.SqlServer app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + app.DbSeed(); } } } \ No newline at end of file diff --git a/src/ShardingCore/AbstractShardingCoreOptions.cs b/src/ShardingCore/AbstractShardingCoreOptions.cs index c969686d..4aea7e88 100644 --- a/src/ShardingCore/AbstractShardingCoreOptions.cs +++ b/src/ShardingCore/AbstractShardingCoreOptions.cs @@ -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,8 @@ namespace ShardingCore { private readonly IDictionary _shardingConfigs = new Dictionary(); - public void AddShardingDbContext(string connectKey, string connectString, Action func) where TContext : DbContext + + public void AddShardingDbContext(string connectKey, string connectString) where TContext : DbContext { if (_shardingConfigs.ContainsKey(connectKey)) { @@ -30,13 +32,22 @@ namespace ShardingCore ShardingCoreHelper.CheckContextConstructors(); var creator = ShardingCoreHelper.CreateActivator(); - var config = new ShardingConfigEntry(connectKey, connectString, creator, typeof(TContext), func); + var config = new ShardingConfigEntry(connectKey, connectString, creator, typeof(TContext), null); _shardingConfigs.Add(connectKey, config); } - - public void AddShardingDbContext(string connectKey, string connectString) where T : DbContext + + + public void AddShardingDbContextWithShardingTable(string connectKey, string connectString, Action func) where TContext : AbstractShardingTableDbContext { - AddShardingDbContext(connectKey, connectString, null); + if (_shardingConfigs.ContainsKey(connectKey)) + { + throw new ArgumentException($"same connect key:[{connectKey}]"); + } + + ShardingCoreHelper.CheckContextConstructors(); + var creator = ShardingCoreHelper.CreateActivator(); + var config = new ShardingConfigEntry(connectKey, connectString, creator, typeof(TContext), func); + _shardingConfigs.Add(connectKey, config); } diff --git a/src/ShardingCore/DbContexts/ShardingDbContexts/AbstractShardingDbContext.cs b/src/ShardingCore/DbContexts/ShardingDbContexts/AbstractShardingDbContext.cs deleted file mode 100644 index b18be158..00000000 --- a/src/ShardingCore/DbContexts/ShardingDbContexts/AbstractShardingDbContext.cs +++ /dev/null @@ -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 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}"); - } - } - } - } -} \ No newline at end of file diff --git a/src/ShardingCore/DbContexts/ShardingDbContexts/AbstractShardingTableDbContext.cs b/src/ShardingCore/DbContexts/ShardingDbContexts/AbstractShardingTableDbContext.cs new file mode 100644 index 00000000..7279bf83 --- /dev/null +++ b/src/ShardingCore/DbContexts/ShardingDbContexts/AbstractShardingTableDbContext.cs @@ -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 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}"); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/EFCores/ShardingModelCacheKeyFactory.cs b/src/ShardingCore/EFCores/ShardingModelCacheKeyFactory.cs index 13509776..3973804f 100644 --- a/src/ShardingCore/EFCores/ShardingModelCacheKeyFactory.cs +++ b/src/ShardingCore/EFCores/ShardingModelCacheKeyFactory.cs @@ -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; diff --git a/src/ShardingCore/Extensions/CommonExtension.cs b/src/ShardingCore/Extensions/CommonExtension.cs index 9cd562be..4865d573 100644 --- a/src/ShardingCore/Extensions/CommonExtension.cs +++ b/src/ShardingCore/Extensions/CommonExtension.cs @@ -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); } /// /// 是否基继承至IShardingEntity diff --git a/src/ShardingCore/Extensions/DbContextExtension.cs b/src/ShardingCore/Extensions/DbContextExtension.cs new file mode 100644 index 00000000..4d7245da --- /dev/null +++ b/src/ShardingCore/Extensions/DbContextExtension.cs @@ -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]); + } + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Extensions/ShardingExtension.cs b/src/ShardingCore/Extensions/ShardingExtension.cs index aef9f305..ea8f5cf0 100644 --- a/src/ShardingCore/Extensions/ShardingExtension.cs +++ b/src/ShardingCore/Extensions/ShardingExtension.cs @@ -25,11 +25,49 @@ namespace ShardingCore.Extensions { return ShardingQueryable.Create(source); } + /// + /// 是否存在待条件 + /// + /// + /// + /// + /// public static async Task ShardingAnyAsync(this IQueryable source, Expression> predicate) { return await ShardingQueryable.Create(source.Where(predicate)).AnyAsync(); } /// + /// 是否存在待条件 + /// + /// + /// + /// + /// + public static bool ShardingAny(this IQueryable source, Expression> predicate) + { + return ShardingQueryable.Create(source.Where(predicate)).Any(); + } + /// + /// 是否存在 + /// + /// + /// + /// + public static async Task ShardingAnyAsync(this IQueryable source) + { + return await ShardingQueryable.Create(source).AnyAsync(); + } + /// + /// 是否存在 + /// + /// + /// + /// + public static bool ShardingAny(this IQueryable source) + { + return ShardingQueryable.Create(source).Any(); + } + /// /// 分页 /// /// diff --git a/src/ShardingCore/IShardingCoreOptions.cs b/src/ShardingCore/IShardingCoreOptions.cs index 34406401..28096621 100644 --- a/src/ShardingCore/IShardingCoreOptions.cs +++ b/src/ShardingCore/IShardingCoreOptions.cs @@ -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(string connectKey, string connectString, Action func) where T : DbContext; + void AddShardingDbContextWithShardingTable(string connectKey, string connectString, Action func) where T : AbstractShardingTableDbContext; void AddShardingDbContext(string connectKey, string connectString) where T : DbContext; diff --git a/src/ShardingCore/ShardingBootstrapper.cs b/src/ShardingCore/ShardingBootstrapper.cs index 958a8233..7e411654 100644 --- a/src/ShardingCore/ShardingBootstrapper.cs +++ b/src/ShardingCore/ShardingBootstrapper.cs @@ -167,7 +167,7 @@ namespace ShardingCore using var scope = _serviceProvider.CreateScope(); var dbContextOptionsProvider = scope.ServiceProvider.GetService(); using var context = _shardingDbContextFactory.Create(shardingConfig.ConnectKey,new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(shardingConfig.ConnectKey), string.Empty, new List())); - var contextModel = context.Model as Model; + context.RemoveDbContextRelationModelThatIsShardingTable(); context.Database.EnsureCreated(); } } diff --git a/src/ShardingCore/TableCreator/ShardingTableCreator.cs b/src/ShardingCore/TableCreator/ShardingTableCreator.cs index 29dc62c2..df0a71a1 100644 --- a/src/ShardingCore/TableCreator/ShardingTableCreator.cs +++ b/src/ShardingCore/TableCreator/ShardingTableCreator.cs @@ -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() {new VirtualTableDbContextConfig(shardingEntityType, virtualTable.GetOriginalTableName(), virtualTable.ShardingConfig.TailPrefix)}))) { + dbContext.RemoveDbContextRelationModelSaveOnlyThatIsShardingTable(shardingEntityType); var databaseCreator = dbContext.Database.GetService() as RelationalDatabaseCreator; try {