修复Migrate在同步上下文中block的bug

This commit is contained in:
xuejiaming 2022-10-18 09:02:54 +08:00
parent 44a6765139
commit 61f76b7b19
7 changed files with 258 additions and 7 deletions

View File

@ -1,6 +1,6 @@
:start
::定义版本
set SHARDINGCORE=6.7.0.5
set SHARDINGCORE=6.7.0.6
::删除所有bin与obj下的文件
@echo off

View File

@ -52,6 +52,8 @@ public class WeatherForecastController : ControllerBase
}
public async Task<IActionResult> Query1()
{
var s = Guid.NewGuid().ToString();
var anyAsync = await _defaultDbContext.Set<AreaDevice>().AnyAsync(o=>o.Area==s);
var list = await _defaultDbContext.Set<AreaDevice>().ToListAsync();
return Ok(list);
}

View File

@ -0,0 +1,243 @@
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
namespace Sample.AutoCreateIfPresent;
public static class MyShardingExtension
{
/// <summary>
/// 根据对象集合解析
/// </summary>
/// <typeparam name="TShardingDbContext"></typeparam>
/// <typeparam name="TEntity"></typeparam>
/// <param name="shardingDbContext"></param>
/// <param name="entities"></param>
/// <returns></returns>
public static Dictionary<string, Dictionary<DbContext, IEnumerable<TEntity>>> BulkShardingEnumerable<TShardingDbContext, TEntity>(this TShardingDbContext shardingDbContext,
IEnumerable<TEntity> entities) where TShardingDbContext : DbContext, IShardingDbContext where TEntity : class
{
if (entities.IsEmpty())
return new Dictionary<string, Dictionary<DbContext, IEnumerable<TEntity>>>();
var shardingRuntimeContext = shardingDbContext.GetShardingRuntimeContext();
var entityType = typeof(TEntity);
var routeTailFactory = shardingRuntimeContext.GetRouteTailFactory();
var virtualDataSource = shardingDbContext.GetVirtualDataSource();
var dataSourceRouteManager = shardingRuntimeContext.GetDataSourceRouteManager();
var tableRouteManager =shardingRuntimeContext.GetTableRouteManager();
var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager();
var dataSourceNames = new Dictionary<string, Dictionary<string, BulkDicEntry<TEntity>>>();
var entitiesArray = entities as TEntity[] ?? entities.ToArray();
var isShardingDataSource = entityMetadataManager.IsShardingDataSource(entityType);
var isShardingTable = entityMetadataManager.IsShardingTable(entityType);
if (!isShardingDataSource && !isShardingTable)
return new Dictionary<string, Dictionary<DbContext, IEnumerable<TEntity>>>()
{
{
virtualDataSource.DefaultDataSourceName,
new Dictionary<DbContext, IEnumerable<TEntity>>()
{
{
shardingDbContext.CreateGenericDbContext(entitiesArray[0]),
entitiesArray
}
}
}
};
if (!isShardingDataSource)
{
var bulkDicEntries = new Dictionary<string, BulkDicEntry<TEntity>>();
dataSourceNames.Add(virtualDataSource.DefaultDataSourceName, bulkDicEntries);
var tableRoute = tableRouteManager.GetRoute(entityType);
var allTails = tableRoute.GetTails().ToHashSet();
foreach (var entity in entitiesArray)
{
BulkShardingTableEnumerable(shardingDbContext, virtualDataSource.DefaultDataSourceName, bulkDicEntries,
routeTailFactory, tableRoute, allTails, entity);
}
}
else
{
var virtualDataSourceRoute = dataSourceRouteManager.GetRoute(entityType);
var allDataSourceNames = virtualDataSourceRoute.GetAllDataSourceNames().ToHashSet();
var entityMetadata = entityMetadataManager.TryGet(entityType);
IVirtualTableRoute tableRoute = null;
ISet<string> allTails = null;
if (isShardingTable)
{
tableRoute = tableRouteManager.GetRoute(entityType);
allTails = tableRoute.GetTails().ToHashSet();
}
foreach (var entity in entitiesArray)
{
var shardingDataSourceValue = entity.GetPropertyValue(entityMetadata.ShardingDataSourceProperty.Name);
if (shardingDataSourceValue == null)
throw new ShardingCoreInvalidOperationException($" etities has null value of sharding data source value");
var shardingDataSourceName = virtualDataSourceRoute.ShardingKeyToDataSourceName(shardingDataSourceValue);
if (!allDataSourceNames.Contains(shardingDataSourceName))
throw new ShardingCoreException(
$" data source name :[{shardingDataSourceName}] all data source names:[{string.Join(",", allDataSourceNames)}]");
if (!dataSourceNames.TryGetValue(shardingDataSourceName, out var bulkDicEntries))
{
bulkDicEntries = new Dictionary<string, BulkDicEntry<TEntity>>();
dataSourceNames.Add(shardingDataSourceName, bulkDicEntries);
}
if (isShardingTable)
{
BulkShardingTableEnumerable(shardingDbContext, shardingDataSourceName, bulkDicEntries,
routeTailFactory, tableRoute, allTails, entity);
}
else
BulkNoShardingTableEnumerable(shardingDbContext, shardingDataSourceName, bulkDicEntries,
routeTailFactory, entity);
}
}
return dataSourceNames.ToDictionary(o => o.Key,
o => o.Value.Select(o => o.Value).ToDictionary(v => v.InnerDbContext, v => v.InnerEntities.Select(t => t)));
}
private static void BulkShardingTableEnumerable<TShardingDbContext, TEntity>(TShardingDbContext shardingDbContext, string dataSourceName, Dictionary<string, BulkDicEntry<TEntity>> dataSourceBulkDicEntries,
IRouteTailFactory routeTailFactory,IVirtualTableRoute tableRoute, ISet<string> allTails, TEntity entity)
where TShardingDbContext : DbContext, IShardingDbContext
where TEntity : class
{
var entityType = typeof(TEntity);
var shardingKey = entity.GetPropertyValue(tableRoute.EntityMetadata.ShardingTableProperty.Name);
var tail = tableRoute.ShardingKeyToTail(shardingKey);
if (!allTails.Contains(tail))
{
//不在alltails说明需要新增那么调用routewithvalue就会处理对应tail
var tableRouteUnit = tableRoute.RouteWithValue(new DataSourceRouteResult(new HashSet<string>(new[] { dataSourceName })),
shardingKey);
if (tableRouteUnit.Tail != tail)
{
throw new ShardingCoreException(
$"sharding key route not match entity:{entityType.FullName},sharding key:{shardingKey},sharding tail:{tail}");
}
allTails.Add(tail);
}
var routeTail = routeTailFactory.Create(tail);
var routeTailIdentity = routeTail.GetRouteTailIdentity();
if (!dataSourceBulkDicEntries.TryGetValue(routeTailIdentity, out var bulkDicEntry))
{
var dbContext = shardingDbContext.GetShareDbContext(dataSourceName, routeTail);
bulkDicEntry = new BulkDicEntry<TEntity>(dbContext, new LinkedList<TEntity>());
dataSourceBulkDicEntries.Add(routeTailIdentity, bulkDicEntry);
}
bulkDicEntry.InnerEntities.AddLast(entity);
}
private static void BulkNoShardingTableEnumerable<TShardingDbContext, TEntity>(TShardingDbContext shardingDbContext, string dataSourceName, Dictionary<string, BulkDicEntry<TEntity>> dataSourceBulkDicEntries, IRouteTailFactory routeTailFactory, TEntity entity)
where TShardingDbContext : DbContext, IShardingDbContext
where TEntity : class
{
var routeTail = routeTailFactory.Create(string.Empty);
var routeTailIdentity = routeTail.GetRouteTailIdentity();
if (!dataSourceBulkDicEntries.TryGetValue(routeTailIdentity, out var bulkDicEntry))
{
var dbContext = shardingDbContext.GetShareDbContext(dataSourceName, routeTail);
bulkDicEntry = new BulkDicEntry<TEntity>(dbContext, new LinkedList<TEntity>());
dataSourceBulkDicEntries.Add(routeTailIdentity, bulkDicEntry);
}
bulkDicEntry.InnerEntities.AddLast(entity);
}
internal class BulkDicEntry<TEntity>
{
public BulkDicEntry(DbContext innerDbContext, LinkedList<TEntity> innerEntities)
{
InnerDbContext = innerDbContext;
InnerEntities = innerEntities;
}
public DbContext InnerDbContext { get; }
public LinkedList<TEntity> InnerEntities { get; }
}
public static Dictionary<DbContext, IEnumerable<TEntity>> BulkShardingTableEnumerable<TShardingDbContext, TEntity>(this TShardingDbContext shardingDbContext,
IEnumerable<TEntity> entities) where TShardingDbContext : DbContext, IShardingDbContext
where TEntity : class
{
var shardingRuntimeContext = shardingDbContext.GetShardingRuntimeContext();
var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager();
if (entityMetadataManager.IsShardingDataSource(typeof(TEntity)))
throw new ShardingCoreInvalidOperationException(typeof(TEntity).FullName);
//if (!entityMetadataManager.IsShardingTable(typeof(TEntity)))
// throw new ShardingCoreInvalidOperationException(typeof(TEntity).FullName);
if (entities.IsEmpty())
return new Dictionary<DbContext, IEnumerable<TEntity>>();
return shardingDbContext.BulkShardingEnumerable(entities).First().Value;
}
/// <summary>
/// 根据条件表达式解析
/// </summary>
/// <typeparam name="TShardingDbContext"></typeparam>
/// <typeparam name="TEntity"></typeparam>
/// <param name="shardingDbContext"></param>
/// <param name="where"></param>
/// <returns></returns>
public static IDictionary<string, IEnumerable<DbContext>> BulkShardingExpression<TShardingDbContext, TEntity>(this TShardingDbContext shardingDbContext, Expression<Func<TEntity, bool>> where) where TEntity : class
where TShardingDbContext : DbContext, IShardingDbContext
{
var shardingRuntimeContext = shardingDbContext.GetShardingRuntimeContext();
var routeTailFactory = shardingRuntimeContext.GetRouteTailFactory();
var dataSourceRouteManager = shardingRuntimeContext.GetDataSourceRouteManager();
var tableRouteManager = shardingRuntimeContext.GetTableRouteManager();// (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(shardingDbContext.GetType()));
var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager();// (IEntityMetadataManager)ShardingContainer.GetService(typeof(IEntityMetadataManager<>).GetGenericType0(shardingDbContext.GetType()));
var dataSourceNames = dataSourceRouteManager.GetDataSourceNames(where);
var result = new Dictionary<string, LinkedList<DbContext>>();
var entityType = typeof(TEntity);
foreach (var dataSourceName in dataSourceNames)
{
if (!result.TryGetValue(dataSourceName, out var dbContexts))
{
dbContexts = new LinkedList<DbContext>();
result.Add(dataSourceName, dbContexts);
}
if (entityMetadataManager.IsShardingTable(entityType))
{
var physicTables = tableRouteManager.RouteTo(entityType,new DataSourceRouteResult(dataSourceName),new ShardingTableRouteConfig(predicate: @where));
if (physicTables.IsEmpty())
throw new ShardingCoreException($"{where.ShardingPrint()} cant found any physic table");
var dbs = physicTables.Select(o => shardingDbContext.GetShareDbContext(dataSourceName, routeTailFactory.Create(o.Tail))).ToList();
foreach (var dbContext in dbs)
{
dbContexts.AddLast(dbContext);
}
}
else
{
var dbContext = shardingDbContext.GetShareDbContext(dataSourceName, routeTailFactory.Create(string.Empty));
dbContexts.AddLast(dbContext);
}
}
return result.ToDictionary(o => o.Key, o => (IEnumerable<DbContext>)o.Value);
}
public static IEnumerable<DbContext> BulkShardingTableExpression<TShardingDbContext, TEntity>(this TShardingDbContext shardingDbContext, Expression<Func<TEntity, bool>> where) where TEntity : class
where TShardingDbContext : DbContext, IShardingDbContext
{
var shardingRuntimeContext = shardingDbContext.GetShardingRuntimeContext();
var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager();// (IEntityMetadataManager)ShardingContainer.GetService(typeof(IEntityMetadataManager<>).GetGenericType0(shardingDbContext.GetType()));
if (entityMetadataManager.IsShardingDataSource(typeof(TEntity)))
throw new ShardingCoreInvalidOperationException(typeof(TEntity).FullName);
return shardingDbContext.BulkShardingExpression<TShardingDbContext, TEntity>(where).First().Value;
}
}

View File

@ -105,7 +105,7 @@ namespace Sample.MySql.Controllers
// var firstOrDefault = _defaultTableDbContext.Set<SysUserMod>().FromSqlRaw($"select * from {nameof(SysUserMod)}").FirstOrDefault();
var sysUserMods1 = _defaultTableDbContext.Set<SysTest>()
var sysUserMods1 = _defaultTableDbContext.Set<SysTest>().UseConnectionMode(1)
.Select(o => new ssss(){ Id = o.Id, C = _abc.Select.Count(x => x.Id == o.Id) }).ToList();
var sysUserMods2 = _defaultTableDbContext.Set<SysTest>()
.Select(o => new ssss(){ Id = o.Id, C = GetAll().Count(x => x.Id == o.Id) }).ToList();

View File

@ -70,7 +70,7 @@ namespace ShardingCore.EFCores
#endif
public override void Migrate(string targetMigration = null)
{
this.MigrateAsync(targetMigration).WaitAndUnwrapException();
this.MigrateAsync(targetMigration).WaitAndUnwrapException(false);
// base.Migrate(targetMigration);
}
@ -78,7 +78,7 @@ namespace ShardingCore.EFCores
{
var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource();
var allDataSourceNames = virtualDataSource.GetAllDataSourceNames();
await DynamicShardingHelper.DynamicMigrateWithDataSourcesAsync(_shardingRuntimeContext, allDataSourceNames, null,targetMigration,cancellationToken);
await DynamicShardingHelper.DynamicMigrateWithDataSourcesAsync(_shardingRuntimeContext, allDataSourceNames, null,targetMigration,cancellationToken).ConfigureAwait(false);
}
#if NET6_0 || NET5_0 || NETSTANDARD2_1

View File

@ -40,6 +40,12 @@ namespace ShardingCore.Extensions
throw new ArgumentNullException(nameof(task));
task.GetAwaiter().GetResult();
}
public static void WaitAndUnwrapException(this Task task,bool continueOnCapturedContext)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
task.ConfigureAwait(continueOnCapturedContext).GetAwaiter().GetResult();
}
/// <summary>
/// Waits for the task to complete, unwrapping any exceptions.

View File

@ -76,13 +76,13 @@ namespace ShardingCore.Helpers
foreach (var migrationUnits in partitionMigrationUnits)
{
var migrateUnits = migrationUnits.Select(o =>new MigrateUnit(shellDbContext,o)).ToList();
await ExecuteMigrateUnitsAsync(shardingRuntimeContext,migrateUnits,targetMigration,cancellationToken);
await ExecuteMigrateUnitsAsync(shardingRuntimeContext,migrateUnits,targetMigration,cancellationToken).ConfigureAwait((false));
}
//包含默认默认的单独最后一次处理
if (allDataSourceNames.Contains(defaultDataSourceName))
{
await ExecuteMigrateUnitsAsync(shardingRuntimeContext,new List<MigrateUnit>(){new MigrateUnit(shellDbContext,defaultDataSourceName)},targetMigration,cancellationToken);
await ExecuteMigrateUnitsAsync(shardingRuntimeContext,new List<MigrateUnit>(){new MigrateUnit(shellDbContext,defaultDataSourceName)},targetMigration,cancellationToken).ConfigureAwait(false);
}
}
}
@ -120,7 +120,7 @@ namespace ShardingCore.Helpers
},cancellationToken);
}).ToArray();
await TaskHelper.WhenAllFastFail(migrateTasks);
await TaskHelper.WhenAllFastFail(migrateTasks).ConfigureAwait(false);
}
public static DbContextOptions CreateShellDbContextOptions(IShardingRuntimeContext shardingRuntimeContext,Type dbContextType,string dataSourceName)