support firstordefaultasync
This commit is contained in:
parent
f3aa01e999
commit
f4620a4bc4
|
@ -26,8 +26,13 @@ namespace Sample.SqlServer.Controllers
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> Get()
|
public async Task<IActionResult> Get()
|
||||||
{
|
{
|
||||||
var result = await _defaultTableDbContext.Set<SysUserMod>().OrderBy(o=>o.Age).ToListAsync();
|
var resultx = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").FirstOrDefaultAsync();
|
||||||
|
var result = await _defaultTableDbContext.Set<SysUserMod>().ToListAsync();
|
||||||
|
|
||||||
|
var sysUserMod98 = result.FirstOrDefault(o => o.Id == "98");
|
||||||
|
sysUserMod98.Name = "name_update"+new Random().Next(1,99)+"_98";
|
||||||
|
await _defaultTableDbContext.SaveChangesAsync();
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,5 +20,6 @@ namespace Sample.SqlServer.DbContexts
|
||||||
modelBuilder.ApplyConfiguration(new SysUserModMap());
|
modelBuilder.ApplyConfiguration(new SysUserModMap());
|
||||||
modelBuilder.ApplyConfiguration(new SysTestMap());
|
modelBuilder.ApplyConfiguration(new SysTestMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,26 @@ 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.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 Sample.SqlServer.DbContexts;
|
using Sample.SqlServer.DbContexts;
|
||||||
using Sample.SqlServer.Shardings;
|
using Sample.SqlServer.Shardings;
|
||||||
|
using ShardingCore;
|
||||||
|
using ShardingCore.EFCores;
|
||||||
using ShardingCore.SqlServer;
|
using ShardingCore.SqlServer;
|
||||||
|
|
||||||
namespace Sample.SqlServer
|
namespace Sample.SqlServer
|
||||||
{
|
{
|
||||||
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();
|
||||||
|
});
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
@ -23,8 +32,8 @@ namespace Sample.SqlServer
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
services.AddShardingSqlServer(o =>
|
services.AddShardingSqlServer(o =>
|
||||||
{
|
{
|
||||||
o.EnsureCreatedWithOutShardingTable = true;
|
o.EnsureCreatedWithOutShardingTable = false;
|
||||||
o.CreateShardingTableOnStart = true;
|
o.CreateShardingTableOnStart = false;
|
||||||
o.UseShardingDbContext<DefaultTableDbContext>( dbConfig =>
|
o.UseShardingDbContext<DefaultTableDbContext>( dbConfig =>
|
||||||
{
|
{
|
||||||
dbConfig.AddShardingTableRoute<SysUserModVirtualTableRoute>();
|
dbConfig.AddShardingTableRoute<SysUserModVirtualTableRoute>();
|
||||||
|
@ -35,8 +44,17 @@ namespace Sample.SqlServer
|
||||||
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.AddDbContext<DefaultShardingDbContext>(o =>
|
services.AddShardingDbContext<DefaultShardingDbContext, DefaultTableDbContext>(op =>
|
||||||
o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True;").UseSharding());
|
{
|
||||||
|
op.UseShardingDbContextOptions((connection, builder) =>
|
||||||
|
{
|
||||||
|
return builder.UseSqlServer(connection).UseLoggerFactory(efLogger)
|
||||||
|
.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll)
|
||||||
|
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
|
||||||
|
.ReplaceService<IModelCustomizer, ShardingModelCustomizer>().Options;
|
||||||
|
});
|
||||||
|
},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.
|
||||||
|
|
|
@ -1,21 +1,14 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Internal;
|
using Microsoft.EntityFrameworkCore.Internal;
|
||||||
using Microsoft.EntityFrameworkCore.Query;
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
using Microsoft.EntityFrameworkCore.Update;
|
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using ShardingCore.Core.ShardingAccessors;
|
|
||||||
using ShardingCore.Core.VirtualRoutes;
|
|
||||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
|
||||||
using ShardingCore.Core.VirtualTables;
|
|
||||||
using ShardingCore.DbContexts;
|
using ShardingCore.DbContexts;
|
||||||
using ShardingCore.DbContexts.VirtualDbContexts;
|
using ShardingCore.DbContexts.VirtualDbContexts;
|
||||||
using ShardingCore.Extensions;
|
using ShardingCore.EFCores;
|
||||||
using ShardingCore.Sharding;
|
using ShardingCore.Sharding;
|
||||||
using ShardingCore.Sharding.Query;
|
|
||||||
using ShardingCore.SqlServer.EFCores;
|
using ShardingCore.SqlServer.EFCores;
|
||||||
using ShardingCore.TableCreator;
|
using System;
|
||||||
|
|
||||||
#if EFCORE2
|
#if EFCORE2
|
||||||
using Microsoft.EntityFrameworkCore.Query.Sql;
|
using Microsoft.EntityFrameworkCore.Query.Sql;
|
||||||
|
@ -62,7 +55,7 @@ namespace ShardingCore.SqlServer
|
||||||
|
|
||||||
public static DbContextOptionsBuilder UseSharding(this DbContextOptionsBuilder optionsBuilder)
|
public static DbContextOptionsBuilder UseSharding(this DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
optionsBuilder.ReplaceService<IDbSetSource, ShardingDbSetSource>().ReplaceService<IAsyncQueryProvider, ShardingEntityQueryProvider>();
|
optionsBuilder.ReplaceService<IDbSetSource, ShardingDbSetSource>().ReplaceService<IQueryCompiler, ShardingQueryCompiler>();
|
||||||
return optionsBuilder;
|
return optionsBuilder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,4 +21,10 @@
|
||||||
<ProjectReference Include="..\ShardingCore\ShardingCore.csproj" />
|
<ProjectReference Include="..\ShardingCore\ShardingCore.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Extensions.Logging.Console">
|
||||||
|
<HintPath>C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\5.0.0\ref\net5.0\Microsoft.Extensions.Logging.Console.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.Console;
|
||||||
using ShardingCore.DbContexts.VirtualDbContexts;
|
using ShardingCore.DbContexts.VirtualDbContexts;
|
||||||
using ShardingCore.DbContexts.VirtualDbContexts.ShareDbContextOptionsProviders;
|
using ShardingCore.DbContexts.VirtualDbContexts.ShareDbContextOptionsProviders;
|
||||||
using ShardingCore.EFCores;
|
using ShardingCore.EFCores;
|
||||||
|
@ -26,25 +27,25 @@ namespace ShardingCore.SqlServer
|
||||||
*/
|
*/
|
||||||
public class SqlServerDbContextOptionsProvider : IDbContextOptionsProvider
|
public class SqlServerDbContextOptionsProvider : IDbContextOptionsProvider
|
||||||
{
|
{
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
|
||||||
private readonly IShardingCoreOptions _shardingCoreOptions;
|
private readonly IShardingCoreOptions _shardingCoreOptions;
|
||||||
|
public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder =>
|
||||||
|
{
|
||||||
|
builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole();
|
||||||
public SqlServerDbContextOptionsProvider(ILoggerFactory loggerFactory, IShardingCoreOptions shardingCoreOptions)
|
});
|
||||||
|
|
||||||
|
|
||||||
|
public SqlServerDbContextOptionsProvider(IShardingCoreOptions shardingCoreOptions)
|
||||||
{
|
{
|
||||||
_loggerFactory = loggerFactory;
|
|
||||||
_shardingCoreOptions = shardingCoreOptions;
|
_shardingCoreOptions = shardingCoreOptions;
|
||||||
}
|
}
|
||||||
public DbContextOptions GetDbContextOptions(DbConnection dbConnection)
|
public DbContextOptions GetDbContextOptions(DbConnection dbConnection)
|
||||||
{
|
{
|
||||||
Console.WriteLine("create new dbcontext options,dbconnection is new:"+(dbConnection==null));
|
|
||||||
|
|
||||||
var track = dbConnection != null;
|
var track = dbConnection != null;
|
||||||
var connection = dbConnection ?? GetSqlConnection();
|
var connection = dbConnection ?? GetSqlConnection();
|
||||||
var dbContextOptions = CreateDbContextOptionBuilder()
|
var dbContextOptions = CreateDbContextOptionBuilder()
|
||||||
.UseSqlServer(connection)
|
.UseSqlServer(connection)
|
||||||
.UseLoggerFactory(_loggerFactory)
|
.UseLoggerFactory(efLogger)
|
||||||
.IfDo(!track, o => o.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking))
|
.IfDo(!track, o => o.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking))
|
||||||
//.IfDo(isQuery,o=>o.ReplaceService<IQueryCompiler, ShardingQueryCompiler>())
|
//.IfDo(isQuery,o=>o.ReplaceService<IQueryCompiler, ShardingQueryCompiler>())
|
||||||
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
|
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using ShardingCore.Core.Internal.StreamMerge;
|
using ShardingCore.Core.Internal.StreamMerge;
|
||||||
using ShardingCore.Core.ShardingAccessors;
|
using ShardingCore.Core.ShardingAccessors;
|
||||||
|
@ -7,20 +8,21 @@ using ShardingCore.Core.VirtualTables;
|
||||||
using ShardingCore.DbContexts;
|
using ShardingCore.DbContexts;
|
||||||
using ShardingCore.DbContexts.Abstractions;
|
using ShardingCore.DbContexts.Abstractions;
|
||||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||||
|
using ShardingCore.Sharding.Abstractions;
|
||||||
using ShardingCore.Sharding.Enumerators;
|
using ShardingCore.Sharding.Enumerators;
|
||||||
using ShardingCore.TableCreator;
|
using ShardingCore.TableCreator;
|
||||||
|
|
||||||
namespace ShardingCore
|
namespace ShardingCore
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* @Author: xjm
|
* @Author: xjm
|
||||||
* @Description:
|
* @Description:
|
||||||
* @Date: Thursday, 28 January 2021 13:32:18
|
* @Date: Thursday, 28 January 2021 13:32:18
|
||||||
* @Email: 326308290@qq.com
|
* @Email: 326308290@qq.com
|
||||||
*/
|
*/
|
||||||
public static class DIExtension
|
public static class DIExtension
|
||||||
{
|
{
|
||||||
|
|
||||||
public static IServiceCollection AddShardingCore(this IServiceCollection services)
|
public static IServiceCollection AddShardingCore(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IDbContextCreateFilterManager, DbContextCreateFilterManager>();
|
services.AddSingleton<IDbContextCreateFilterManager, DbContextCreateFilterManager>();
|
||||||
|
@ -39,5 +41,29 @@ namespace ShardingCore
|
||||||
services.AddSingleton<IShardingScopeFactory, ShardingScopeFactory>();
|
services.AddSingleton<IShardingScopeFactory, ShardingScopeFactory>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
throw new ArgumentNullException($"AddScfSqlServerProvider 参数不能为空:{nameof(configure)}");
|
||||||
|
var shardingConfig = new ShardingConfig<TActualDbContext>();
|
||||||
|
configure?.Invoke(shardingConfig);
|
||||||
|
services.AddSingleton(shardingConfig);
|
||||||
|
|
||||||
|
services.AddDbContext<TShardingDbContext>(optionsAction, contextLifetime, optionsLifetime);
|
||||||
|
services.AddShardingCore();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
services.AddSingleton<IShardingBootstrapper, ShardingBootstrapper>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,15 +1,26 @@
|
||||||
#if !EFCORE2
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Internal;
|
||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Query;
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||||
using Microsoft.EntityFrameworkCore.Storage;
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using ShardingCore.Core.ShardingAccessors;
|
using ShardingCore.Core.ShardingAccessors;
|
||||||
|
using ShardingCore.Exceptions;
|
||||||
|
using ShardingCore.Extensions;
|
||||||
|
using ShardingCore.Sharding;
|
||||||
|
using ShardingCore.Sharding.Abstractions;
|
||||||
|
using ShardingCore.Sharding.Enumerators;
|
||||||
|
using ShardingCore.Sharding.StreamMergeEngines;
|
||||||
|
|
||||||
namespace ShardingCore.EFCores
|
namespace ShardingCore.EFCores
|
||||||
{
|
{
|
||||||
|
@ -19,281 +30,132 @@ namespace ShardingCore.EFCores
|
||||||
* Author:xuejiaming
|
* Author:xuejiaming
|
||||||
* Created: 2020/12/28 13:58:46
|
* Created: 2020/12/28 13:58:46
|
||||||
**/
|
**/
|
||||||
public class ShardingQueryCompiler: QueryCompiler
|
public class ShardingQueryCompiler: IQueryCompiler
|
||||||
{
|
{
|
||||||
private readonly IQueryContextFactory _queryContextFactory;
|
private readonly IQueryContextFactory _queryContextFactory;
|
||||||
private readonly IDatabase _database;
|
private readonly IDatabase _database;
|
||||||
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _logger;
|
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _logger;
|
||||||
private readonly IModel _model;
|
private readonly ICurrentDbContext _currentContext;
|
||||||
|
private readonly IModel _model;
|
||||||
|
private readonly IStreamMergeContextFactory _streamMergeContextFactory;
|
||||||
|
|
||||||
public ShardingQueryCompiler(IQueryContextFactory queryContextFactory, ICompiledQueryCache compiledQueryCache, ICompiledQueryCacheKeyGenerator compiledQueryCacheKeyGenerator, IDatabase database, IDiagnosticsLogger<DbLoggerCategory.Query> logger, ICurrentDbContext currentContext, IEvaluatableExpressionFilter evaluatableExpressionFilter, IModel model) : base(queryContextFactory, compiledQueryCache, compiledQueryCacheKeyGenerator, database, logger, currentContext, evaluatableExpressionFilter, model)
|
public ShardingQueryCompiler(IQueryContextFactory queryContextFactory, ICompiledQueryCache compiledQueryCache, ICompiledQueryCacheKeyGenerator compiledQueryCacheKeyGenerator, IDatabase database, IDiagnosticsLogger<DbLoggerCategory.Query> logger, ICurrentDbContext currentContext, IEvaluatableExpressionFilter evaluatableExpressionFilter, IModel model)
|
||||||
{
|
{
|
||||||
_queryContextFactory = queryContextFactory;
|
_queryContextFactory = queryContextFactory;
|
||||||
_database = database;
|
_database = database;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_model = model;
|
_currentContext = currentContext;
|
||||||
}
|
_model = model;
|
||||||
|
_streamMergeContextFactory = ShardingContainer.GetService<IStreamMergeContextFactory>();
|
||||||
public override TResult Execute<TResult>(Expression query)
|
}
|
||||||
{
|
|
||||||
var shardingAccessor = ShardingContainer.Services.GetService<IShardingAccessor>();
|
|
||||||
if (shardingAccessor?.ShardingContext != null)
|
|
||||||
{
|
|
||||||
return ShardingExecute<TResult>(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.Execute<TResult>(query);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// use no compiler
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TResult"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private TResult ShardingExecute<TResult>(Expression query)
|
|
||||||
{
|
|
||||||
var queryContext = _queryContextFactory.Create();
|
|
||||||
|
|
||||||
query = ExtractParameters(query, queryContext, _logger);
|
|
||||||
|
|
||||||
var compiledQuery
|
|
||||||
= CompileQueryCore<TResult>(_database, query, _model, false);
|
|
||||||
|
|
||||||
return compiledQuery(queryContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override TResult ExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken = new CancellationToken())
|
|
||||||
{
|
|
||||||
var shardingAccessor = ShardingContainer.Services.GetService<IShardingAccessor>();
|
|
||||||
if (shardingAccessor?.ShardingContext != null)
|
|
||||||
{
|
|
||||||
var result= ShardingExecuteAsync<TResult>(query, cancellationToken);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.ExecuteAsync<TResult>(query, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TResult ShardingExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken = new CancellationToken())
|
|
||||||
{
|
|
||||||
var queryContext = _queryContextFactory.Create();
|
|
||||||
|
|
||||||
queryContext.CancellationToken = cancellationToken;
|
|
||||||
|
|
||||||
query = ExtractParameters(query, queryContext, _logger);
|
|
||||||
|
|
||||||
var compiledQuery
|
|
||||||
= CompileQueryCore<TResult>(_database, query, _model, true);
|
|
||||||
|
|
||||||
return compiledQuery(queryContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if EFCORE2
|
private ICurrentDbContext GetCurrentDbContext()
|
||||||
using System;
|
{
|
||||||
using System.Collections.Generic;
|
return _currentContext;
|
||||||
using System.Linq;
|
}
|
||||||
using System.Linq.Expressions;
|
public TResult Execute<TResult>(Expression query)
|
||||||
using System.Reflection;
|
{
|
||||||
using System.Runtime.ExceptionServices;
|
throw new NotImplementedException();
|
||||||
using System.Threading;
|
}
|
||||||
using System.Threading.Tasks;
|
|
||||||
using ShardingCore;
|
|
||||||
using ShardingCore.Core.ShardingAccessors;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
||||||
using Microsoft.EntityFrameworkCore.Internal;
|
|
||||||
using Microsoft.EntityFrameworkCore.Query;
|
|
||||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Remotion.Linq.Clauses.StreamedData;
|
|
||||||
|
|
||||||
namespace ShardingCore.EFCores
|
public TResult ExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
/**
|
var currentDbContext = GetCurrentDbContext().Context;
|
||||||
* 描述:
|
|
||||||
*
|
|
||||||
* Author:xuejiaming
|
|
||||||
* Created: 2020/12/28 13:58:46
|
|
||||||
**/
|
|
||||||
public class ShardingQueryCompiler: QueryCompiler
|
|
||||||
{
|
|
||||||
|
|
||||||
private static MethodInfo CompileQueryMethod { get; }
|
|
||||||
= typeof(IDatabase).GetTypeInfo()
|
|
||||||
.GetDeclaredMethod(nameof(IDatabase.CompileQuery));
|
|
||||||
private readonly IQueryContextFactory _queryContextFactory;
|
|
||||||
private readonly ICompiledQueryCache _compiledQueryCache;
|
|
||||||
private readonly ICompiledQueryCacheKeyGenerator _compiledQueryCacheKeyGenerator;
|
|
||||||
private readonly IDatabase _database;
|
|
||||||
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _logger;
|
|
||||||
private readonly IQueryModelGenerator _queryModelGenerator;
|
|
||||||
private readonly Type _contextType;
|
|
||||||
|
|
||||||
public ShardingQueryCompiler(IQueryContextFactory queryContextFactory, ICompiledQueryCache compiledQueryCache, ICompiledQueryCacheKeyGenerator compiledQueryCacheKeyGenerator, IDatabase database, IDiagnosticsLogger<DbLoggerCategory.Query> logger, ICurrentDbContext currentContext, IQueryModelGenerator queryModelGenerator) : base(queryContextFactory, compiledQueryCache, compiledQueryCacheKeyGenerator, database, logger, currentContext, queryModelGenerator)
|
if (currentDbContext is IShardingDbContext shardingDbContext)
|
||||||
{
|
|
||||||
_queryContextFactory = queryContextFactory;
|
|
||||||
_compiledQueryCache = compiledQueryCache;
|
|
||||||
_compiledQueryCacheKeyGenerator = compiledQueryCacheKeyGenerator;
|
|
||||||
_database = database;
|
|
||||||
_logger = logger;
|
|
||||||
_queryModelGenerator = queryModelGenerator;
|
|
||||||
_contextType = currentContext.Context.GetType();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override TResult Execute<TResult>(Expression query)
|
|
||||||
{
|
|
||||||
|
|
||||||
var shardingAccessor = ShardingContainer.Services.GetService<IShardingAccessor>();
|
|
||||||
if (shardingAccessor?.ShardingContext != null)
|
|
||||||
{
|
|
||||||
return ShardingExecute<TResult>(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.Execute<TResult>(query);
|
|
||||||
}
|
|
||||||
private TResult ShardingExecute<TResult>(Expression query)
|
|
||||||
{
|
|
||||||
var queryContext = _queryContextFactory.Create();
|
|
||||||
|
|
||||||
query = _queryModelGenerator.ExtractParameters(_logger, query, queryContext);
|
|
||||||
|
|
||||||
var compiledQuery
|
|
||||||
= CompileQueryCore<TResult>(query, _queryModelGenerator, _database, _logger, _contextType);
|
|
||||||
|
|
||||||
|
|
||||||
return compiledQuery(queryContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression query)
|
|
||||||
{
|
|
||||||
|
|
||||||
var shardingAccessor = ShardingContainer.Services.GetService<IShardingAccessor>();
|
|
||||||
if (shardingAccessor?.ShardingContext != null)
|
|
||||||
{
|
|
||||||
return ShardingExecuteEnumerableAsync<TResult>(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.ExecuteAsync<TResult>(query);
|
|
||||||
}
|
|
||||||
private IAsyncEnumerable<TResult> ShardingExecuteEnumerableAsync<TResult>(Expression query)
|
|
||||||
{
|
|
||||||
var queryContext = _queryContextFactory.Create();
|
|
||||||
|
|
||||||
query = _queryModelGenerator.ExtractParameters(_logger, query, queryContext);
|
|
||||||
|
|
||||||
return CompileAsyncQueryCore<TResult>(query,_queryModelGenerator, _database)(queryContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Task<TResult> ExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
|
|
||||||
var shardingAccessor = ShardingContainer.Services.GetService<IShardingAccessor>();
|
|
||||||
if (shardingAccessor?.ShardingContext != null)
|
|
||||||
{
|
{
|
||||||
return ShardingExecuteAsync<TResult>(query, cancellationToken);
|
if (typeof(TResult).HasImplementedRawGeneric(typeof(IAsyncEnumerable<>)))
|
||||||
|
{
|
||||||
|
|
||||||
|
var queryEntityType = typeof(TResult).GetGenericArguments()[0];
|
||||||
|
Type type = typeof(EnumerableQuery<>);
|
||||||
|
type = type.MakeGenericType(queryEntityType);
|
||||||
|
var queryable = Activator.CreateInstance(type, query);
|
||||||
|
|
||||||
|
var streamMergeContextMethod = _streamMergeContextFactory.GetType().GetMethod("Create");
|
||||||
|
if (streamMergeContextMethod == null)
|
||||||
|
throw new ShardingCoreException("cant found IStreamMergeContextFactory method [Create]");
|
||||||
|
var streamMergeContext = streamMergeContextMethod.MakeGenericMethod(new Type[] { queryEntityType }).Invoke(_streamMergeContextFactory, new[] { queryable,shardingDbContext });
|
||||||
|
|
||||||
|
|
||||||
|
Type streamMergeEngineType = typeof(AsyncEnumerableStreamMergeEngine<>);
|
||||||
|
streamMergeEngineType = streamMergeEngineType.MakeGenericType(queryEntityType);
|
||||||
|
return (TResult)Activator.CreateInstance(streamMergeEngineType, streamMergeContext);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(TResult).HasImplementedRawGeneric(typeof(Task<>)))
|
||||||
|
{
|
||||||
|
if (query is MethodCallExpression methodCallExpression)
|
||||||
|
{
|
||||||
|
|
||||||
|
var queryEntityType = query.Type;
|
||||||
|
Type type = typeof(IQueryable<>);
|
||||||
|
type = type.MakeGenericType(queryEntityType);
|
||||||
|
var rootQuery = methodCallExpression.Arguments.FirstOrDefault(o=>o.Type==type);
|
||||||
|
|
||||||
|
switch (methodCallExpression.Method.Name)
|
||||||
|
{
|
||||||
|
|
||||||
|
case nameof(Enumerable.FirstOrDefault): return FirstOrDefaultAsync<TResult>(shardingDbContext, queryEntityType, rootQuery, queryable =>
|
||||||
|
(TResult)(typeof(ShardingEntityFrameworkQueryableExtensions).GetMethod(nameof(ShardingEntityFrameworkQueryableExtensions.ShardingFirstOrDefaultAsync))
|
||||||
|
.MakeGenericMethod(new Type[]
|
||||||
|
{
|
||||||
|
queryEntityType
|
||||||
|
}).Invoke(null, new object[] { queryable, cancellationToken })), cancellationToken);
|
||||||
|
|
||||||
|
|
||||||
|
//, BindingFlags.Static | BindingFlags.Public);.InvokeMember(, System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Static
|
||||||
|
//| System.Reflection.BindingFlags.Public, null, null, new object[] { queryable, cancellationToken }), cancellationToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
throw new ShardingCoreException($"db context operator not support query expression:[{query}] result type:[{typeof(TResult).FullName}]");
|
||||||
|
//IQueryable<TResult> queryable = new EnumerableQuery<TResult>(expression);
|
||||||
|
//var streamMergeContext = _streamMergeContextFactory.Create(queryable, shardingDbContext);
|
||||||
|
|
||||||
|
//var streamMergeEngine = AsyncEnumerableStreamMergeEngine<TResult>.Create<TResult>(streamMergeContext);
|
||||||
|
//return streamMergeEngine.GetAsyncEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.ExecuteAsync<TResult>(query, cancellationToken);
|
throw new ShardingCoreException("db context operator is not IShardingDbContext");
|
||||||
}
|
}
|
||||||
private Task<TResult> ShardingExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var queryContext = _queryContextFactory.Create();
|
|
||||||
|
|
||||||
queryContext.CancellationToken = cancellationToken;
|
|
||||||
|
|
||||||
query = _queryModelGenerator.ExtractParameters(_logger, query, queryContext);
|
private TResult FirstOrDefaultAsync<TResult>(IShardingDbContext shardingDbContext,Type queryEntityType, Expression query,Func<IQueryable, TResult> efQuery, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
|
||||||
var compiledQuery = CompileAsyncQueryCore<TResult>(query,_queryModelGenerator, _database);
|
Type type = typeof(EnumerableQuery<>);
|
||||||
|
type = type.MakeGenericType(queryEntityType);
|
||||||
|
var queryable = Activator.CreateInstance(type, query);
|
||||||
|
|
||||||
return ExecuteSingletonAsyncQuery(queryContext, compiledQuery, _logger, _contextType);
|
var streamMergeContextMethod = _streamMergeContextFactory.GetType().GetMethod("Create");
|
||||||
}
|
if (streamMergeContextMethod == null)
|
||||||
|
throw new ShardingCoreException("cant found IStreamMergeContextFactory method [Create]");
|
||||||
private static Func<QueryContext, TResult> CompileQueryCore<TResult>(
|
var streamMergeContext = streamMergeContextMethod.MakeGenericMethod(new Type[] { queryEntityType }).Invoke(_streamMergeContextFactory, new object[] { queryable, shardingDbContext });
|
||||||
Expression query,
|
|
||||||
IQueryModelGenerator queryModelGenerator,
|
|
||||||
IDatabase database,
|
|
||||||
IDiagnosticsLogger<DbLoggerCategory.Query> logger,
|
|
||||||
Type contextType)
|
|
||||||
{
|
|
||||||
var queryModel = queryModelGenerator.ParseQuery(query);
|
|
||||||
|
|
||||||
var resultItemType
|
Type streamMergeEngineType = typeof(FirstOrDefaultAsyncInMemoryAsyncStreamMergeEngine<>);
|
||||||
= (queryModel.GetOutputDataInfo()
|
streamMergeEngineType = streamMergeEngineType.MakeGenericType(queryEntityType);
|
||||||
as StreamedSequenceInfo)?.ResultItemType
|
var streamEngine = Activator.CreateInstance(streamMergeEngineType, streamMergeContext);
|
||||||
?? typeof(TResult);
|
var streamEngineMethod = streamMergeEngineType.GetMethod("ExecuteAsync");
|
||||||
|
if (streamEngineMethod == null)
|
||||||
|
throw new ShardingCoreException("cant found InMemoryAsyncStreamMergeEngine method [ExecuteAsync]");
|
||||||
|
return (TResult)streamEngineMethod.Invoke(streamEngine, new object[] { efQuery, cancellationToken });
|
||||||
|
}
|
||||||
|
|
||||||
if (resultItemType == typeof(TResult))
|
public Func<QueryContext, TResult> CreateCompiledQuery<TResult>(Expression query)
|
||||||
{
|
{
|
||||||
var compiledQuery = database.CompileQuery<TResult>(queryModel);
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
return qc =>
|
public Func<QueryContext, TResult> CreateCompiledAsyncQuery<TResult>(Expression query)
|
||||||
{
|
{
|
||||||
try
|
throw new NotImplementedException();
|
||||||
{
|
}
|
||||||
return compiledQuery(qc).First();
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
logger.QueryIterationFailed(contextType, exception);
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (Func<QueryContext, TResult>)CompileQueryMethod
|
|
||||||
.MakeGenericMethod(resultItemType)
|
|
||||||
.Invoke(database, new object[] { queryModel });
|
|
||||||
}
|
|
||||||
catch (TargetInvocationException e)
|
|
||||||
{
|
|
||||||
ExceptionDispatchInfo.Capture(e.InnerException).Throw();
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static Func<QueryContext, IAsyncEnumerable<TResult>> CompileAsyncQueryCore<TResult>(
|
|
||||||
Expression query,
|
|
||||||
IQueryModelGenerator queryModelGenerator,
|
|
||||||
IDatabase database)
|
|
||||||
{
|
|
||||||
var queryModel = queryModelGenerator.ParseQuery(query);
|
|
||||||
|
|
||||||
return database.CompileAsyncQuery<TResult>(queryModel);
|
|
||||||
}
|
|
||||||
private static async Task<TResult> ExecuteSingletonAsyncQuery<TResult>(
|
|
||||||
QueryContext queryContext,
|
|
||||||
Func<QueryContext, IAsyncEnumerable<TResult>> compiledQuery,
|
|
||||||
IDiagnosticsLogger<DbLoggerCategory.Query> logger,
|
|
||||||
Type contextType)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var asyncEnumerable = compiledQuery(queryContext);
|
|
||||||
|
|
||||||
using (var asyncEnumerator = asyncEnumerable.GetEnumerator())
|
|
||||||
{
|
|
||||||
await asyncEnumerator.MoveNext(queryContext.CancellationToken);
|
|
||||||
|
|
||||||
return asyncEnumerator.Current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
logger.QueryIterationFailed(contextType, exception);
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ShardingCore.Extensions
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* @Author: xjm
|
||||||
|
* @Description:
|
||||||
|
* @Date: 2021/8/17 9:43:00
|
||||||
|
* @Ver: 1.0
|
||||||
|
* @Email: 326308290@qq.com
|
||||||
|
*/
|
||||||
|
public static class GenericExtension
|
||||||
|
{
|
||||||
|
public static Type[] GetGenericArguments(this Type type, Type genericType)
|
||||||
|
{
|
||||||
|
return type.GetInterfaces() //取类型的接口
|
||||||
|
.Where(i => IsGenericType(i)) //筛选出相应泛型接口
|
||||||
|
.SelectMany(i => i.GetGenericArguments()) //选择所有接口的泛型参数
|
||||||
|
.ToArray(); //ToArray
|
||||||
|
|
||||||
|
bool IsGenericType(Type type1)
|
||||||
|
=> type1.IsGenericType && type1.GetGenericTypeDefinition() == genericType;
|
||||||
|
}
|
||||||
|
public static bool HasImplementedRawGeneric(this Type type, Type generic)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||||
|
|
||||||
|
if (generic == null) throw new ArgumentNullException(nameof(generic));
|
||||||
|
|
||||||
|
// 测试接口。
|
||||||
|
|
||||||
|
var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
|
||||||
|
|
||||||
|
if (isTheRawGenericType) return true;
|
||||||
|
|
||||||
|
// 测试类型。
|
||||||
|
|
||||||
|
while (type != null && type != typeof(object))
|
||||||
|
|
||||||
|
{
|
||||||
|
isTheRawGenericType = IsTheRawGenericType(type);
|
||||||
|
|
||||||
|
if (isTheRawGenericType) return true;
|
||||||
|
|
||||||
|
type = type.BaseType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有找到任何匹配的接口或类型。
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 测试某个类型是否是指定的原始接口。
|
||||||
|
|
||||||
|
bool IsTheRawGenericType(Type test)
|
||||||
|
|
||||||
|
=> generic == (test.IsGenericType ? test.GetGenericTypeDefinition() : test);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,8 @@ namespace ShardingCore.Extensions
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static IQueryable<T> RemoveTake<T>(this IQueryable<T> source)
|
internal static IQueryable<T> RemoveTake<T>(this IQueryable<T> source)
|
||||||
{
|
{
|
||||||
return (IQueryable<T>) source.Provider.CreateQuery(new RemoveTakeVisitor().Visit(source.Expression));
|
var expression = new RemoveTakeVisitor().Visit(source.Expression);
|
||||||
|
return (IQueryable<T>) source.Provider.CreateQuery(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
|
|
||||||
|
namespace ShardingCore.Extensions
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* @Author: xjm
|
||||||
|
* @Description:
|
||||||
|
* @Date: 2021/8/17 15:51:32
|
||||||
|
* @Ver: 1.0
|
||||||
|
* @Email: 326308290@qq.com
|
||||||
|
*/
|
||||||
|
internal static class ShardingEntityFrameworkQueryableExtensions
|
||||||
|
{
|
||||||
|
public static Task<TSource> ShardingFirstOrDefaultAsync<TSource>(
|
||||||
|
this IQueryable<TSource> source,
|
||||||
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
{
|
||||||
|
return EntityFrameworkQueryableExtensions.FirstOrDefaultAsync(source, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ShardingCore.Extensions
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* @Author: xjm
|
||||||
|
* @Description:
|
||||||
|
* @Date: 2021/8/17 21:42:37
|
||||||
|
* @Ver: 1.0
|
||||||
|
* @Email: 326308290@qq.com
|
||||||
|
*/
|
||||||
|
public static class ShardingQueryaleExtension
|
||||||
|
{
|
||||||
|
public static IQueryable<TElement> AsShardingQueryable<TElement>(
|
||||||
|
this IEnumerable<TElement> source)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException(nameof(source));
|
||||||
|
return source is IQueryable<TElement> queryable ? queryable : (IQueryable<TElement>)new EnumerableQuery<TElement>(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -183,5 +183,13 @@ namespace ShardingCore.Helpers
|
||||||
var func = outer.Compile();
|
var func = outer.Compile();
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//public static TResult ShardingExecuteAsyncEnumerabe(Expression expression)
|
||||||
|
//{
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,10 +8,13 @@ using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Storage;
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using ShardingCore.Core;
|
using ShardingCore.Core;
|
||||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||||
using ShardingCore.Core.VirtualTables;
|
using ShardingCore.Core.VirtualTables;
|
||||||
using ShardingCore.DbContexts;
|
using ShardingCore.DbContexts;
|
||||||
|
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||||
|
using ShardingCore.EFCores;
|
||||||
using ShardingCore.Extensions;
|
using ShardingCore.Extensions;
|
||||||
using ShardingCore.Sharding.Abstractions;
|
using ShardingCore.Sharding.Abstractions;
|
||||||
|
|
||||||
|
@ -27,28 +30,67 @@ 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
|
public abstract class AbstractShardingDbContext<T> : DbContext, IShardingDbContext 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 DbContextOptions<T> _dbContextOptions;
|
||||||
|
|
||||||
|
private readonly object CREATELOCK = new object();
|
||||||
|
|
||||||
public AbstractShardingDbContext(DbContextOptions options) : base(options)
|
public AbstractShardingDbContext(DbContextOptions options) : base(options)
|
||||||
{
|
{
|
||||||
_shardingDbContextFactory = ShardingContainer.GetService<IShardingDbContextFactory>();
|
_shardingDbContextFactory = ShardingContainer.GetService<IShardingDbContextFactory>();
|
||||||
|
_virtualTableManager = ShardingContainer.GetService<IVirtualTableManager>();
|
||||||
|
_shardingConfig = ShardingContainer.GetService<ShardingConfig<T>>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type ActualDbContextType => typeof(T);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private DbContextOptionsBuilder<T> CreateDbContextOptionBuilder()
|
||||||
|
{
|
||||||
|
Type type = typeof(DbContextOptionsBuilder<>);
|
||||||
|
type = type.MakeGenericType(ActualDbContextType);
|
||||||
|
return (DbContextOptionsBuilder<T>)Activator.CreateInstance(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DbContextOptions<T> GetDbContextOptions()
|
||||||
|
{
|
||||||
|
var dbContextOptionBuilder = CreateDbContextOptionBuilder();
|
||||||
|
var dbConnection = Database.GetDbConnection();
|
||||||
|
dbConnection.Open();
|
||||||
|
return _shardingConfig.ShardingDbContextOptionsCreator(dbConnection, dbContextOptionBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShardingDbContextOptions CreateSameShardingDbContextOptions(string tail)
|
||||||
|
{
|
||||||
|
if (_dbContextOptions == null)
|
||||||
|
{
|
||||||
|
lock (CREATELOCK)
|
||||||
|
{
|
||||||
|
if (_dbContextOptions == null)
|
||||||
|
{
|
||||||
|
_dbContextOptions = GetDbContextOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ShardingDbContextOptions(_dbContextOptions, tail);
|
||||||
|
}
|
||||||
|
|
||||||
public DbContext GetDbContext(bool track, string tail)
|
public DbContext GetDbContext(bool track, string tail)
|
||||||
{
|
{
|
||||||
if (!_dbContextCaches.TryGetValue(tail, out var dbContext))
|
if (!_dbContextCaches.TryGetValue(tail, out var dbContext))
|
||||||
{
|
{
|
||||||
dbContext = _shardingDbContextFactory.Create(track ? this.Database.GetDbConnection() : null, tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail); ;
|
dbContext = _shardingDbContextFactory.Create(CreateSameShardingDbContextOptions(tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail));
|
||||||
_dbContextCaches.TryAdd(tail, dbContext);
|
_dbContextCaches.TryAdd(tail, dbContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (IsOpenTransaction)
|
|
||||||
//{
|
|
||||||
// _dbTransaction.Use(dbContext);
|
|
||||||
//}
|
|
||||||
|
|
||||||
return dbContext;
|
return dbContext;
|
||||||
}
|
}
|
||||||
|
@ -338,7 +380,12 @@ namespace ShardingCore.Sharding
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (!isBeginTransaction)
|
if (!isBeginTransaction)
|
||||||
Database.CurrentTransaction.Dispose();
|
Database.CurrentTransaction?.Dispose();
|
||||||
|
|
||||||
|
foreach (var dbContextCache in _dbContextCaches)
|
||||||
|
{
|
||||||
|
dbContextCache.Value.Database.UseTransaction(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -368,7 +415,12 @@ namespace ShardingCore.Sharding
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (!isBeginTransaction)
|
if (!isBeginTransaction)
|
||||||
Database.CurrentTransaction.Dispose();
|
Database.CurrentTransaction?.Dispose();
|
||||||
|
|
||||||
|
foreach (var dbContextCache in _dbContextCaches)
|
||||||
|
{
|
||||||
|
dbContextCache.Value.Database.UseTransaction(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -390,15 +442,21 @@ namespace ShardingCore.Sharding
|
||||||
foreach (var dbContextCache in _dbContextCaches)
|
foreach (var dbContextCache in _dbContextCaches)
|
||||||
{
|
{
|
||||||
await dbContextCache.Value.Database.UseTransactionAsync(Database.CurrentTransaction.GetDbTransaction(), cancellationToken: cancellationToken);
|
await dbContextCache.Value.Database.UseTransactionAsync(Database.CurrentTransaction.GetDbTransaction(), cancellationToken: cancellationToken);
|
||||||
i +=await dbContextCache.Value.SaveChangesAsync(cancellationToken);
|
i += await dbContextCache.Value.SaveChangesAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
if (!isBeginTransaction)
|
if (!isBeginTransaction)
|
||||||
await Database.CurrentTransaction.CommitAsync(cancellationToken);
|
await Database.CurrentTransaction.CommitAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (!isBeginTransaction)
|
if (!isBeginTransaction) { }
|
||||||
|
if (Database.CurrentTransaction != null)
|
||||||
await Database.CurrentTransaction.DisposeAsync();
|
await Database.CurrentTransaction.DisposeAsync();
|
||||||
|
|
||||||
|
foreach (var dbContextCache in _dbContextCaches)
|
||||||
|
{
|
||||||
|
await dbContextCache.Value.Database.UseTransactionAsync(null, cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -420,7 +478,7 @@ namespace ShardingCore.Sharding
|
||||||
foreach (var dbContextCache in _dbContextCaches)
|
foreach (var dbContextCache in _dbContextCaches)
|
||||||
{
|
{
|
||||||
await dbContextCache.Value.Database.UseTransactionAsync(Database.CurrentTransaction.GetDbTransaction(), cancellationToken: cancellationToken);
|
await dbContextCache.Value.Database.UseTransactionAsync(Database.CurrentTransaction.GetDbTransaction(), cancellationToken: cancellationToken);
|
||||||
i += await dbContextCache.Value.SaveChangesAsync(acceptAllChangesOnSuccess,cancellationToken);
|
i += await dbContextCache.Value.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||||
}
|
}
|
||||||
if (!isBeginTransaction)
|
if (!isBeginTransaction)
|
||||||
await Database.CurrentTransaction.CommitAsync(cancellationToken);
|
await Database.CurrentTransaction.CommitAsync(cancellationToken);
|
||||||
|
@ -428,7 +486,13 @@ namespace ShardingCore.Sharding
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (!isBeginTransaction)
|
if (!isBeginTransaction)
|
||||||
await Database.CurrentTransaction.DisposeAsync();
|
if (Database.CurrentTransaction != null)
|
||||||
|
await Database.CurrentTransaction.DisposeAsync();
|
||||||
|
|
||||||
|
foreach (var dbContextCache in _dbContextCaches)
|
||||||
|
{
|
||||||
|
await dbContextCache.Value.Database.UseTransactionAsync(null, cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,10 @@ namespace ShardingCore.Sharding.Abstractions
|
||||||
*/
|
*/
|
||||||
public interface IShardingDbContext
|
public interface IShardingDbContext
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 真实的DbContext 类型
|
||||||
|
/// </summary>
|
||||||
|
Type ActualDbContextType { get;}
|
||||||
|
|
||||||
DbContext GetDbContext(bool track,string tail);
|
DbContext GetDbContext(bool track,string tail);
|
||||||
DbContext CreateGenericDbContext<T>(T entity) where T : class;
|
DbContext CreateGenericDbContext<T>(T entity) where T : class;
|
||||||
|
|
|
@ -13,6 +13,6 @@ namespace ShardingCore.Sharding.Abstractions
|
||||||
public interface IStreamMergeEngine<T>
|
public interface IStreamMergeEngine<T>
|
||||||
{
|
{
|
||||||
Task<IStreamMergeAsyncEnumerator<T>> GetAsyncEnumerator();
|
Task<IStreamMergeAsyncEnumerator<T>> GetAsyncEnumerator();
|
||||||
Task<IStreamMergeEnumerator<T>> GetEnumerator();
|
IStreamMergeEnumerator<T> GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,103 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using ShardingCore.Core.ShardingAccessors;
|
|
||||||
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
|
|
||||||
using ShardingCore.Exceptions;
|
|
||||||
using ShardingCore.Extensions;
|
|
||||||
using ShardingCore.Sharding.Abstractions;
|
|
||||||
using ShardingCore.Sharding.Enumerators;
|
|
||||||
using ShardingCore.Sharding.Enumerators.StreamMergeAsync;
|
|
||||||
|
|
||||||
namespace ShardingCore.Sharding
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* @Author: xjm
|
|
||||||
* @Description:
|
|
||||||
* @Date: Saturday, 14 August 2021 22:07:28
|
|
||||||
* @Email: 326308290@qq.com
|
|
||||||
*/
|
|
||||||
public class GenericStreamMergeEngine<T> : IStreamMergeEngine<T>,IDisposable
|
|
||||||
{
|
|
||||||
|
|
||||||
private readonly StreamMergeContext<T> _mergeContext;
|
|
||||||
private readonly ICollection<DbContext> _parallelDbContexts;
|
|
||||||
|
|
||||||
public GenericStreamMergeEngine(StreamMergeContext<T> mergeContext)
|
|
||||||
{
|
|
||||||
_mergeContext = mergeContext;
|
|
||||||
_parallelDbContexts = new LinkedList<DbContext>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IStreamMergeEngine<T> Create<T>(StreamMergeContext<T> mergeContext)
|
|
||||||
{
|
|
||||||
return new GenericStreamMergeEngine<T>(mergeContext);
|
|
||||||
}
|
|
||||||
public async Task<IStreamMergeAsyncEnumerator<T>> GetAsyncEnumerator()
|
|
||||||
{
|
|
||||||
var tableResult = _mergeContext.GetRouteResults();
|
|
||||||
var enumeratorTasks = tableResult.Select(routeResult =>
|
|
||||||
{
|
|
||||||
if (routeResult.ReplaceTables.Count > 1)
|
|
||||||
throw new ShardingCoreException("route found more than 1 table name s");
|
|
||||||
var tail = string.Empty;
|
|
||||||
if (routeResult.ReplaceTables.Count == 1)
|
|
||||||
tail = routeResult.ReplaceTables.First().Tail;
|
|
||||||
|
|
||||||
return Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
using (var scope = _mergeContext.CreateScope())
|
|
||||||
{
|
|
||||||
var shardingContext = ShardingContext.Create(routeResult);
|
|
||||||
scope.ShardingAccessor.ShardingContext = shardingContext;
|
|
||||||
|
|
||||||
var shardingDbContext = _mergeContext.CreateDbContext(tail);
|
|
||||||
_parallelDbContexts.Add(shardingDbContext);
|
|
||||||
var newQueryable = (IQueryable<T>) _mergeContext.GetReWriteQueryable()
|
|
||||||
.ReplaceDbContextQueryable(shardingDbContext);
|
|
||||||
|
|
||||||
var asyncEnumerator = await GetAsyncEnumerator(newQueryable);
|
|
||||||
return new StreamMergeAsyncEnumerator<T>(asyncEnumerator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).ToArray();
|
|
||||||
|
|
||||||
var streamEnumerators = await Task.WhenAll(enumeratorTasks);
|
|
||||||
if (_mergeContext.HasSkipTake())
|
|
||||||
return new PaginationStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
|
||||||
if (_mergeContext.HasGroupQuery())
|
|
||||||
return new MultiAggregateOrderStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
|
||||||
return new MultiOrderStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<IStreamMergeEnumerator<T>> GetEnumerator()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private async Task<IAsyncEnumerator<T>> GetAsyncEnumerator(IQueryable<T> newQueryable)
|
|
||||||
{
|
|
||||||
var enumator = newQueryable.AsAsyncEnumerable().GetAsyncEnumerator();
|
|
||||||
await enumator.MoveNextAsync();
|
|
||||||
return enumator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_parallelDbContexts.ForEach(o => o.Dispose());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +1,131 @@
|
||||||
using System;
|
//using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
//using System.Collections.Generic;
|
||||||
using System.Linq;
|
//using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq.Expressions;
|
//using System.Linq;
|
||||||
using System.Reflection;
|
//using System.Linq.Expressions;
|
||||||
using System.Threading;
|
//using System.Reflection;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
//using System.Threading;
|
||||||
using Microsoft.EntityFrameworkCore.Query;
|
//using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
//using Microsoft.EntityFrameworkCore.Query;
|
||||||
using ShardingCore.Extensions;
|
//using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||||
|
//using ShardingCore.Exceptions;
|
||||||
|
//using ShardingCore.Extensions;
|
||||||
|
//using ShardingCore.Sharding.Abstractions;
|
||||||
|
//using ShardingCore.Sharding.Enumerators;
|
||||||
|
|
||||||
namespace ShardingCore.Sharding.Query
|
//namespace ShardingCore.Sharding.Query
|
||||||
{
|
//{
|
||||||
/*
|
///*
|
||||||
* @Author: xjm
|
//* @Author: xjm
|
||||||
* @Description:
|
//* @Description:
|
||||||
* @Date: Saturday, 14 August 2021 14:25:27
|
//* @Date: Saturday, 14 August 2021 14:25:27
|
||||||
* @Email: 326308290@qq.com
|
//* @Email: 326308290@qq.com
|
||||||
*/
|
//*/
|
||||||
public class ShardingEntityQueryProvider: IAsyncQueryProvider
|
// public class ShardingEntityQueryProvider: IAsyncQueryProvider
|
||||||
{
|
// {
|
||||||
private static readonly MethodInfo _genericCreateQueryMethod
|
// private static readonly MethodInfo _genericCreateQueryMethod
|
||||||
= typeof(ShardingEntityQueryProvider).GetRuntimeMethods()
|
// = typeof(ShardingEntityQueryProvider).GetRuntimeMethods()
|
||||||
.Single(m => (m.Name == "CreateQuery") && m.IsGenericMethod);
|
// .Single(m => (m.Name == "CreateQuery") && m.IsGenericMethod);
|
||||||
|
|
||||||
private readonly MethodInfo _genericExecuteMethod;
|
// private readonly MethodInfo _genericExecuteMethod;
|
||||||
|
|
||||||
private readonly IQueryCompiler _queryCompiler;
|
// private readonly IQueryCompiler _queryCompiler;
|
||||||
private readonly ICurrentDbContext _currentDbContext;
|
// private readonly ICurrentDbContext _currentDbContext;
|
||||||
|
// private readonly IStreamMergeContextFactory _streamMergeContextFactory;
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
// /// any release. You should only use it directly in your code with extreme caution and knowing that
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public ShardingEntityQueryProvider(IQueryCompiler queryCompiler,ICurrentDbContext currentDbContext)
|
// public ShardingEntityQueryProvider(IQueryCompiler queryCompiler,ICurrentDbContext currentDbContext)
|
||||||
{
|
// {
|
||||||
_queryCompiler = queryCompiler;
|
// _queryCompiler = queryCompiler;
|
||||||
_currentDbContext = currentDbContext;
|
// _currentDbContext = currentDbContext;
|
||||||
_genericExecuteMethod = queryCompiler.GetType()
|
// _genericExecuteMethod = queryCompiler.GetType()
|
||||||
.GetRuntimeMethods()
|
// .GetRuntimeMethods()
|
||||||
.Single(m => (m.Name == "Execute") && m.IsGenericMethod);
|
// .Single(m => (m.Name == "Execute") && m.IsGenericMethod);
|
||||||
}
|
// _streamMergeContextFactory = ShardingContainer.GetService<IStreamMergeContextFactory>();
|
||||||
|
// }
|
||||||
|
|
||||||
public ICurrentDbContext GetCurrentDbContext()
|
// public ICurrentDbContext GetCurrentDbContext()
|
||||||
{
|
// {
|
||||||
return _currentDbContext;
|
// return _currentDbContext;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
// /// any release. You should only use it directly in your code with extreme caution and knowing that
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public virtual IQueryable<TElement> CreateQuery<TElement>(Expression expression)
|
// public virtual IQueryable<TElement> CreateQuery<TElement>(Expression expression)
|
||||||
=> new ShardingEntityQueryable<TElement>(this, expression);
|
// => new ShardingEntityQueryable<TElement>(this, expression);
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
// /// any release. You should only use it directly in your code with extreme caution and knowing that
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public virtual IQueryable CreateQuery(Expression expression)
|
// public virtual IQueryable CreateQuery(Expression expression)
|
||||||
=> (IQueryable)_genericCreateQueryMethod
|
// => (IQueryable)_genericCreateQueryMethod
|
||||||
.MakeGenericMethod(expression.Type.GetSequenceType())
|
// .MakeGenericMethod(expression.Type.GetSequenceType())
|
||||||
.Invoke(this, new object[] { expression });
|
// .Invoke(this, new object[] { expression });
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
// /// any release. You should only use it directly in your code with extreme caution and knowing that
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public virtual TResult Execute<TResult>(Expression expression)
|
// public virtual TResult Execute<TResult>(Expression expression)
|
||||||
=> throw new NotSupportedException();
|
// => throw new NotSupportedException();
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
// /// any release. You should only use it directly in your code with extreme caution and knowing that
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public virtual object Execute(Expression expression)
|
// public virtual object Execute(Expression expression)
|
||||||
=> throw new NotSupportedException();
|
// => throw new NotSupportedException();
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
// /// any release. You should only use it directly in your code with extreme caution and knowing that
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public virtual TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = default)
|
// public virtual TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = default)
|
||||||
=> throw new NotSupportedException();
|
// {
|
||||||
}
|
// var currentDbContext = GetCurrentDbContext();
|
||||||
}
|
|
||||||
|
// if (currentDbContext is IShardingDbContext shardingDbContext)
|
||||||
|
// {
|
||||||
|
// if (typeof(TResult).HasImplementedRawGeneric(typeof(IAsyncEnumerable<>)))
|
||||||
|
// {
|
||||||
|
// var constructors
|
||||||
|
// = typeof(EnumerableQuery<>).GetTypeInfo().DeclaredConstructors
|
||||||
|
// .Where(c => !c.IsStatic && c.IsPublic)
|
||||||
|
// .ToArray();
|
||||||
|
|
||||||
|
// var parameters = constructors[0].GetParameters();
|
||||||
|
// var parameterType = parameters[0].ParameterType;
|
||||||
|
// Type type = typeof(EnumerableQuery<>);
|
||||||
|
// type = type.MakeGenericType(ActualDbContextType);
|
||||||
|
// Activator.CreateInstance(type);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// IQueryable<TResult> queryable = new EnumerableQuery<TResult>(expression);
|
||||||
|
// var streamMergeContext = _streamMergeContextFactory.Create(queryable, shardingDbContext);
|
||||||
|
|
||||||
|
// var streamMergeEngine = AsyncEnumerableStreamMergeEngine<TResult>.Create<TResult>(streamMergeContext);
|
||||||
|
// return streamMergeEngine.GetAsyncEnumerator();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// throw new ShardingCoreException("db context is not IShardingDbContext");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
@ -16,19 +16,19 @@ using ShardingCore.Sharding.Enumerators;
|
||||||
|
|
||||||
namespace ShardingCore.Sharding.Query
|
namespace ShardingCore.Sharding.Query
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* @Author: xjm
|
* @Author: xjm
|
||||||
* @Description:
|
* @Description:
|
||||||
* @Date: Saturday, 14 August 2021 14:17:30
|
* @Date: Saturday, 14 August 2021 14:17:30
|
||||||
* @Email: 326308290@qq.com
|
* @Email: 326308290@qq.com
|
||||||
*/
|
*/
|
||||||
public class ShardingEntityQueryable<TResult>: IOrderedQueryable<TResult>,
|
public class ShardingEntityQueryable<TResult> : IOrderedQueryable<TResult>,
|
||||||
IAsyncEnumerable<TResult>,
|
IAsyncEnumerable<TResult>,
|
||||||
IListSource
|
IListSource
|
||||||
{
|
{
|
||||||
private readonly IAsyncQueryProvider _queryProvider;
|
private readonly IAsyncQueryProvider _queryProvider;
|
||||||
|
|
||||||
private readonly DbContext _dbContext;
|
//private readonly DbContext _dbContext;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||||
|
@ -36,7 +36,7 @@ namespace ShardingCore.Sharding.Query
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ShardingEntityQueryable(IAsyncQueryProvider queryProvider,IEntityType entityType)
|
public ShardingEntityQueryable(IAsyncQueryProvider queryProvider, IEntityType entityType)
|
||||||
: this(queryProvider, new QueryRootExpression(queryProvider, entityType))
|
: this(queryProvider, new QueryRootExpression(queryProvider, entityType))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -51,10 +51,10 @@ namespace ShardingCore.Sharding.Query
|
||||||
{
|
{
|
||||||
Check.NotNull(queryProvider, nameof(queryProvider));
|
Check.NotNull(queryProvider, nameof(queryProvider));
|
||||||
Check.NotNull(expression, nameof(expression));
|
Check.NotNull(expression, nameof(expression));
|
||||||
if (queryProvider is ShardingEntityQueryProvider shardingEntityQueryProvider)
|
//if (queryProvider is ShardingEntityQueryProvider shardingEntityQueryProvider)
|
||||||
{
|
//{
|
||||||
_dbContext = shardingEntityQueryProvider.GetCurrentDbContext().Context;
|
// _dbContext = shardingEntityQueryProvider.GetCurrentDbContext().Context;
|
||||||
}
|
//}
|
||||||
|
|
||||||
_queryProvider = queryProvider;
|
_queryProvider = queryProvider;
|
||||||
Expression = expression;
|
Expression = expression;
|
||||||
|
@ -63,20 +63,11 @@ namespace ShardingCore.Sharding.Query
|
||||||
public IEnumerator<TResult> GetEnumerator()
|
public IEnumerator<TResult> GetEnumerator()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
||||||
}
|
}
|
||||||
public IAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
|
public IAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
|
||||||
{
|
{
|
||||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
return _queryProvider.ExecuteAsync<IAsyncEnumerable<TResult>>(Expression).GetAsyncEnumerator(cancellationToken);
|
||||||
{
|
|
||||||
IQueryable<TResult> queryable = new EnumerableQuery<TResult>(Expression);
|
|
||||||
var streamMergeContext = ShardingContainer.GetService<IStreamMergeContextFactory>().Create(queryable, shardingDbContext);
|
|
||||||
|
|
||||||
var streamMergeEngine = GenericStreamMergeEngine<TResult>.Create<TResult>(streamMergeContext);
|
|
||||||
return streamMergeEngine.GetAsyncEnumerator().GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ShardingCoreException("db context is not IShardingDbContext");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
@ -86,13 +77,13 @@ namespace ShardingCore.Sharding.Query
|
||||||
|
|
||||||
public Type ElementType => typeof(TResult);
|
public Type ElementType => typeof(TResult);
|
||||||
public Expression Expression { get; }
|
public Expression Expression { get; }
|
||||||
public IQueryProvider Provider => _queryProvider;
|
public IQueryProvider Provider => _queryProvider;
|
||||||
|
|
||||||
public IList GetList()
|
public IList GetList()
|
||||||
{
|
{
|
||||||
throw new NotSupportedException(CoreStrings.DataBindingWithIListSource);
|
throw new NotSupportedException(CoreStrings.DataBindingWithIListSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsListCollection => false;
|
public bool ContainsListCollection => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,7 +29,17 @@ namespace ShardingCore.Core.Internal.StreamMerge.ReWrite
|
||||||
var orders = extraEntry.Orders ?? Enumerable.Empty<PropertyOrder>();
|
var orders = extraEntry.Orders ?? Enumerable.Empty<PropertyOrder>();
|
||||||
|
|
||||||
//去除分页,获取前Take+Skip数量
|
//去除分页,获取前Take+Skip数量
|
||||||
var reWriteQueryable = _queryable.RemoveTake().RemoveSkip();
|
var reWriteQueryable = _queryable;
|
||||||
|
if (take.HasValue)
|
||||||
|
{
|
||||||
|
reWriteQueryable = _queryable.RemoveTake();
|
||||||
|
}
|
||||||
|
if (skip.HasValue)
|
||||||
|
{
|
||||||
|
reWriteQueryable = _queryable.RemoveSkip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (take.HasValue)
|
if (take.HasValue)
|
||||||
reWriteQueryable = reWriteQueryable.Take(take.Value + skip.GetValueOrDefault());
|
reWriteQueryable = reWriteQueryable.Take(take.Value + skip.GetValueOrDefault());
|
||||||
//包含group by
|
//包含group by
|
||||||
|
|
|
@ -14,10 +14,10 @@ using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Internal;
|
using Microsoft.EntityFrameworkCore.Internal;
|
||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||||
using ShardingCore.Core;
|
using ShardingCore.Core;
|
||||||
using ShardingCore.Sharding.Abstractions;
|
using ShardingCore.Sharding.Abstractions;
|
||||||
using ShardingCore.Sharding.Internal;
|
using ShardingCore.Sharding.Internal;
|
||||||
using ShardingCore.Sharding.Query;
|
|
||||||
|
|
||||||
namespace ShardingCore.Sharding
|
namespace ShardingCore.Sharding
|
||||||
{
|
{
|
||||||
|
@ -28,173 +28,15 @@ namespace ShardingCore.Sharding
|
||||||
* @Ver: 1.0
|
* @Ver: 1.0
|
||||||
* @Email: 326308290@qq.com
|
* @Email: 326308290@qq.com
|
||||||
*/
|
*/
|
||||||
public class ShardingInternalDbSet<TEntity> :
|
public class ShardingInternalDbSet<TEntity> :InternalDbSet<TEntity>
|
||||||
DbSet<TEntity>,
|
|
||||||
IQueryable<TEntity>,
|
|
||||||
IAsyncEnumerable<TEntity>,
|
|
||||||
IInfrastructure<IServiceProvider>,
|
|
||||||
IResettableService
|
|
||||||
where TEntity : class
|
where TEntity : class
|
||||||
{
|
{
|
||||||
private readonly DbContext _context;
|
private readonly DbContext _context;
|
||||||
private readonly string _entityTypeName;
|
|
||||||
private IEntityType _entityType;
|
|
||||||
private ShardingEntityQueryable<TEntity> _entityQueryable;
|
|
||||||
private LocalView<TEntity> _localView;
|
|
||||||
|
|
||||||
/// <summary>
|
public ShardingInternalDbSet(DbContext context, string entityTypeName) : base(context, entityTypeName)
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
public ShardingInternalDbSet(DbContext context, string entityTypeName)
|
|
||||||
{
|
{
|
||||||
Check.NotNull(context, nameof(context));
|
|
||||||
|
|
||||||
// Just storing context/service locator here so that the context will be initialized by the time the
|
|
||||||
// set is used and services will be obtained from the correctly scoped container when this happens.
|
|
||||||
_context = context;
|
_context = context;
|
||||||
_entityTypeName = entityTypeName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
public override IEntityType EntityType
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_entityType != null)
|
|
||||||
{
|
|
||||||
return _entityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
_entityType = _entityTypeName != null
|
|
||||||
? _context.Model.FindEntityType(_entityTypeName)
|
|
||||||
: _context.Model.FindEntityType(typeof(TEntity));
|
|
||||||
|
|
||||||
if (_entityType == null)
|
|
||||||
{
|
|
||||||
if (_context.Model.HasEntityTypeWithDefiningNavigation(typeof(TEntity)))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
CoreStrings.InvalidSetTypeWeak(typeof(TEntity).ShortDisplayName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_context.Model.IsShared(typeof(TEntity)))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
CoreStrings.InvalidSetSharedType(typeof(TEntity).ShortDisplayName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidOperationException(CoreStrings.InvalidSetType(typeof(TEntity).ShortDisplayName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_entityType.IsOwned())
|
|
||||||
{
|
|
||||||
_entityType = null;
|
|
||||||
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
CoreStrings.InvalidSetTypeOwned(typeof(TEntity).ShortDisplayName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_entityType.ClrType != typeof(TEntity))
|
|
||||||
{
|
|
||||||
var message = CoreStrings.DbSetIncorrectGenericType(
|
|
||||||
_entityType.ShortName(), _entityType.ClrType.ShortDisplayName(),
|
|
||||||
typeof(TEntity).ShortDisplayName());
|
|
||||||
_entityType = null;
|
|
||||||
|
|
||||||
throw new InvalidOperationException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _entityType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckState()
|
|
||||||
{
|
|
||||||
// ReSharper disable once AssignmentIsFullyDiscarded
|
|
||||||
_ = EntityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckKey()
|
|
||||||
{
|
|
||||||
if (EntityType.FindPrimaryKey() == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
CoreStrings.InvalidSetKeylessOperation(typeof(TEntity).ShortDisplayName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShardingEntityQueryable<TEntity> ShardingEntityQueryable
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
CheckState();
|
|
||||||
|
|
||||||
return NonCapturingLazyInitializer.EnsureInitialized(
|
|
||||||
ref _entityQueryable,
|
|
||||||
this,
|
|
||||||
internalSet => internalSet.CreateEntityQueryable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShardingEntityQueryable<TEntity> CreateEntityQueryable()
|
|
||||||
=> new ShardingEntityQueryable<TEntity>(_context.GetDependencies().QueryProvider, EntityType);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
public override LocalView<TEntity> Local
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
CheckKey();
|
|
||||||
|
|
||||||
if (_context.ChangeTracker.AutoDetectChangesEnabled)
|
|
||||||
{
|
|
||||||
_context.ChangeTracker.DetectChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _localView ??= new LocalView<TEntity>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
public override TEntity Find(params object[] keyValues)
|
|
||||||
=> Finder.Find(keyValues);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
|
||||||
=> Finder.FindAsync(keyValues);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
public override ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
|
||||||
=> Finder.FindAsync(keyValues, cancellationToken);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
||||||
|
@ -514,94 +356,5 @@ namespace ShardingCore.Sharding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEntityFinder<TEntity> Finder
|
|
||||||
=> (IEntityFinder<TEntity>)_context.GetDependencies().EntityFinderFactory.Create(EntityType);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()
|
|
||||||
=> ShardingEntityQueryable.GetEnumerator();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
=> ShardingEntityQueryable.GetEnumerator();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
IAsyncEnumerator<TEntity> IAsyncEnumerable<TEntity>.GetAsyncEnumerator(CancellationToken cancellationToken)
|
|
||||||
=> ShardingEntityQueryable.GetAsyncEnumerator(cancellationToken);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
Type IQueryable.ElementType
|
|
||||||
=> ShardingEntityQueryable.ElementType;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
Expression IQueryable.Expression
|
|
||||||
=> ShardingEntityQueryable.Expression;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
IQueryProvider IQueryable.Provider
|
|
||||||
=> ShardingEntityQueryable.Provider;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
IServiceProvider IInfrastructure<IServiceProvider>.Instance
|
|
||||||
=> _context.GetInfrastructure();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
void IResettableService.ResetState()
|
|
||||||
=> _localView = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
|
||||||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
|
|
||||||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
|
||||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cancellationToken"> A <see cref="CancellationToken" /> to observe while waiting for the task to complete. </param>
|
|
||||||
Task IResettableService.ResetStateAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
((IResettableService)this).ResetState();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace ShardingCore.Sharding
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* @Author: xjm
|
||||||
|
* @Description:
|
||||||
|
* @Date: 2021/8/17 21:03:03
|
||||||
|
* @Ver: 1.0
|
||||||
|
* @Email: 326308290@qq.com
|
||||||
|
*/
|
||||||
|
public class ShardingTempInternalDbSet<TEntity> :
|
||||||
|
IQueryable<TEntity>,
|
||||||
|
IEnumerable<TEntity>,
|
||||||
|
IEnumerable,
|
||||||
|
IQueryable where TEntity:class
|
||||||
|
{
|
||||||
|
private IQueryable<TEntity> _queryable;
|
||||||
|
public ShardingTempInternalDbSet(EnumerableQuery<TEntity> queryable)
|
||||||
|
{
|
||||||
|
_queryable = queryable.AsQueryable();
|
||||||
|
}
|
||||||
|
public IEnumerator<TEntity> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _queryable.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type ElementType => _queryable.ElementType;
|
||||||
|
public Expression Expression => _queryable.Expression;
|
||||||
|
public IQueryProvider Provider => _queryable.Provider;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ namespace ShardingCore.Sharding
|
||||||
public class StreamMergeContext<T>
|
public class StreamMergeContext<T>
|
||||||
{
|
{
|
||||||
private readonly IShardingParallelDbContextFactory _shardingParallelDbContextFactory;
|
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;
|
||||||
private readonly IRoutingRuleEngineFactory _tableRoutingRuleEngineFactory;
|
private readonly IRoutingRuleEngineFactory _tableRoutingRuleEngineFactory;
|
||||||
|
@ -41,7 +41,7 @@ namespace ShardingCore.Sharding
|
||||||
IShardingParallelDbContextFactory shardingParallelDbContextFactory,IShardingScopeFactory shardingScopeFactory)
|
IShardingParallelDbContextFactory shardingParallelDbContextFactory,IShardingScopeFactory shardingScopeFactory)
|
||||||
{
|
{
|
||||||
_shardingParallelDbContextFactory = shardingParallelDbContextFactory;
|
_shardingParallelDbContextFactory = shardingParallelDbContextFactory;
|
||||||
_shardingScopeFactory = shardingScopeFactory;
|
//_shardingScopeFactory = shardingScopeFactory;
|
||||||
_source = source;
|
_source = source;
|
||||||
_shardingDbContext = shardingDbContext;
|
_shardingDbContext = shardingDbContext;
|
||||||
_tableRoutingRuleEngineFactory = tableRoutingRuleEngineFactory;
|
_tableRoutingRuleEngineFactory = tableRoutingRuleEngineFactory;
|
||||||
|
@ -78,10 +78,10 @@ namespace ShardingCore.Sharding
|
||||||
return _tableRoutingRuleEngineFactory.Route(_source);
|
return _tableRoutingRuleEngineFactory.Route(_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShardingScope CreateScope()
|
//public ShardingScope CreateScope()
|
||||||
{
|
//{
|
||||||
return _shardingScopeFactory.CreateScope();
|
// return _shardingScopeFactory.CreateScope();
|
||||||
}
|
//}
|
||||||
|
|
||||||
public IQueryable<T> GetReWriteQueryable()
|
public IQueryable<T> GetReWriteQueryable()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using ShardingCore.Exceptions;
|
||||||
|
using ShardingCore.Extensions;
|
||||||
|
using ShardingCore.Sharding.Enumerators;
|
||||||
|
using ShardingCore.Sharding.Enumerators.StreamMergeAsync;
|
||||||
|
|
||||||
|
namespace ShardingCore.Sharding.StreamMergeEngines
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* @Author: xjm
|
||||||
|
* @Description:
|
||||||
|
* @Date: 2021/8/17 14:22:10
|
||||||
|
* @Ver: 1.0
|
||||||
|
* @Email: 326308290@qq.com
|
||||||
|
*/
|
||||||
|
public abstract class AbstractInMemoryAsyncStreamMergeEngine<T>
|
||||||
|
{
|
||||||
|
private readonly StreamMergeContext<T> _mergeContext;
|
||||||
|
|
||||||
|
public AbstractInMemoryAsyncStreamMergeEngine(StreamMergeContext<T> mergeContext)
|
||||||
|
{
|
||||||
|
_mergeContext = mergeContext;
|
||||||
|
}
|
||||||
|
private async Task<IAsyncEnumerator<T>> GetAsyncEnumerator(IQueryable<T> newQueryable)
|
||||||
|
{
|
||||||
|
var enumator = newQueryable.AsAsyncEnumerable().GetAsyncEnumerator();
|
||||||
|
await enumator.MoveNextAsync();
|
||||||
|
return enumator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<T>> ExecuteAsync(Func<IQueryable, Task<T>> efQuery,CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
var tableResult = _mergeContext.GetRouteResults();
|
||||||
|
var enumeratorTasks = tableResult.Select(routeResult =>
|
||||||
|
{
|
||||||
|
if (routeResult.ReplaceTables.Count > 1)
|
||||||
|
throw new ShardingCoreException("route found more than 1 table name s");
|
||||||
|
var tail = string.Empty;
|
||||||
|
if (routeResult.ReplaceTables.Count == 1)
|
||||||
|
tail = routeResult.ReplaceTables.First().Tail;
|
||||||
|
|
||||||
|
return Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//using (var scope = _mergeContext.CreateScope())
|
||||||
|
//{
|
||||||
|
//var shardingContext = ShardingContext.Create(routeResult);
|
||||||
|
//scope.ShardingAccessor.ShardingContext = shardingContext;
|
||||||
|
|
||||||
|
var shardingDbContext = _mergeContext.CreateDbContext(tail);
|
||||||
|
var newQueryable = (IQueryable<T>)_mergeContext.GetReWriteQueryable()
|
||||||
|
.ReplaceDbContextQueryable(shardingDbContext);
|
||||||
|
var query = await efQuery(newQueryable);
|
||||||
|
return query;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
return (await Task.WhenAll(enumeratorTasks)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using ShardingCore.Exceptions;
|
||||||
|
using ShardingCore.Extensions;
|
||||||
|
using ShardingCore.Sharding.Enumerators;
|
||||||
|
using ShardingCore.Sharding.Enumerators.StreamMergeAsync;
|
||||||
|
|
||||||
|
namespace ShardingCore.Sharding.StreamMergeEngines
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* @Author: xjm
|
||||||
|
* @Description:
|
||||||
|
* @Date: Saturday, 14 August 2021 22:07:28
|
||||||
|
* @Email: 326308290@qq.com
|
||||||
|
*/
|
||||||
|
public class AsyncEnumerableStreamMergeEngine<T> :IAsyncEnumerable<T>
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly StreamMergeContext<T> _mergeContext;
|
||||||
|
|
||||||
|
public AsyncEnumerableStreamMergeEngine(StreamMergeContext<T> mergeContext)
|
||||||
|
{
|
||||||
|
_mergeContext = mergeContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
//public static IStreamMergeEngine<T> Create<T>(StreamMergeContext<T> mergeContext)
|
||||||
|
//{
|
||||||
|
// return new AsyncEnumerableStreamMergeEngine<T>(mergeContext);
|
||||||
|
//}
|
||||||
|
//public async Task<IStreamMergeAsyncEnumerator<T>> GetAsyncEnumerator()
|
||||||
|
//{
|
||||||
|
// var tableResult = _mergeContext.GetRouteResults();
|
||||||
|
// var enumeratorTasks = tableResult.Select(routeResult =>
|
||||||
|
// {
|
||||||
|
// if (routeResult.ReplaceTables.Count > 1)
|
||||||
|
// throw new ShardingCoreException("route found more than 1 table name s");
|
||||||
|
// var tail = string.Empty;
|
||||||
|
// if (routeResult.ReplaceTables.Count == 1)
|
||||||
|
// tail = routeResult.ReplaceTables.First().Tail;
|
||||||
|
|
||||||
|
// return Task.Run(async () =>
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// //using (var scope = _mergeContext.CreateScope())
|
||||||
|
// //{
|
||||||
|
// //var shardingContext = ShardingContext.Create(routeResult);
|
||||||
|
// //scope.ShardingAccessor.ShardingContext = shardingContext;
|
||||||
|
|
||||||
|
// var shardingDbContext = _mergeContext.CreateDbContext(tail);
|
||||||
|
// var newQueryable = (IQueryable<T>) _mergeContext.GetReWriteQueryable()
|
||||||
|
// .ReplaceDbContextQueryable(shardingDbContext);
|
||||||
|
|
||||||
|
// var asyncEnumerator = await GetAsyncEnumerator(newQueryable);
|
||||||
|
// return new StreamMergeAsyncEnumerator<T>(asyncEnumerator);
|
||||||
|
// //}
|
||||||
|
// }
|
||||||
|
// catch (Exception e)
|
||||||
|
// {
|
||||||
|
// Console.WriteLine(e);
|
||||||
|
// throw;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }).ToArray();
|
||||||
|
|
||||||
|
// var streamEnumerators = await Task.WhenAll(enumeratorTasks);
|
||||||
|
// if (_mergeContext.HasSkipTake())
|
||||||
|
// return new PaginationStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
||||||
|
// if (_mergeContext.HasGroupQuery())
|
||||||
|
// return new MultiAggregateOrderStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
||||||
|
// return new MultiOrderStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
||||||
|
//}
|
||||||
|
//public IStreamMergeEnumerator<T> GetEnumerator()
|
||||||
|
//{
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<IAsyncEnumerator<T>> GetAsyncEnumerator(IQueryable<T> newQueryable)
|
||||||
|
{
|
||||||
|
var enumator = newQueryable.AsAsyncEnumerable().GetAsyncEnumerator();
|
||||||
|
await enumator.MoveNextAsync();
|
||||||
|
return enumator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
var tableResult = _mergeContext.GetRouteResults();
|
||||||
|
var enumeratorTasks = tableResult.Select(routeResult =>
|
||||||
|
{
|
||||||
|
if (routeResult.ReplaceTables.Count > 1)
|
||||||
|
throw new ShardingCoreException("route found more than 1 table name s");
|
||||||
|
var tail = string.Empty;
|
||||||
|
if (routeResult.ReplaceTables.Count == 1)
|
||||||
|
tail = routeResult.ReplaceTables.First().Tail;
|
||||||
|
|
||||||
|
return Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//using (var scope = _mergeContext.CreateScope())
|
||||||
|
//{
|
||||||
|
//var shardingContext = ShardingContext.Create(routeResult);
|
||||||
|
//scope.ShardingAccessor.ShardingContext = shardingContext;
|
||||||
|
|
||||||
|
var shardingDbContext = _mergeContext.CreateDbContext(tail);
|
||||||
|
var newQueryable = (IQueryable<T>)_mergeContext.GetReWriteQueryable()
|
||||||
|
.ReplaceDbContextQueryable(shardingDbContext);
|
||||||
|
|
||||||
|
var asyncEnumerator = await GetAsyncEnumerator(newQueryable);
|
||||||
|
return new StreamMergeAsyncEnumerator<T>(asyncEnumerator);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
var streamEnumerators = Task.WhenAll(enumeratorTasks).GetAwaiter().GetResult();
|
||||||
|
if (_mergeContext.HasSkipTake())
|
||||||
|
return new PaginationStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
||||||
|
if (_mergeContext.HasGroupQuery())
|
||||||
|
return new MultiAggregateOrderStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
||||||
|
return new MultiOrderStreamMergeAsyncEnumerator<T>(_mergeContext, streamEnumerators);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ShardingCore.Extensions;
|
||||||
|
|
||||||
|
namespace ShardingCore.Sharding.StreamMergeEngines
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* @Author: xjm
|
||||||
|
* @Description:
|
||||||
|
* @Date: 2021/8/17 15:16:36
|
||||||
|
* @Ver: 1.0
|
||||||
|
* @Email: 326308290@qq.com
|
||||||
|
*/
|
||||||
|
public class FirstOrDefaultAsyncInMemoryAsyncStreamMergeEngine<TResult>:AbstractInMemoryAsyncStreamMergeEngine<TResult>
|
||||||
|
{
|
||||||
|
private readonly StreamMergeContext<TResult> _mergeContext;
|
||||||
|
|
||||||
|
public FirstOrDefaultAsyncInMemoryAsyncStreamMergeEngine(StreamMergeContext<TResult> mergeContext) : base(mergeContext)
|
||||||
|
{
|
||||||
|
_mergeContext = mergeContext;
|
||||||
|
}
|
||||||
|
public async Task<TResult> ExecuteAsync(Func<IQueryable, Task<TResult>> efQuery, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
var result = await base.ExecuteAsync(efQuery, cancellationToken);
|
||||||
|
var q = result.Where(o => o != null).AsQueryable();
|
||||||
|
if (_mergeContext.Orders.Any())
|
||||||
|
return q.OrderWithExpression(_mergeContext.Orders).FirstOrDefault();
|
||||||
|
|
||||||
|
return q.FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,11 +61,13 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
{
|
{
|
||||||
var dbContextDependencies = typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as IDbContextDependencies;
|
var dbContextDependencies = typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as IDbContextDependencies;
|
||||||
var targetIQ = (IQueryable) ((IDbSetCache) _dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.EntityType.ClrType);
|
var targetIQ = (IQueryable) ((IDbSetCache) _dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.EntityType.ClrType);
|
||||||
var newQueryable = targetIQ.Provider.CreateQuery((Expression) Expression.Call((Expression) null, typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethod("AsNoTracking").MakeGenericMethod(queryRootExpression.EntityType.ClrType), targetIQ.Expression));
|
//AsNoTracking
|
||||||
|
//(Expression)Expression.Call((Expression)null, typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethod("AsNoTracking").MakeGenericMethod(queryRootExpression.EntityType.ClrType), targetIQ.Expression)
|
||||||
|
var newQueryable = targetIQ.Provider.CreateQuery(targetIQ.Expression);
|
||||||
Source = newQueryable;
|
Source = newQueryable;
|
||||||
//如何替换ef5的set
|
//如何替换ef5的set
|
||||||
var replaceQueryRoot = new ReplaceSingleQueryRootExpressionVisitor();
|
var replaceQueryRoot = new ReplaceSingleQueryRootExpressionVisitor();
|
||||||
replaceQueryRoot.Visit(newQueryable.Expression);
|
replaceQueryRoot.Visit(Source.Expression);
|
||||||
return base.VisitExtension(replaceQueryRoot.QueryRootExpression);
|
return base.VisitExtension(replaceQueryRoot.QueryRootExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"SqlServer": {
|
"SqlServer": {
|
||||||
"ConnectionString": "Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True;MultipleActiveResultSets=true"
|
"ConnectionString": "Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,7 +22,7 @@ namespace ShardingCore.Test50
|
||||||
private readonly ShardingDefaultDbContext _virtualDbContext;
|
private readonly ShardingDefaultDbContext _virtualDbContext;
|
||||||
private readonly IRoutingRuleEngineFactory _routingRuleEngineFactory;
|
private readonly IRoutingRuleEngineFactory _routingRuleEngineFactory;
|
||||||
|
|
||||||
public ShardingTest(ShardingDefaultDbContext virtualDbContext,IRoutingRuleEngineFactory routingRuleEngineFactory)
|
public ShardingTest(ShardingDefaultDbContext virtualDbContext, IRoutingRuleEngineFactory routingRuleEngineFactory)
|
||||||
{
|
{
|
||||||
_virtualDbContext = virtualDbContext;
|
_virtualDbContext = virtualDbContext;
|
||||||
_routingRuleEngineFactory = routingRuleEngineFactory;
|
_routingRuleEngineFactory = routingRuleEngineFactory;
|
||||||
|
@ -48,31 +48,24 @@ namespace ShardingCore.Test50
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ToList_All_Test()
|
public async Task ToList_All_Test()
|
||||||
{
|
{
|
||||||
try
|
|
||||||
|
var mods = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
|
||||||
|
Assert.Equal(1000, mods.Count);
|
||||||
|
|
||||||
|
var modOrders1 = await _virtualDbContext.Set<SysUserMod>().OrderBy(o => o.Age).ToListAsync();
|
||||||
|
int ascAge = 1;
|
||||||
|
foreach (var sysUserMod in modOrders1)
|
||||||
{
|
{
|
||||||
|
Assert.Equal(ascAge, sysUserMod.Age);
|
||||||
var mods = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
|
ascAge++;
|
||||||
Assert.Equal(1000, mods.Count);
|
|
||||||
|
|
||||||
var modOrders1 = await _virtualDbContext.Set<SysUserMod>().OrderBy(o => o.Age).ToListAsync();
|
|
||||||
int ascAge = 1;
|
|
||||||
foreach (var sysUserMod in modOrders1)
|
|
||||||
{
|
|
||||||
Assert.Equal(ascAge, sysUserMod.Age);
|
|
||||||
ascAge++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var modOrders2 = await _virtualDbContext.Set<SysUserMod>().OrderByDescending(o => o.Age).ToListAsync();
|
|
||||||
int descAge = 1000;
|
|
||||||
foreach (var sysUserMod in modOrders2)
|
|
||||||
{
|
|
||||||
Assert.Equal(descAge, sysUserMod.Age);
|
|
||||||
descAge--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
var modOrders2 = await _virtualDbContext.Set<SysUserMod>().OrderByDescending(o => o.Age).ToListAsync();
|
||||||
|
int descAge = 1000;
|
||||||
|
foreach (var sysUserMod in modOrders2)
|
||||||
{
|
{
|
||||||
throw;
|
Assert.Equal(descAge, sysUserMod.Age);
|
||||||
|
descAge--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ namespace ShardingCore.Test50
|
||||||
|
|
||||||
services.AddShardingSqlServer(o =>
|
services.AddShardingSqlServer(o =>
|
||||||
{
|
{
|
||||||
o.EnsureCreatedWithOutShardingTable = true;
|
o.EnsureCreatedWithOutShardingTable = false;
|
||||||
o.CreateShardingTableOnStart = true;
|
o.CreateShardingTableOnStart = false;
|
||||||
o.UseShardingDbContext<DefaultDbContext>( dbConfig =>
|
o.UseShardingDbContext<DefaultDbContext>( dbConfig =>
|
||||||
{
|
{
|
||||||
dbConfig.AddShardingTableRoute<SysUserModVirtualTableRoute>();
|
dbConfig.AddShardingTableRoute<SysUserModVirtualTableRoute>();
|
||||||
|
@ -82,7 +82,7 @@ namespace ShardingCore.Test50
|
||||||
var shardingBootstrapper = serviceProvider.GetService<IShardingBootstrapper>();
|
var shardingBootstrapper = serviceProvider.GetService<IShardingBootstrapper>();
|
||||||
shardingBootstrapper.Start();
|
shardingBootstrapper.Start();
|
||||||
// 有一些测试数据要初始化可以放在这里
|
// 有一些测试数据要初始化可以放在这里
|
||||||
//InitData(serviceProvider).GetAwaiter().GetResult();
|
//InitData(serviceProvider).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -94,9 +94,7 @@ namespace ShardingCore.Test50
|
||||||
{
|
{
|
||||||
using (var scope = serviceProvider.CreateScope())
|
using (var scope = serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
var virtualDbContext = scope.ServiceProvider.GetService<DefaultDbContext>();
|
var virtualDbContext = scope.ServiceProvider.GetService<ShardingDefaultDbContext>();
|
||||||
if (!await virtualDbContext.Set<SysUserMod>().AnyAsync(o => true))
|
|
||||||
{
|
|
||||||
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>();
|
||||||
|
@ -136,7 +134,6 @@ namespace ShardingCore.Test50
|
||||||
await virtualDbContext.AddRangeAsync(userSalaries);
|
await virtualDbContext.AddRangeAsync(userSalaries);
|
||||||
|
|
||||||
await virtualDbContext.SaveChangesAsync();
|
await virtualDbContext.SaveChangesAsync();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue