Merge branch 'ShardingNavigations'
# Conflicts: # nuget-publish.bat # src/ShardingCore/Extensions/DbContextExtensions/DbContextExtensionShardingCore.cs
This commit is contained in:
commit
422e78c0d1
|
@ -55,7 +55,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.ShardingConsole", "s
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.OracleIssue", "samples\Sample.OracleIssue\Sample.OracleIssue.csproj", "{BF4FEA2A-3F09-47D8-9BF7-4261D8D1671D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.Test6x", "test\ShardingCore.Test6x\ShardingCore.Test6x.csproj", "{8ED3A191-5A29-4599-B383-9FD225CC0BA2}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCore.Test6x", "test\ShardingCore.Test6x\ShardingCore.Test6x.csproj", "{8ED3A191-5A29-4599-B383-9FD225CC0BA2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src6", "src6", "{585A790B-8B19-430F-BEB7-9F7D1A3AAFAA}"
|
||||
EndProject
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
:start
|
||||
::定义版本
|
||||
set EFCORE7=7.7.0.12
|
||||
set EFCORE6=7.6.0.12
|
||||
set EFCORE5=7.5.0.12
|
||||
set EFCORE3=7.3.0.12
|
||||
set EFCORE2=7.2.0.12
|
||||
set EFCORE7=7.7.1.1-preview1
|
||||
set EFCORE6=7.6.1.1-preview1
|
||||
set EFCORE5=7.5.1.1-preview1
|
||||
set EFCORE3=7.3.1.1-preview1
|
||||
set EFCORE2=7.2.1.1-preview1
|
||||
|
||||
::删除所有bin与obj下的文件
|
||||
@echo off
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Extensions.ShardingQueryableExtensions;
|
||||
|
||||
namespace Sample.AutoCreateIfPresent.Controllers;
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace Sample.AutoCreateIfPresent
|
|||
base.OnModelCreating(modelBuilder);
|
||||
modelBuilder.ApplyConfiguration(new OrderByHourMap());
|
||||
modelBuilder.ApplyConfiguration(new AreaDeviceMap());
|
||||
Console.WriteLine(this.IsExecutor);
|
||||
}
|
||||
|
||||
public IRouteTail RouteTail { get; set; }
|
||||
|
|
|
@ -44,7 +44,7 @@ public static class MyShardingExtension
|
|||
new Dictionary<DbContext, IEnumerable<TEntity>>()
|
||||
{
|
||||
{
|
||||
shardingDbContext.CreateGenericDbContext(entitiesArray[0]),
|
||||
shardingDbContext.GetShardingExecutor().CreateGenericDbContext(entitiesArray[0]),
|
||||
entitiesArray
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Sample.BulkConsole
|
|||
});
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var s = Guid.NewGuid().ToString("n");
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ public class DbSetDiscoverExpressionVisitor<TEntity>:ExpressionVisitor where TEn
|
|||
var dbContextDependencies =
|
||||
typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as IDbContextDependencies;
|
||||
var targetIQ =
|
||||
((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.EntityType.ClrType);
|
||||
((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.ElementType);
|
||||
DbSet = (DbSet<TEntity>)targetIQ;
|
||||
}
|
||||
return base.VisitExtension(node);
|
||||
|
|
|
@ -9,6 +9,7 @@ using ShardingCore.Core.RuntimeContexts;
|
|||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources.PhysicDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions;
|
||||
using ShardingCore.Extensions.ShardingPageExtensions;
|
||||
using ShardingCore.Extensions.ShardingQueryableExtensions;
|
||||
using ShardingCore.Helpers;
|
||||
|
||||
|
@ -61,30 +62,31 @@ namespace Sample.MySql.Controllers
|
|||
|
||||
public IQueryable<SysTest> GetAll()
|
||||
{
|
||||
var shardingRouteManager = _shardingRuntimeContext.GetShardingRouteManager();
|
||||
// var shardingTableCreator = _shardingRuntimeContext.GetShardingTableCreator();
|
||||
// var tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
|
||||
// //系统的时间分片都会实现 ITailAppendable 如果不是系统的自定义的转成你自己的对象即可
|
||||
// var virtualTableRoute = (ITailAppendable)tableRouteManager.GetRoute(typeof(SysUserMod));
|
||||
// //一定要先在路由里面添加尾巴
|
||||
// virtualTableRoute.Append("20220921");
|
||||
// shardingTableCreator.CreateTable<SysUserMod>("ds0","20220921");
|
||||
var shardingTableCreator = _shardingRuntimeContext.GetShardingTableCreator();
|
||||
var tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
|
||||
//系统的时间分片都会实现 ITailAppendable 如果不是系统的自定义的转成你自己的对象即可
|
||||
var virtualTableRoute = (ITailAppendable)tableRouteManager.GetRoute(typeof(SysUserMod));
|
||||
//一定要先在路由里面添加尾巴
|
||||
virtualTableRoute.Append("20220921");
|
||||
shardingTableCreator.CreateTable<SysUserMod>("ds0","20220921");
|
||||
return _defaultTableDbContext.Set<SysTest>();
|
||||
}
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Get()
|
||||
{
|
||||
var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource();
|
||||
virtualDataSource.AddPhysicDataSource(new DefaultPhysicDataSource("2023", "xxxxxxxx", false));
|
||||
var dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
|
||||
var virtualDataSourceRoute = dataSourceRouteManager.GetRoute(typeof(SysUserMod));
|
||||
virtualDataSourceRoute.AddDataSourceName("2023");
|
||||
var dataSourceInitializer = _shardingRuntimeContext.GetDataSourceInitializer();
|
||||
dataSourceInitializer.InitConfigure("2023",true,true);
|
||||
using (var dbContextTransaction = _defaultTableDbContext.Database.BeginTransaction())
|
||||
{
|
||||
|
||||
}
|
||||
var s = Guid.NewGuid().ToString();
|
||||
var page =await _defaultTableDbContext.Set<SysUserLogByMonth>().Where(o=>o.Id==s).OrderByDescending(o=>o.Time).ToShardingPageAsync(1,2);
|
||||
// var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource();
|
||||
// virtualDataSource.AddPhysicDataSource(new DefaultPhysicDataSource("2023", "xxxxxxxx", false));
|
||||
// var dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
|
||||
// var virtualDataSourceRoute = dataSourceRouteManager.GetRoute(typeof(SysUserMod));
|
||||
// virtualDataSourceRoute.AddDataSourceName("2023");
|
||||
// var dataSourceInitializer = _shardingRuntimeContext.GetDataSourceInitializer();
|
||||
// dataSourceInitializer.InitConfigure("2023",true,true);
|
||||
// using (var dbContextTransaction = _defaultTableDbContext.Database.BeginTransaction())
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
var x2 = await (from ut in _defaultTableDbContext.Set<SysTest>()
|
||||
join uu in _defaultTableDbContext.Set<SysUserLogByMonth>()
|
||||
|
@ -244,5 +246,27 @@ namespace Sample.MySql.Controllers
|
|||
// var sysUserMods2 = await _defaultTableDbContext.Set<SysTest>().FromSqlRaw("select * from SysTest where id='2'").ToListAsync();
|
||||
return Ok();
|
||||
}
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Get6()
|
||||
{
|
||||
var sysUserMod = await _defaultTableDbContext.Set<SysUserMod>().FirstOrDefaultAsync();
|
||||
sysUserMod.Age = new Random().Next(1,999);
|
||||
_defaultTableDbContext.Update(sysUserMod);
|
||||
_defaultTableDbContext.SaveChanges();
|
||||
// var sysUserMods1 = await _defaultTableDbContext.Set<SysUserMod>().FromSqlRaw("select * from SysUserMod where id='2'").ToListAsync();
|
||||
// var sysUserMods2 = await _defaultTableDbContext.Set<SysTest>().FromSqlRaw("select * from SysTest where id='2'").ToListAsync();
|
||||
return Ok();
|
||||
}
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Get7()
|
||||
{
|
||||
var sysUserMod = await _defaultTableDbContext.Set<SysUserMod>().FindAsync("101");
|
||||
sysUserMod.Age = new Random().Next(1,999);
|
||||
_defaultTableDbContext.Update(sysUserMod);
|
||||
_defaultTableDbContext.SaveChanges();
|
||||
// var sysUserMods1 = await _defaultTableDbContext.Set<SysUserMod>().FromSqlRaw("select * from SysUserMod where id='2'").ToListAsync();
|
||||
// var sysUserMods2 = await _defaultTableDbContext.Set<SysTest>().FromSqlRaw("select * from SysTest where id='2'").ToListAsync();
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,12 +38,13 @@ namespace Sample.MySql
|
|||
});
|
||||
}
|
||||
var userModMonths = new List<SysUserLogByMonth>();
|
||||
var begin = new DateTime(2021, 1, 01);
|
||||
foreach (var id in ids)
|
||||
{
|
||||
userModMonths.Add(new SysUserLogByMonth()
|
||||
{
|
||||
Id = id.ToString(),
|
||||
Time = DateTime.Now
|
||||
Time = begin.AddHours(id*12)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -40,10 +40,10 @@ namespace Sample.MySql.DbContexts
|
|||
modelBuilder.ApplyConfiguration(new SysTestMap());
|
||||
modelBuilder.ApplyConfiguration(new SysUserLogByMonthMap());
|
||||
|
||||
modelBuilder.Entity<SysUserLogByMonth>().HasData(new SysUserLogByMonth() { Id = "1", Time = DateTime.Now });
|
||||
modelBuilder.Entity<SysTest>().HasData(new SysTest() { Id = "1", UserId = "123" });
|
||||
modelBuilder.Entity<TestMod>().ToTable(nameof(TestMod));
|
||||
modelBuilder.Entity<TestModItem>().ToTable(nameof(TestModItem));
|
||||
// modelBuilder.Entity<SysUserLogByMonth>().HasData(new SysUserLogByMonth() { Id = "1", Time = DateTime.Now });
|
||||
// modelBuilder.Entity<SysTest>().HasData(new SysTest() { Id = "1", UserId = "123" });
|
||||
// modelBuilder.Entity<TestMod>().ToTable(nameof(TestMod));
|
||||
// modelBuilder.Entity<SysTest>().ToTable("xxx");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.2" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0-alpha.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src6\ShardingCore6\ShardingCore6.csproj" />
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Update;
|
||||
using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal;
|
||||
using Pomelo.EntityFrameworkCore.MySql.Migrations;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
|
@ -12,7 +13,8 @@ namespace Sample.MySql
|
|||
{
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
|
||||
public ShardingMySqlMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, IRelationalAnnotationProvider annotationProvider, IMySqlOptions options,IShardingRuntimeContext shardingRuntimeContext) : base(dependencies, annotationProvider, options)
|
||||
|
||||
public ShardingMySqlMigrationsSqlGenerator(IShardingRuntimeContext shardingRuntimeContext,MigrationsSqlGeneratorDependencies dependencies, ICommandBatchPreparer commandBatchPreparer, IMySqlOptions options) : base(dependencies, commandBatchPreparer, options)
|
||||
{
|
||||
_shardingRuntimeContext = shardingRuntimeContext;
|
||||
}
|
||||
|
|
|
@ -9,14 +9,14 @@ public class SysUserModVirtualDataSourceRoute:AbstractShardingOperatorVirtualDat
|
|||
{
|
||||
public override string ShardingKeyToDataSourceName(object shardingKey)
|
||||
{
|
||||
return $"{((string)shardingKey=="ds1"?"ds1":"ds2")}";
|
||||
return $"{shardingKey}";
|
||||
}
|
||||
|
||||
public override List<string> GetAllDataSourceNames()
|
||||
{
|
||||
return new List<string>()
|
||||
{
|
||||
"ds1", "ds2"
|
||||
"ds0", "ds1", "ds2"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace Sample.MySql
|
|||
{
|
||||
o.AddShardingTableRoute<DynamicTableRoute>();
|
||||
o.AddShardingTableRoute<SysUserLogByMonthRoute>();
|
||||
// o.AddShardingTableRoute<SysUserModVirtualTableRoute>();
|
||||
o.AddShardingTableRoute<SysUserModVirtualTableRoute>();
|
||||
o.AddShardingDataSourceRoute<SysUserModVirtualDataSourceRoute>();
|
||||
o.AddShardingTableRoute<TestModRoute>();
|
||||
o.AddShardingTableRoute<TestModItemRoute>();
|
||||
|
@ -104,25 +104,25 @@ namespace Sample.MySql
|
|||
|
||||
o.UseShardingQuery((conStr, builder) =>
|
||||
{
|
||||
builder.UseMySql(conStr, new MySqlServerVersion(new Version()));
|
||||
// .UseLoggerFactory(efLogger)
|
||||
// .EnableSensitiveDataLogging()
|
||||
builder.UseMySql(conStr, new MySqlServerVersion(new Version()))
|
||||
.UseLoggerFactory(efLogger)
|
||||
.EnableSensitiveDataLogging();
|
||||
//.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||
});
|
||||
o.UseShardingTransaction((connection, builder) =>
|
||||
{
|
||||
builder
|
||||
.UseMySql(connection, new MySqlServerVersion(new Version()));
|
||||
// .UseLoggerFactory(efLogger)
|
||||
// .EnableSensitiveDataLogging()
|
||||
.UseMySql(connection, new MySqlServerVersion(new Version()))
|
||||
.UseLoggerFactory(efLogger)
|
||||
.EnableSensitiveDataLogging();
|
||||
//.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||
});
|
||||
o.AddDefaultDataSource("ds0",
|
||||
"server=127.0.0.1;port=3306;database=dbdbd02;userid=root;password=root;");
|
||||
"server=127.0.0.1;port=3306;database=dbdbd0;userid=root;password=root;");
|
||||
o.AddExtraDataSource(sp => new Dictionary<string, string>()
|
||||
{
|
||||
{ "ds1", "server=127.0.0.1;port=3306;database=dbdbd12;userid=root;password=root;" },
|
||||
{ "ds2", "server=127.0.0.1;port=3306;database=dbdbd22;userid=root;password=root;" }
|
||||
{ "ds1", "server=127.0.0.1;port=3306;database=dbdbd1;userid=root;password=root;" },
|
||||
{ "ds2", "server=127.0.0.1;port=3306;database=dbdbd2;userid=root;password=root;" }
|
||||
});
|
||||
o.UseShardingMigrationConfigure(b =>
|
||||
{
|
||||
|
|
|
@ -1,24 +1,12 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using ShardingCore.Sharding.ShardingDbContextExecutors;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ShardingCore.EFCores;
|
||||
using ShardingCore.Helpers;
|
||||
using ShardingCore.Utils;
|
||||
using Volo.Abp.Domain.Entities;
|
||||
using Volo.Abp.EntityFrameworkCore;
|
||||
using Volo.Abp.Reflection;
|
||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Sharding;
|
||||
|
||||
namespace Samples.AbpSharding
|
||||
{
|
||||
|
@ -26,59 +14,36 @@ namespace Samples.AbpSharding
|
|||
public abstract class AbstractShardingAbpDbContext<TDbContext> : AbpDbContext<TDbContext>, IShardingDbContext
|
||||
where TDbContext : DbContext
|
||||
{
|
||||
private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
|
||||
protected AbstractShardingAbpDbContext(DbContextOptions<TDbContext> options) : base(options)
|
||||
{
|
||||
|
||||
var wrapOptionsExtension = options.FindExtension<ShardingWrapOptionsExtension>();
|
||||
if (wrapOptionsExtension != null)
|
||||
{
|
||||
_shardingDbContextExecutor = new ShardingDbContextExecutor(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否是真正的执行者
|
||||
/// </summary>
|
||||
private bool isExecutor => _shardingDbContextExecutor == null;
|
||||
|
||||
//public void ShardingUpgrade()
|
||||
//{
|
||||
// //IsExecutor = true;
|
||||
//}
|
||||
|
||||
public DbContext GetDbContext(string dataSourceName, CreateDbContextStrategyEnum strategy, IRouteTail routeTail)
|
||||
{
|
||||
var dbContext = _shardingDbContextExecutor.CreateDbContext(strategy, dataSourceName, routeTail);
|
||||
if (dbContext is AbpDbContext<TDbContext> abpDbContext)
|
||||
{
|
||||
abpDbContext.LazyServiceProvider = this.LazyServiceProvider;
|
||||
}
|
||||
|
||||
return dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据对象创建通用的dbcontext
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public DbContext CreateGenericDbContext<TEntity>(TEntity entity) where TEntity : class
|
||||
{
|
||||
CheckAndSetShardingKeyThatSupportAutoCreate(entity);
|
||||
var dbContext = _shardingDbContextExecutor.CreateGenericDbContext(entity);
|
||||
if (dbContext is AbpDbContext<TDbContext> abpDbContext && abpDbContext.LazyServiceProvider == null)
|
||||
{
|
||||
abpDbContext.LazyServiceProvider = this.LazyServiceProvider;
|
||||
}
|
||||
|
||||
return dbContext;
|
||||
}
|
||||
|
||||
private IShardingDbContextExecutor _shardingDbContextExecutor;
|
||||
public IShardingDbContextExecutor GetShardingExecutor()
|
||||
{
|
||||
return _shardingDbContextExecutor;
|
||||
return _shardingDbContextExecutor??=DoCreateShardingDbContextExecutor();
|
||||
}
|
||||
|
||||
private IShardingDbContextExecutor DoCreateShardingDbContextExecutor()
|
||||
{
|
||||
var shardingDbContextExecutor = this.CreateShardingDbContextExecutor()!;
|
||||
|
||||
shardingDbContextExecutor.EntityCreateDbContextBefore += (sender, args) =>
|
||||
{
|
||||
CheckAndSetShardingKeyThatSupportAutoCreate(args.Entity);
|
||||
};
|
||||
shardingDbContextExecutor.CreateDbContextAfter += (sender, args) =>
|
||||
{
|
||||
var argsDbContext = args.DbContext;
|
||||
|
||||
if (argsDbContext is AbpDbContext<TDbContext> abpDbContext&&
|
||||
abpDbContext.LazyServiceProvider == null)
|
||||
{
|
||||
abpDbContext.LazyServiceProvider = this.LazyServiceProvider;
|
||||
}
|
||||
};
|
||||
return shardingDbContextExecutor;
|
||||
}
|
||||
|
||||
|
||||
|
@ -118,416 +83,19 @@ namespace Samples.AbpSharding
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public override EntityEntry Add(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
base.Add(entity);
|
||||
return CreateGenericDbContext(entity).Add(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Add<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Add(entity);
|
||||
return CreateGenericDbContext(entity).Add(entity);
|
||||
}
|
||||
|
||||
|
||||
public override ValueTask<EntityEntry<TEntity>> AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.AddAsync(entity, cancellationToken);
|
||||
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
public override ValueTask<EntityEntry> AddAsync(object entity, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.AddAsync(entity, cancellationToken);
|
||||
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
public override void AddRange(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.AddRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AddRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
public override void AddRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.AddRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AddRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task AddRangeAsync(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
await base.AddRangeAsync(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
await group.Key.AddRangeAsync(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task AddRangeAsync(IEnumerable<object> entities, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
await base.AddRangeAsync(entities, cancellationToken);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
await group.Key.AddRangeAsync(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Attach<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Attach(entity);
|
||||
return CreateGenericDbContext(entity).Attach(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Attach(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Attach(entity);
|
||||
return CreateGenericDbContext(entity).Attach(entity);
|
||||
}
|
||||
|
||||
public override void AttachRange(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.AttachRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AttachRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override void AttachRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.AttachRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AttachRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//public override DatabaseFacade Database => _dbContextCaches.Any()
|
||||
// ? _dbContextCaches.First().Value.Database
|
||||
// : GetDbContext(true, string.Empty).Database;
|
||||
|
||||
public override EntityEntry<TEntity> Entry<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Entry(entity);
|
||||
return CreateGenericDbContext(entity).Entry(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Entry(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Entry(entity);
|
||||
return CreateGenericDbContext(entity).Entry(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Update<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Update(entity);
|
||||
return CreateGenericDbContext(entity).Update(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Update(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Update(entity);
|
||||
return CreateGenericDbContext(entity).Update(entity);
|
||||
}
|
||||
|
||||
public override void UpdateRange(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.UpdateRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.UpdateRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.UpdateRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.UpdateRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Remove<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Remove(entity);
|
||||
return CreateGenericDbContext(entity).Remove(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Remove(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Remove(entity);
|
||||
return CreateGenericDbContext(entity).Remove(entity);
|
||||
}
|
||||
|
||||
public override void RemoveRange(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.RemoveRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.RemoveRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.RemoveRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.RemoveRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override int SaveChanges()
|
||||
{
|
||||
|
||||
if (isExecutor)
|
||||
return base.SaveChanges();
|
||||
return this.SaveChanges(true);
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.SaveChanges(acceptAllChangesOnSuccess);
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (Database.CurrentTransaction == null && _shardingDbContextExecutor.IsMultiDbContext)
|
||||
{
|
||||
using (var tran = Database.BeginTransaction())
|
||||
{
|
||||
i = _shardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _shardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.SaveChangesAsync(cancellationToken);
|
||||
return this.SaveChangesAsync(true, cancellationToken);
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (Database.CurrentTransaction == null && _shardingDbContextExecutor.IsMultiDbContext)
|
||||
{
|
||||
using (var tran = await Database.BeginTransactionAsync(cancellationToken))
|
||||
{
|
||||
i = await _shardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
|
||||
await tran.CommitAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = await _shardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
if (isExecutor)
|
||||
{
|
||||
_shardingDbContextExecutor?.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
_shardingDbContextExecutor.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
await base.DisposeAsync();
|
||||
}
|
||||
else
|
||||
if (_shardingDbContextExecutor != null)
|
||||
{
|
||||
await _shardingDbContextExecutor.DisposeAsync();
|
||||
|
||||
}
|
||||
await base.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,478 +34,35 @@ namespace Samples.AbpSharding
|
|||
where TUser : AbpUser<TUser>
|
||||
where TSelf : AbpZeroDbContext<TTenant, TRole, TUser, TSelf>
|
||||
{
|
||||
private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
|
||||
|
||||
protected AbstractShardingAbpZeroDbContext(DbContextOptions<TSelf> options)
|
||||
: base(options)
|
||||
{
|
||||
var wrapOptionsExtension = options.FindExtension<ShardingWrapOptionsExtension>();
|
||||
if (wrapOptionsExtension != null)
|
||||
{
|
||||
_shardingDbContextExecutor = new ShardingDbContextExecutor(this);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否是真正的执行者
|
||||
/// </summary>
|
||||
protected bool isExecutor => _shardingDbContextExecutor == null;
|
||||
|
||||
/// <summary>
|
||||
/// 路由表
|
||||
/// </summary>
|
||||
public IRouteTail RouteTail { get; set; }
|
||||
|
||||
|
||||
public override EntityEntry Add(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
base.Add(entity);
|
||||
return CreateGenericDbContext(entity).Add(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Add<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Add(entity);
|
||||
return CreateGenericDbContext(entity).Add(entity);
|
||||
}
|
||||
|
||||
|
||||
public override ValueTask<EntityEntry<TEntity>> AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.AddAsync(entity, cancellationToken);
|
||||
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
public override ValueTask<EntityEntry> AddAsync(object entity, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.AddAsync(entity, cancellationToken);
|
||||
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
public override void AddRange(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.AddRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AddRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.AddRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AddRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task AddRangeAsync(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
await base.AddRangeAsync(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
await group.Key.AddRangeAsync(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task AddRangeAsync(IEnumerable<object> entities, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
await base.AddRangeAsync(entities, cancellationToken);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
await group.Key.AddRangeAsync(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Attach<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Attach(entity);
|
||||
return CreateGenericDbContext(entity).Attach(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Attach(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Attach(entity);
|
||||
return CreateGenericDbContext(entity).Attach(entity);
|
||||
}
|
||||
|
||||
public override void AttachRange(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.AttachRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AttachRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override void AttachRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.AttachRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AttachRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Entry<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Entry(entity);
|
||||
return CreateGenericDbContext(entity).Entry(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Entry(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Entry(entity);
|
||||
return CreateGenericDbContext(entity).Entry(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Update<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Update(entity);
|
||||
return CreateGenericDbContext(entity).Update(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Update(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Update(entity);
|
||||
return CreateGenericDbContext(entity).Update(entity);
|
||||
}
|
||||
|
||||
public override void UpdateRange(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.UpdateRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.UpdateRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.UpdateRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.UpdateRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Remove<TEntity>(TEntity entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Remove(entity);
|
||||
return CreateGenericDbContext(entity).Remove(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Remove(object entity)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.Remove(entity);
|
||||
return CreateGenericDbContext(entity).Remove(entity);
|
||||
}
|
||||
|
||||
public override void RemoveRange(params object[] entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.RemoveRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.RemoveRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
base.RemoveRange(entities);
|
||||
return;
|
||||
}
|
||||
var groups = entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.RemoveRange(group.Select(o => o.Entity));
|
||||
}
|
||||
}
|
||||
|
||||
public override int SaveChanges()
|
||||
{
|
||||
|
||||
if (isExecutor)
|
||||
return base.SaveChanges();
|
||||
return this.SaveChanges(true);
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.SaveChanges(acceptAllChangesOnSuccess);
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (Database.CurrentTransaction == null && _shardingDbContextExecutor.IsMultiDbContext)
|
||||
{
|
||||
using (var tran = Database.BeginTransaction())
|
||||
{
|
||||
i = _shardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _shardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
return base.SaveChangesAsync(cancellationToken);
|
||||
return this.SaveChangesAsync(true, cancellationToken);
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (isExecutor)
|
||||
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (Database.CurrentTransaction == null && _shardingDbContextExecutor.IsMultiDbContext)
|
||||
{
|
||||
using (var tran = await Database.BeginTransactionAsync(cancellationToken))
|
||||
{
|
||||
i = await _shardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
|
||||
await tran.CommitAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = await _shardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
if (isExecutor)
|
||||
{
|
||||
base.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
_shardingDbContextExecutor.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
if (isExecutor)
|
||||
{
|
||||
await base.DisposeAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await _shardingDbContextExecutor.DisposeAsync();
|
||||
|
||||
await base.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Sharding Core 方法实现
|
||||
|
||||
/// <summary>
|
||||
/// 根据查询获取DbContext
|
||||
/// </summary>
|
||||
/// <param name="dataSourceName"></param>
|
||||
/// <param name="strategy"></param>
|
||||
/// <param name="routeTail"></param>
|
||||
/// <returns></returns>
|
||||
public DbContext GetDbContext(string dataSourceName, CreateDbContextStrategyEnum strategy, IRouteTail routeTail)
|
||||
{
|
||||
var dbContext = _shardingDbContextExecutor.CreateDbContext(
|
||||
strategy,
|
||||
dataSourceName,
|
||||
routeTail
|
||||
);
|
||||
|
||||
this.FillDbContextInject(dbContext);
|
||||
|
||||
return dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据对象创建通用的dbcontext
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public DbContext CreateGenericDbContext<TEntity>(TEntity entity) where TEntity : class
|
||||
{
|
||||
CheckAndSetShardingKeyThatSupportAutoCreate(entity);
|
||||
|
||||
var dbContext = _shardingDbContextExecutor.CreateGenericDbContext(entity);
|
||||
|
||||
this.FillDbContextInject(dbContext);
|
||||
|
||||
return dbContext;
|
||||
}
|
||||
|
||||
private IShardingDbContextExecutor _shardingDbContextExecutor;
|
||||
public IShardingDbContextExecutor GetShardingExecutor()
|
||||
{
|
||||
return _shardingDbContextExecutor;
|
||||
return _shardingDbContextExecutor??=DoCreateShardingDbContextExecutor();
|
||||
}
|
||||
private IShardingDbContextExecutor DoCreateShardingDbContextExecutor()
|
||||
{
|
||||
var shardingDbContextExecutor = this.CreateShardingDbContextExecutor()!;
|
||||
|
||||
shardingDbContextExecutor.EntityCreateDbContextBefore += (sender, args) =>
|
||||
{
|
||||
CheckAndSetShardingKeyThatSupportAutoCreate(args.Entity);
|
||||
};
|
||||
shardingDbContextExecutor.CreateDbContextAfter += (sender, args) =>
|
||||
{
|
||||
var argsDbContext = args.DbContext;
|
||||
FillDbContextInject(argsDbContext);
|
||||
};
|
||||
return shardingDbContextExecutor;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -604,5 +161,23 @@ namespace Samples.AbpSharding
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
_shardingDbContextExecutor?.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
if(_shardingDbContextExecutor!=null)
|
||||
{
|
||||
await _shardingDbContextExecutor.DisposeAsync();
|
||||
}
|
||||
|
||||
await base.DisposeAsync();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace ShardingCore.Core.QueryTrackers
|
|||
{
|
||||
public object Track(object entity, IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(entity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var attachedEntity = genericDbContext.GetAttachedEntity(entity);
|
||||
if (attachedEntity == null)
|
||||
genericDbContext.Attach(entity);
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
|
|||
var dataSources = allDataSourceNames.Where(o => o== shardingKeyToDataSource).ToList();
|
||||
if (dataSources.IsEmpty())
|
||||
{
|
||||
throw new ShardingCoreException($"sharding key route not match {EntityMetadata.EntityType} -> [{EntityMetadata.ShardingTableProperty.Name}] ->【{shardingKey}】 all data sources ->[{string.Join(",", allDataSourceNames.Select(o=>o))}]");
|
||||
throw new ShardingCoreException($"sharding key route not match {EntityMetadata.EntityType} -> [{EntityMetadata.ShardingDataSourceProperty.Name}] ->【{shardingKey}】 all data sources ->[{string.Join(",", allDataSourceNames.Select(o=>o))}]");
|
||||
}
|
||||
|
||||
if (dataSources.Count > 1)
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
#if EFCORE2
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 14 August 2021 10:17:43
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public class ShardingDbSetSource : IDbSetSource, IDbQuerySource
|
||||
{
|
||||
private static readonly MethodInfo _genericCreateSet
|
||||
= typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
|
||||
|
||||
private static readonly MethodInfo _genericCreateQuery
|
||||
= typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateQueryFactory));
|
||||
|
||||
private readonly ConcurrentDictionary<Type, Func<DbContext, object>> _cache
|
||||
= new ConcurrentDictionary<Type, Func<DbContext, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, _genericCreateSet);
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual object CreateQuery(DbContext context, Type type)
|
||||
=> CreateCore(context, type, _genericCreateQuery);
|
||||
|
||||
private object CreateCore(DbContext context, Type type, MethodInfo createMethod)
|
||||
=> _cache.GetOrAdd(
|
||||
type,
|
||||
t => (Func<DbContext, object>)createMethod
|
||||
.MakeGenericMethod(t)
|
||||
.Invoke(null, null))(context);
|
||||
|
||||
private static Func<DbContext, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> c => new ShardingInternalDbSet<TEntity>(c);
|
||||
|
||||
private static Func<DbContext, DbQuery<TQuery>> CreateQueryFactory<TQuery>()
|
||||
where TQuery : class
|
||||
=> c => new ShardingInternalDbQuery<TQuery>(c);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,27 +0,0 @@
|
|||
#if EFCORE2
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/8/20 17:05:36
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
|
||||
public class ShardingInternalDbQuery<TQuery> : InternalDbQuery<TQuery> where TQuery : class
|
||||
{
|
||||
public ShardingInternalDbQuery(DbContext context) : base(context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -1,427 +0,0 @@
|
|||
#if EFCORE2
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.Core.TrackerManagers;
|
||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/8/15 8:39:15
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
public class ShardingInternalDbSet<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _localView;
|
||||
|
||||
public ShardingInternalDbSet(DbContext context) : base(context)
|
||||
{
|
||||
_context = (IShardingDbContext)context;
|
||||
_shardingRuntimeContext = context.GetShardingRuntimeContext();
|
||||
}
|
||||
|
||||
private IDataSourceRouteManager _dataSourceRouteManager;
|
||||
|
||||
protected IDataSourceRouteManager DataSourceRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _dataSourceRouteManager)
|
||||
{
|
||||
_dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
|
||||
}
|
||||
|
||||
return _dataSourceRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
public override LocalView<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(this);
|
||||
}
|
||||
}
|
||||
private ITableRouteManager _tableRouteManager;
|
||||
|
||||
protected ITableRouteManager TableRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _tableRouteManager)
|
||||
{
|
||||
_tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
|
||||
}
|
||||
|
||||
return _tableRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
private IEntityMetadataManager _entityMetadataManager;
|
||||
|
||||
protected IEntityMetadataManager EntityMetadataManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _entityMetadataManager)
|
||||
{
|
||||
_entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
|
||||
}
|
||||
|
||||
return _entityMetadataManager;
|
||||
}
|
||||
}
|
||||
|
||||
private ITrackerManager _trackerManager;
|
||||
|
||||
protected ITrackerManager TrackerManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _trackerManager)
|
||||
{
|
||||
_trackerManager = _shardingRuntimeContext.GetTrackerManager();
|
||||
}
|
||||
|
||||
return _trackerManager;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
public override async Task<EntityEntry<TEntity>> AddAsync(TEntity entity, CancellationToken cancellationToken =
|
||||
new CancellationToken())
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, 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>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <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 void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, 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>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> entities)
|
||||
{
|
||||
return entities.Select(o =>
|
||||
{
|
||||
var dbContext = _context.CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
|
||||
}
|
||||
|
||||
public override TEntity Find(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override Task<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override Task<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
return base.FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
private DbContext GetDbContextByKeyValue(params object[] keyValues)
|
||||
{
|
||||
var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
|
||||
if (entityMetadata == null)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException(
|
||||
$"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
|
||||
}
|
||||
|
||||
//既不是分表也不是分库的话就是默认对象
|
||||
if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
|
||||
{
|
||||
var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
|
||||
var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
|
||||
var routeTail = routeTailFactory.Create(string.Empty);
|
||||
return _context.GetShareDbContext(defaultDataSourceName, routeTail);
|
||||
}
|
||||
|
||||
if (keyValues.Length == 1)
|
||||
{
|
||||
//单key字段
|
||||
if (entityMetadata.IsSingleKey)
|
||||
{
|
||||
var isShardingDataSource = entityMetadata.IsShardingDataSource();
|
||||
var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
|
||||
if (isShardingDataSource && !shardingDataSourceFieldIsKey)
|
||||
return null;
|
||||
var isShardingTable = entityMetadata.IsShardingTable();
|
||||
var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
|
||||
if (isShardingTable && !shardingTableFieldIsKey)
|
||||
return null;
|
||||
var primaryKeyValue = keyValues[0];
|
||||
if (primaryKeyValue != null)
|
||||
{
|
||||
var dataSourceName = GetDataSourceName(primaryKeyValue);
|
||||
var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
|
||||
var tableTail = TableRouteManager.GetTableTail<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
#if EFCORE2
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
public class ShardingStateManager:StateManager
|
||||
{
|
||||
private readonly DbContext _currentDbContext;
|
||||
private readonly IShardingDbContext _currentShardingDbContext;
|
||||
|
||||
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
_currentDbContext=dependencies.CurrentContext.Context;
|
||||
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var findEntityType = genericDbContext.Model.FindEntityType(entity.GetType());
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity, findEntityType);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer,
|
||||
ISet<IForeignKey> handledForeignKeys)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = _currentDbContext.Database.BeginTransaction())
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -92,7 +92,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
#if EFCORE3
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 14 August 2021 10:17:43
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
public class ShardingDbSetSource:IDbSetSource
|
||||
{
|
||||
|
||||
private static readonly MethodInfo _genericCreateSet
|
||||
= typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
|
||||
|
||||
private readonly ConcurrentDictionary<Type, Func<DbContext, object>> _cache
|
||||
= new ConcurrentDictionary<Type, Func<DbContext, object>>();
|
||||
|
||||
/// <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 virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, _genericCreateSet);
|
||||
|
||||
private object CreateCore(DbContext context, Type type, MethodInfo createMethod)
|
||||
=> _cache.GetOrAdd(
|
||||
type,
|
||||
t => (Func<DbContext, object>)createMethod
|
||||
.MakeGenericMethod(t)
|
||||
.Invoke(null, null))(context);
|
||||
|
||||
private static Func<DbContext, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> c => new ShardingInternalDbSet<TEntity>(c);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -1,436 +0,0 @@
|
|||
#if EFCORE3
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.Core.TrackerManagers;
|
||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/8/15 8:39:15
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
public class ShardingInternalDbSet<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _localView;
|
||||
|
||||
|
||||
public ShardingInternalDbSet(DbContext context) : base(context)
|
||||
{
|
||||
_context = (IShardingDbContext)context;
|
||||
_shardingRuntimeContext = context.GetShardingRuntimeContext();
|
||||
}
|
||||
|
||||
private IDataSourceRouteManager _dataSourceRouteManager;
|
||||
|
||||
protected IDataSourceRouteManager DataSourceRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _dataSourceRouteManager)
|
||||
{
|
||||
_dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
|
||||
}
|
||||
|
||||
return _dataSourceRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
public override LocalView<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(this);
|
||||
}
|
||||
}
|
||||
private ITableRouteManager _tableRouteManager;
|
||||
|
||||
protected ITableRouteManager TableRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _tableRouteManager)
|
||||
{
|
||||
_tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
|
||||
}
|
||||
|
||||
return _tableRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
private IEntityMetadataManager _entityMetadataManager;
|
||||
|
||||
protected IEntityMetadataManager EntityMetadataManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _entityMetadataManager)
|
||||
{
|
||||
_entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
|
||||
}
|
||||
|
||||
return _entityMetadataManager;
|
||||
}
|
||||
}
|
||||
|
||||
private ITrackerManager _trackerManager;
|
||||
|
||||
protected ITrackerManager TrackerManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _trackerManager)
|
||||
{
|
||||
_trackerManager = _shardingRuntimeContext.GetTrackerManager();
|
||||
}
|
||||
|
||||
return _trackerManager;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
/// <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 async ValueTask<EntityEntry<TEntity>> AddAsync(
|
||||
TEntity entity,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, 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>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <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 void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, 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>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> entities)
|
||||
{
|
||||
return entities.Select(o =>
|
||||
{
|
||||
var dbContext = _context.CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
|
||||
}
|
||||
|
||||
public override TEntity Find(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
private DbContext GetDbContextByKeyValue(params object[] keyValues)
|
||||
{
|
||||
var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
|
||||
if (entityMetadata == null)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException(
|
||||
$"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
|
||||
}
|
||||
|
||||
//既不是分表也不是分库的话就是默认对象
|
||||
if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
|
||||
{
|
||||
var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
|
||||
var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
|
||||
var routeTail = routeTailFactory.Create(string.Empty);
|
||||
return _context.GetShareDbContext(defaultDataSourceName, routeTail);
|
||||
}
|
||||
|
||||
if (keyValues.Length == 1)
|
||||
{
|
||||
//单key字段
|
||||
if (entityMetadata.IsSingleKey)
|
||||
{
|
||||
var isShardingDataSource = entityMetadata.IsShardingDataSource();
|
||||
var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
|
||||
if (isShardingDataSource && !shardingDataSourceFieldIsKey)
|
||||
return null;
|
||||
var isShardingTable = entityMetadata.IsShardingTable();
|
||||
var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
|
||||
if (isShardingTable && !shardingTableFieldIsKey)
|
||||
return null;
|
||||
var primaryKeyValue = keyValues[0];
|
||||
if (primaryKeyValue != null)
|
||||
{
|
||||
var dataSourceName = GetDataSourceName(primaryKeyValue);
|
||||
var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
|
||||
var tableTail = TableRouteManager.GetTableTail<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
#if EFCORE3
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
public class ShardingStateManager:StateManager
|
||||
{
|
||||
private readonly DbContext _currentDbContext;
|
||||
private readonly IShardingDbContext _currentShardingDbContext;
|
||||
|
||||
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
_currentDbContext=dependencies.CurrentContext.Context;
|
||||
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var findEntityType = genericDbContext.Model.FindEntityType(entity.GetType());
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity, findEntityType);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = _currentDbContext.Database.BeginTransaction())
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
await tran.CommitAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -91,7 +91,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
#if EFCORE5
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 14 August 2021 10:17:43
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
public class ShardingDbSetSource : IDbSetSource
|
||||
{
|
||||
|
||||
private static readonly MethodInfo _genericCreateSet
|
||||
= typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
|
||||
|
||||
private readonly ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>> _cache
|
||||
= new ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>>();
|
||||
|
||||
/// <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 virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, null, _genericCreateSet);
|
||||
|
||||
/// <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 virtual object Create(DbContext context, string name, Type type)
|
||||
=> CreateCore(context, type, name, _genericCreateSet);
|
||||
|
||||
private object CreateCore(DbContext context, Type type, string name, MethodInfo createMethod)
|
||||
=> _cache.GetOrAdd(
|
||||
(type, name),
|
||||
t => (Func<DbContext, string, object>)createMethod
|
||||
.MakeGenericMethod(t.Type)
|
||||
.Invoke(null, null))(context, name);
|
||||
|
||||
private static Func<DbContext, string, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> (c, name) => new ShardingInternalDbSet<TEntity>(c, name);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -1,439 +0,0 @@
|
|||
#if EFCORE5
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.Core.TrackerManagers;
|
||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/8/15 8:39:15
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
public class ShardingInternalDbSet<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _localView;
|
||||
|
||||
|
||||
|
||||
public ShardingInternalDbSet(DbContext context, string entityTypeName) : base(context, entityTypeName)
|
||||
{
|
||||
_context = (IShardingDbContext)context;
|
||||
_shardingRuntimeContext = context.GetShardingRuntimeContext();
|
||||
}
|
||||
|
||||
private IDataSourceRouteManager _dataSourceRouteManager;
|
||||
|
||||
protected IDataSourceRouteManager DataSourceRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _dataSourceRouteManager)
|
||||
{
|
||||
_dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
|
||||
}
|
||||
|
||||
return _dataSourceRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
public override LocalView<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(this);
|
||||
}
|
||||
}
|
||||
private ITableRouteManager _tableRouteManager;
|
||||
|
||||
protected ITableRouteManager TableRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _tableRouteManager)
|
||||
{
|
||||
_tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
|
||||
}
|
||||
|
||||
return _tableRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
private IEntityMetadataManager _entityMetadataManager;
|
||||
|
||||
protected IEntityMetadataManager EntityMetadataManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _entityMetadataManager)
|
||||
{
|
||||
_entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
|
||||
}
|
||||
|
||||
return _entityMetadataManager;
|
||||
}
|
||||
}
|
||||
|
||||
private ITrackerManager _trackerManager;
|
||||
|
||||
protected ITrackerManager TrackerManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _trackerManager)
|
||||
{
|
||||
_trackerManager = _shardingRuntimeContext.GetTrackerManager();
|
||||
}
|
||||
|
||||
return _trackerManager;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
/// <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 async ValueTask<EntityEntry<TEntity>> AddAsync(
|
||||
TEntity entity,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, 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>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <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 void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, 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>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> entities)
|
||||
{
|
||||
return entities.Select(o =>
|
||||
{
|
||||
var dbContext = _context.CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
|
||||
}
|
||||
|
||||
public override TEntity Find(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
private DbContext GetDbContextByKeyValue(params object[] keyValues)
|
||||
{
|
||||
var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
|
||||
if (entityMetadata == null)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException(
|
||||
$"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
|
||||
}
|
||||
|
||||
//既不是分表也不是分库的话就是默认对象
|
||||
if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
|
||||
{
|
||||
var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
|
||||
var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
|
||||
var routeTail = routeTailFactory.Create(string.Empty);
|
||||
return _context.GetShareDbContext(defaultDataSourceName, routeTail);
|
||||
}
|
||||
|
||||
if (keyValues.Length == 1)
|
||||
{
|
||||
//单key字段
|
||||
if (entityMetadata.IsSingleKey)
|
||||
{
|
||||
var isShardingDataSource = entityMetadata.IsShardingDataSource();
|
||||
var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
|
||||
if (isShardingDataSource && !shardingDataSourceFieldIsKey)
|
||||
return null;
|
||||
var isShardingTable = entityMetadata.IsShardingTable();
|
||||
var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
|
||||
if (isShardingTable && !shardingTableFieldIsKey)
|
||||
return null;
|
||||
var primaryKeyValue = keyValues[0];
|
||||
if (primaryKeyValue != null)
|
||||
{
|
||||
var dataSourceName = GetDataSourceName(primaryKeyValue);
|
||||
var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
|
||||
var tableTail = TableRouteManager.GetTableTail<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
#if EFCORE5
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
public class ShardingStateManager:StateManager
|
||||
{
|
||||
private readonly DbContext _currentDbContext;
|
||||
private readonly IShardingDbContext _currentShardingDbContext;
|
||||
|
||||
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
_currentDbContext=dependencies.CurrentContext.Context;
|
||||
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var findEntityType = genericDbContext.Model.FindEntityType(entity.GetType());
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity, findEntityType);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = _currentDbContext.Database.BeginTransaction())
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
await tran.CommitAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -91,7 +91,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
#if EFCORE6
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 14 August 2021 10:17:43
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
public class ShardingDbSetSource : IDbSetSource
|
||||
{
|
||||
|
||||
private static readonly MethodInfo _genericCreateSet
|
||||
= typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
|
||||
|
||||
private readonly ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>> _cache
|
||||
= new ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>>();
|
||||
|
||||
/// <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 virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, null, _genericCreateSet);
|
||||
|
||||
/// <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 virtual object Create(DbContext context, string name, Type type)
|
||||
=> CreateCore(context, type, name, _genericCreateSet);
|
||||
|
||||
private object CreateCore(DbContext context, Type type, string name, MethodInfo createMethod)
|
||||
=> _cache.GetOrAdd(
|
||||
(type, name),
|
||||
t => (Func<DbContext, string, object>)createMethod
|
||||
.MakeGenericMethod(t.Type)
|
||||
.Invoke(null, null))(context, name);
|
||||
|
||||
private static Func<DbContext, string, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> (c, name) => new ShardingInternalDbSet<TEntity>(c, name);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -1,436 +0,0 @@
|
|||
#if EFCORE6
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.Core.TrackerManagers;
|
||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/8/15 8:39:15
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingInternalDbSet<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _localView;
|
||||
|
||||
|
||||
|
||||
public ShardingInternalDbSet(DbContext context, string entityTypeName) : base(context, entityTypeName)
|
||||
{
|
||||
_context = (IShardingDbContext)context;
|
||||
_shardingRuntimeContext = context.GetShardingRuntimeContext();
|
||||
}
|
||||
|
||||
private IDataSourceRouteManager _dataSourceRouteManager;
|
||||
|
||||
protected IDataSourceRouteManager DataSourceRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _dataSourceRouteManager)
|
||||
{
|
||||
_dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
|
||||
}
|
||||
|
||||
return _dataSourceRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
public override LocalView<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(this);
|
||||
}
|
||||
}
|
||||
private ITableRouteManager _tableRouteManager;
|
||||
|
||||
protected ITableRouteManager TableRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _tableRouteManager)
|
||||
{
|
||||
_tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
|
||||
}
|
||||
|
||||
return _tableRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
private IEntityMetadataManager _entityMetadataManager;
|
||||
|
||||
protected IEntityMetadataManager EntityMetadataManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _entityMetadataManager)
|
||||
{
|
||||
_entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
|
||||
}
|
||||
|
||||
return _entityMetadataManager;
|
||||
}
|
||||
}
|
||||
|
||||
private ITrackerManager _trackerManager;
|
||||
|
||||
protected ITrackerManager TrackerManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _trackerManager)
|
||||
{
|
||||
_trackerManager = _shardingRuntimeContext.GetTrackerManager();
|
||||
}
|
||||
|
||||
return _trackerManager;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
/// <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 async ValueTask<EntityEntry<TEntity>> AddAsync(
|
||||
TEntity entity,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, 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>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <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 void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, 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>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> entities)
|
||||
{
|
||||
return entities.Select(o =>
|
||||
{
|
||||
var dbContext = _context.CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
|
||||
}
|
||||
|
||||
public override TEntity Find(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
private DbContext GetDbContextByKeyValue(params object[] keyValues)
|
||||
{
|
||||
var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
|
||||
if (entityMetadata == null)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException(
|
||||
$"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
|
||||
}
|
||||
|
||||
//既不是分表也不是分库的话就是默认对象
|
||||
if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
|
||||
{
|
||||
var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
|
||||
var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
|
||||
var routeTail = routeTailFactory.Create(string.Empty);
|
||||
return _context.GetShareDbContext(defaultDataSourceName, routeTail);
|
||||
}
|
||||
|
||||
if (keyValues.Length == 1)
|
||||
{
|
||||
//单key字段
|
||||
if (entityMetadata.IsSingleKey)
|
||||
{
|
||||
var isShardingDataSource = entityMetadata.IsShardingDataSource();
|
||||
var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
|
||||
if (isShardingDataSource && !shardingDataSourceFieldIsKey)
|
||||
return null;
|
||||
var isShardingTable = entityMetadata.IsShardingTable();
|
||||
var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
|
||||
if (isShardingTable && !shardingTableFieldIsKey)
|
||||
return null;
|
||||
var primaryKeyValue = keyValues[0];
|
||||
if (primaryKeyValue != null)
|
||||
{
|
||||
var dataSourceName = GetDataSourceName(primaryKeyValue);
|
||||
var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
|
||||
var tableTail = TableRouteManager.GetTableTail<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
#if EFCORE6
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
public class ShardingStateManager:StateManager
|
||||
{
|
||||
private readonly DbContext _currentDbContext;
|
||||
private readonly IShardingDbContext _currentShardingDbContext;
|
||||
|
||||
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
_currentDbContext=dependencies.CurrentContext.Context;
|
||||
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var findEntityType = genericDbContext.Model.FindEntityType(entity.GetType());
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity, findEntityType);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = _currentDbContext.Database.BeginTransaction())
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
await tran.CommitAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -91,7 +91,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
#if EFCORE7
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 14 August 2021 10:17:43
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingDbSetSource : IDbSetSource
|
||||
{
|
||||
|
||||
private static readonly MethodInfo _genericCreateSet
|
||||
= typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
|
||||
|
||||
private readonly ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>> _cache
|
||||
= new ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>>();
|
||||
|
||||
/// <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 virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, null, _genericCreateSet);
|
||||
|
||||
/// <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 virtual object Create(DbContext context, string name, Type type)
|
||||
=> CreateCore(context, type, name, _genericCreateSet);
|
||||
|
||||
private object CreateCore(DbContext context, Type type, string name, MethodInfo createMethod)
|
||||
=> _cache.GetOrAdd(
|
||||
(type, name),
|
||||
t => (Func<DbContext, string, object>)createMethod
|
||||
.MakeGenericMethod(t.Type)
|
||||
.Invoke(null, null))(context, name);
|
||||
|
||||
private static Func<DbContext, string, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> (c, name) => new ShardingInternalDbSet<TEntity>(c, name);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -1,435 +0,0 @@
|
|||
#if EFCORE7
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.Core.TrackerManagers;
|
||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/8/15 8:39:15
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingInternalDbSet<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _localView;
|
||||
|
||||
public ShardingInternalDbSet(DbContext context, string entityTypeName) : base(context, entityTypeName)
|
||||
{
|
||||
_context = (IShardingDbContext)context;
|
||||
_shardingRuntimeContext = context.GetShardingRuntimeContext();
|
||||
}
|
||||
|
||||
private IDataSourceRouteManager _dataSourceRouteManager;
|
||||
|
||||
protected IDataSourceRouteManager DataSourceRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _dataSourceRouteManager)
|
||||
{
|
||||
_dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
|
||||
}
|
||||
|
||||
return _dataSourceRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
public override LocalView<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(this);
|
||||
}
|
||||
}
|
||||
private ITableRouteManager _tableRouteManager;
|
||||
|
||||
protected ITableRouteManager TableRouteManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _tableRouteManager)
|
||||
{
|
||||
_tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
|
||||
}
|
||||
|
||||
return _tableRouteManager;
|
||||
}
|
||||
}
|
||||
|
||||
private IEntityMetadataManager _entityMetadataManager;
|
||||
|
||||
protected IEntityMetadataManager EntityMetadataManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _entityMetadataManager)
|
||||
{
|
||||
_entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
|
||||
}
|
||||
|
||||
return _entityMetadataManager;
|
||||
}
|
||||
}
|
||||
|
||||
private ITrackerManager _trackerManager;
|
||||
|
||||
protected ITrackerManager TrackerManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _trackerManager)
|
||||
{
|
||||
_trackerManager = _shardingRuntimeContext.GetTrackerManager();
|
||||
}
|
||||
|
||||
return _trackerManager;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
/// <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 async ValueTask<EntityEntry<TEntity>> AddAsync(
|
||||
TEntity entity,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, 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>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <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 EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <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 void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, 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>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> entities)
|
||||
{
|
||||
return entities.Select(o =>
|
||||
{
|
||||
var dbContext = _context.CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
|
||||
}
|
||||
|
||||
public override TEntity Find(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
|
||||
private DbContext GetDbContextByKeyValue(params object[] keyValues)
|
||||
{
|
||||
var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
|
||||
if (entityMetadata == null)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException(
|
||||
$"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
|
||||
}
|
||||
|
||||
//既不是分表也不是分库的话就是默认对象
|
||||
if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
|
||||
{
|
||||
var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
|
||||
var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
|
||||
var routeTail = routeTailFactory.Create(string.Empty);
|
||||
return _context.GetShareDbContext(defaultDataSourceName, routeTail);
|
||||
}
|
||||
|
||||
if (keyValues.Length == 1)
|
||||
{
|
||||
//单key字段
|
||||
if (entityMetadata.IsSingleKey)
|
||||
{
|
||||
var isShardingDataSource = entityMetadata.IsShardingDataSource();
|
||||
var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
|
||||
if (isShardingDataSource && !shardingDataSourceFieldIsKey)
|
||||
return null;
|
||||
var isShardingTable = entityMetadata.IsShardingTable();
|
||||
var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
|
||||
if (isShardingTable && !shardingTableFieldIsKey)
|
||||
return null;
|
||||
var primaryKeyValue = keyValues[0];
|
||||
if (primaryKeyValue != null)
|
||||
{
|
||||
var dataSourceName = GetDataSourceName(primaryKeyValue);
|
||||
var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
|
||||
var tableTail = TableRouteManager.GetTableTail<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using ShardingCore.Sharding.ShardingDbContextExecutors;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
#if EFCORE7
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
public class ShardingStateManager:StateManager
|
||||
{
|
||||
private readonly IShardingDbContext _currentShardingDbContext;
|
||||
|
||||
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
_currentShardingDbContext = (IShardingDbContext)Context;
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
|
||||
{
|
||||
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
|
||||
var findEntityType = genericDbContext.Model.FindEntityType(entity.GetType());
|
||||
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
return stateManager.GetOrCreateEntry(entity, findEntityType);
|
||||
}
|
||||
|
||||
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
|
||||
{
|
||||
throw new ShardingCoreNotImplementedException();
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (Context.Database.AutoTransactionsEnabled&&Context.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = Context.Database.BeginTransaction())
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (Context.Database.AutoTransactionsEnabled && Context.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
|
||||
{
|
||||
using (var tran = await Context.Database.BeginTransactionAsync(cancellationToken))
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
await tran.CommitAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -15,8 +15,11 @@ namespace ShardingCore.Exceptions
|
|||
*/
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ShardingCoreException : Exception
|
||||
{
|
||||
public ShardingCoreException()
|
||||
{
|
||||
|
||||
}
|
||||
public ShardingCoreException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ShardingCoreNotImplementedException:ShardingCoreException
|
||||
{
|
||||
public ShardingCoreNotImplementedException()
|
||||
{
|
||||
|
||||
}
|
||||
public ShardingCoreNotImplementedException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingCoreNotImplementedException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -146,7 +146,7 @@ namespace ShardingCore.Extensions
|
|||
var shardingRuntimeContext = dbContext.GetShardingRuntimeContext();
|
||||
var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager();
|
||||
|
||||
#if EFCORE6 || EFCORE7
|
||||
#if EFCORE6
|
||||
var entityTypes = contextModel.GetEntityTypes();
|
||||
foreach (var entityType in entityTypes)
|
||||
{
|
||||
|
@ -156,17 +156,8 @@ namespace ShardingCore.Extensions
|
|||
}
|
||||
}
|
||||
var contextModelRelationalModel = contextModel.GetRelationalModel() as RelationalModel;
|
||||
foreach (var keyValuePair in contextModelRelationalModel.Tables)
|
||||
{
|
||||
foreach (var valueEntityTypeMapping in keyValuePair.Value.EntityTypeMappings)
|
||||
{
|
||||
var x = !entityMetadataManager.IsOnlyShardingDataSource(valueEntityTypeMapping.EntityType.ClrType);
|
||||
Console.WriteLine(valueEntityTypeMapping.EntityType.ClrType);
|
||||
Console.WriteLine(x);
|
||||
}
|
||||
}
|
||||
var valueTuples =
|
||||
contextModelRelationalModel.Tables.Where(o => o.Value.EntityTypeMappings.Any(m => !entityMetadataManager.IsOnlyShardingDataSource(m.EntityType.ClrType))).Select(o => o.Key).ToList();
|
||||
contextModelRelationalModel.Tables.Where(o => o.Value.EntityTypeMappings.Any(m => !entityMetadataManager.IsShardingDataSource(m.EntityType.ClrType) ||entityMetadataManager.TryGet(m.EntityType.ClrType)==null)).Select(o => o.Key).ToList();
|
||||
for (int i = 0; i < valueTuples.Count; i++)
|
||||
{
|
||||
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
|
||||
|
@ -183,7 +174,7 @@ namespace ShardingCore.Extensions
|
|||
}
|
||||
var contextModelRelationalModel = contextModel.RelationalModel as RelationalModel;
|
||||
var valueTuples =
|
||||
contextModelRelationalModel.Tables.Where(o => o.Value.EntityTypeMappings.Any(m => !entityMetadataManager.IsOnlyShardingDataSource(m.EntityType.ClrType))).Select(o => o.Key).ToList();
|
||||
contextModelRelationalModel.Tables.Where(o => o.Value.EntityTypeMappings.Any(m => !entityMetadataManager.IsShardingDataSource(m.EntityType.ClrType)||entityMetadataManager.TryGet(m.EntityType.ClrType)==null)).Select(o => o.Key).ToList();
|
||||
for (int i = 0; i < valueTuples.Count; i++)
|
||||
{
|
||||
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
|
||||
|
@ -200,7 +191,7 @@ namespace ShardingCore.Extensions
|
|||
_data.Clear();
|
||||
}
|
||||
}
|
||||
var list = entityTypes.Where(o => !entityMetadataManager.IsOnlyShardingDataSource(o.Value.ClrType)).Select(o => o.Key).ToList();
|
||||
var list = entityTypes.Where(o => !entityMetadataManager.IsShardingDataSource(o.Value.ClrType) || entityMetadataManager.TryGet(o.Value.ClrType) == null).Select(o => o.Key).ToList();
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
entityTypes.Remove(list[i]);
|
||||
|
@ -225,7 +216,7 @@ namespace ShardingCore.Extensions
|
|||
var contextModel = dbContext.Model as Model;
|
||||
#endif
|
||||
|
||||
#if EFCORE6|| EFCORE7
|
||||
#if EFCORE6
|
||||
var contextModelRelationalModel = contextModel.GetRelationalModel() as RelationalModel;
|
||||
contextModelRelationalModel.Tables.Clear();
|
||||
#endif
|
||||
|
|
|
@ -14,11 +14,24 @@ using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
|
|||
using ShardingCore.EFCores;
|
||||
using ShardingCore.Sharding;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using ShardingCore.Sharding.ShardingDbContextExecutors;
|
||||
|
||||
namespace ShardingCore.Extensions
|
||||
{
|
||||
public static class ShardingDbContextExtension
|
||||
{
|
||||
public static IShardingDbContextExecutor CreateShardingDbContextExecutor<TDbContext>(
|
||||
this TDbContext shellDbContext)
|
||||
where TDbContext:DbContext,IShardingDbContext
|
||||
{
|
||||
var shardingWrapOptionsExtension = shellDbContext.GetService<IDbContextOptions>().FindExtension<ShardingWrapOptionsExtension>();
|
||||
if (shardingWrapOptionsExtension != null)
|
||||
{
|
||||
return new ShardingDbContextExecutor(shellDbContext);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
public static bool IsUseReadWriteSeparation(this IShardingDbContext shardingDbContext)
|
||||
{
|
||||
return shardingDbContext.GetShardingExecutor().GetVirtualDataSource().UseReadWriteSeparation;
|
||||
|
@ -39,7 +52,7 @@ namespace ShardingCore.Extensions
|
|||
/// <returns></returns>
|
||||
public static DbContext GetShareDbContext(this IShardingDbContext shardingDbContext,string dataSourceName,IRouteTail routeTail)
|
||||
{
|
||||
return shardingDbContext.GetDbContext(dataSourceName, CreateDbContextStrategyEnum.ShareConnection, routeTail);
|
||||
return shardingDbContext.GetShardingExecutor().CreateDbContext(CreateDbContextStrategyEnum.ShareConnection,dataSourceName, routeTail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -51,7 +64,7 @@ namespace ShardingCore.Extensions
|
|||
/// <returns></returns>
|
||||
public static DbContext GetIndependentWriteDbContext(this IShardingDbContext shardingDbContext,string dataSourceName,IRouteTail routeTail)
|
||||
{
|
||||
return shardingDbContext.GetDbContext(dataSourceName, CreateDbContextStrategyEnum.IndependentConnectionWrite, routeTail);
|
||||
return shardingDbContext.GetShardingExecutor().CreateDbContext(CreateDbContextStrategyEnum.IndependentConnectionWrite,dataSourceName, routeTail);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取独立生命周期的读连接字符串的db context
|
||||
|
@ -62,7 +75,7 @@ namespace ShardingCore.Extensions
|
|||
/// <returns></returns>
|
||||
public static DbContext GetIndependentQueryDbContext(this IShardingDbContext shardingDbContext,string dataSourceName,IRouteTail routeTail)
|
||||
{
|
||||
return shardingDbContext.GetDbContext(dataSourceName, CreateDbContextStrategyEnum.IndependentConnectionQuery, routeTail);
|
||||
return shardingDbContext.GetShardingExecutor().CreateDbContext(CreateDbContextStrategyEnum.IndependentConnectionQuery,dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ namespace ShardingCore.Extensions
|
|||
new Dictionary<DbContext, IEnumerable<TEntity>>()
|
||||
{
|
||||
{
|
||||
shardingDbContext.CreateGenericDbContext(entitiesArray[0]),
|
||||
shardingDbContext.GetShardingExecutor().CreateGenericDbContext(entitiesArray[0]),
|
||||
entitiesArray
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ShardingCore.EFCores;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.Sharding
|
||||
{
|
||||
|
@ -23,392 +25,48 @@ namespace ShardingCore.Sharding
|
|||
/// </summary>
|
||||
public abstract class AbstractShardingDbContext : DbContext, IShardingDbContext
|
||||
{
|
||||
protected IShardingDbContextExecutor ShardingDbContextExecutor { get; }
|
||||
|
||||
|
||||
public AbstractShardingDbContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
var wrapOptionsExtension = options.FindExtension<ShardingWrapOptionsExtension>();
|
||||
if (wrapOptionsExtension != null)
|
||||
{
|
||||
ShardingDbContextExecutor = new ShardingDbContextExecutor(this);
|
||||
}
|
||||
|
||||
IsExecutor = wrapOptionsExtension == null;
|
||||
}
|
||||
|
||||
private bool _createExecutor = false;
|
||||
/// <summary>
|
||||
/// 是否是真正的执行者
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public bool IsExecutor { get; }
|
||||
|
||||
|
||||
|
||||
public DbContext GetDbContext(string dataSourceName, CreateDbContextStrategyEnum strategy, IRouteTail routeTail)
|
||||
/// <param name="options"></param>
|
||||
protected AbstractShardingDbContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
return ShardingDbContextExecutor.CreateDbContext(strategy, dataSourceName, routeTail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据对象创建通用的dbcontext
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public DbContext CreateGenericDbContext<TEntity>(TEntity entity) where TEntity : class
|
||||
{
|
||||
return ShardingDbContextExecutor.CreateGenericDbContext(entity);
|
||||
|
||||
}
|
||||
|
||||
private IShardingDbContextExecutor? _shardingDbContextExecutor;
|
||||
public IShardingDbContextExecutor GetShardingExecutor()
|
||||
{
|
||||
return ShardingDbContextExecutor;
|
||||
if (!_createExecutor)
|
||||
{
|
||||
_shardingDbContextExecutor=this.CreateShardingDbContextExecutor();
|
||||
_createExecutor = true;
|
||||
}
|
||||
return _shardingDbContextExecutor;
|
||||
}
|
||||
|
||||
public override EntityEntry Add(object entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
base.Add(entity);
|
||||
return CreateGenericDbContext(entity).Add(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Add<TEntity>(TEntity entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Add(entity);
|
||||
return CreateGenericDbContext(entity).Add(entity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !EFCORE2
|
||||
|
||||
public override ValueTask<EntityEntry<TEntity>> AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.AddAsync(entity, cancellationToken);
|
||||
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
public override ValueTask<EntityEntry> AddAsync(object entity, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.AddAsync(entity, cancellationToken);
|
||||
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
|
||||
}
|
||||
#endif
|
||||
#if EFCORE2
|
||||
public override Task<EntityEntry<TEntity>> AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.AddAsync(entity, cancellationToken);
|
||||
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
public override Task<EntityEntry> AddAsync(object entity, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.AddAsync(entity, cancellationToken);
|
||||
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
|
||||
}
|
||||
#endif
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic<TEntity>(IEnumerable<TEntity> entities) where TEntity:class
|
||||
{
|
||||
return entities.Select(o =>
|
||||
{
|
||||
var dbContext = CreateGenericDbContext(o);
|
||||
return new
|
||||
{
|
||||
DbContext = dbContext,
|
||||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
|
||||
}
|
||||
public override void AddRange(params object[] entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
base.AddRange(entities);
|
||||
return;
|
||||
}
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
base.AddRange(entities);
|
||||
return;
|
||||
}
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task AddRangeAsync(params object[] entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
await base.AddRangeAsync(entities);
|
||||
return;
|
||||
}
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task AddRangeAsync(IEnumerable<object> entities, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
await base.AddRangeAsync(entities, cancellationToken);
|
||||
return;
|
||||
}
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.AddRangeAsync(aggregateKv.Value,cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Attach<TEntity>(TEntity entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Attach(entity);
|
||||
return CreateGenericDbContext(entity).Attach(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Attach(object entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Attach(entity);
|
||||
return CreateGenericDbContext(entity).Attach(entity);
|
||||
}
|
||||
|
||||
public override void AttachRange(params object[] entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
base.AttachRange(entities);
|
||||
return;
|
||||
}
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AttachRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
base.AttachRange(entities);
|
||||
return;
|
||||
}
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//public override DatabaseFacade Database => _dbContextCaches.Any()
|
||||
// ? _dbContextCaches.First().Value.Database
|
||||
// : GetDbContext(true, string.Empty).Database;
|
||||
|
||||
public override EntityEntry<TEntity> Entry<TEntity>(TEntity entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Entry(entity);
|
||||
return CreateGenericDbContext(entity).Entry(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Entry(object entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Entry(entity);
|
||||
return CreateGenericDbContext(entity).Entry(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Update<TEntity>(TEntity entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Update(entity);
|
||||
return CreateGenericDbContext(entity).Update(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Update(object entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Update(entity);
|
||||
return CreateGenericDbContext(entity).Update(entity);
|
||||
}
|
||||
|
||||
public override void UpdateRange(params object[] entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
base.UpdateRange(entities);
|
||||
return;
|
||||
}
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
base.UpdateRange(entities);
|
||||
return;
|
||||
}
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override EntityEntry<TEntity> Remove<TEntity>(TEntity entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Remove(entity);
|
||||
return CreateGenericDbContext(entity).Remove(entity);
|
||||
}
|
||||
|
||||
public override EntityEntry Remove(object entity)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.Remove(entity);
|
||||
return CreateGenericDbContext(entity).Remove(entity);
|
||||
}
|
||||
|
||||
public override void RemoveRange(params object[] entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
base.RemoveRange(entities);
|
||||
return;
|
||||
}
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveRange(IEnumerable<object> entities)
|
||||
{
|
||||
if (IsExecutor)
|
||||
{
|
||||
base.RemoveRange(entities);
|
||||
return;
|
||||
}
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override int SaveChanges(bool acceptAllChangesOnSuccess)
|
||||
{
|
||||
if (IsExecutor)
|
||||
return base.SaveChanges(acceptAllChangesOnSuccess);
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (Database.AutoTransactionsEnabled&&Database.CurrentTransaction==null&&ShardingDbContextExecutor.IsMultiDbContext)
|
||||
{
|
||||
using (var tran = Database.BeginTransaction())
|
||||
{
|
||||
i = ShardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess);
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = ShardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
if (IsExecutor)
|
||||
return await base.SaveChangesAsync(acceptAllChangesOnSuccess,cancellationToken);
|
||||
//ApplyShardingConcepts();
|
||||
int i = 0;
|
||||
//如果是内部开的事务就内部自己消化
|
||||
if (Database.AutoTransactionsEnabled && Database.CurrentTransaction==null && ShardingDbContextExecutor.IsMultiDbContext)
|
||||
{
|
||||
using (var tran = await Database.BeginTransactionAsync(cancellationToken))
|
||||
{
|
||||
i = await ShardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
#if EFCORE2
|
||||
tran.Commit();
|
||||
#endif
|
||||
#if !EFCORE2
|
||||
await tran.CommitAsync(cancellationToken);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = await ShardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
/// <summary>
|
||||
/// 当前dbcontext是否是执行的dbcontext
|
||||
/// </summary>
|
||||
public bool IsExecutor => GetShardingExecutor() == default;
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
if (IsExecutor)
|
||||
{
|
||||
_shardingDbContextExecutor?.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
ShardingDbContextExecutor.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
#if !EFCORE2
|
||||
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
if (IsExecutor)
|
||||
if (_shardingDbContextExecutor!=null)
|
||||
{
|
||||
await base.DisposeAsync();
|
||||
await _shardingDbContextExecutor.DisposeAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await ShardingDbContextExecutor.DisposeAsync();
|
||||
|
||||
await base.DisposeAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -13,23 +13,6 @@ namespace ShardingCore.Sharding.Abstractions
|
|||
*/
|
||||
public interface IShardingDbContext
|
||||
{
|
||||
/// <summary>
|
||||
/// create DbContext
|
||||
/// </summary>
|
||||
/// <param name="dataSourceName">data source</param>
|
||||
/// <param name="strategy">生成db connection的策略,主要区别在于是否和主db connection一直或者是否需要缓存其connection还有是否是独立声明周期的区别</param>
|
||||
/// <param name="routeTail"></param>
|
||||
/// <returns></returns>
|
||||
DbContext GetDbContext(string dataSourceName, CreateDbContextStrategyEnum strategy, IRouteTail routeTail);
|
||||
|
||||
/// <summary>
|
||||
/// 创建通用的db context
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
DbContext CreateGenericDbContext<T>(T entity) where T : class;
|
||||
|
||||
IShardingDbContextExecutor GetShardingExecutor();
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,22 @@ namespace ShardingCore.Sharding.Abstractions
|
|||
|
||||
#endif
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用对象创建db context的前执行
|
||||
/// </summary>
|
||||
event EventHandler<EntityCreateDbContextBeforeEventArgs> EntityCreateDbContextBefore;
|
||||
/// <summary>
|
||||
/// 使用对象创建db context的后执行
|
||||
/// </summary>
|
||||
event EventHandler<EntityCreateDbContextAfterEventArgs> EntityCreateDbContextAfter;
|
||||
/// <summary>
|
||||
/// 使用tail创建db context的前执行
|
||||
/// </summary>
|
||||
event EventHandler<CreateDbContextBeforeEventArgs> CreateDbContextBefore;
|
||||
/// <summary>
|
||||
/// 使用tail创建db context的后执行
|
||||
/// </summary>
|
||||
event EventHandler<CreateDbContextAfterEventArgs> CreateDbContextAfter;
|
||||
/// <summary>
|
||||
/// has multi db context
|
||||
/// </summary>
|
||||
|
@ -52,5 +68,7 @@ namespace ShardingCore.Sharding.Abstractions
|
|||
|
||||
int SaveChanges(bool acceptAllChangesOnSuccess);
|
||||
|
||||
DbContext GetShellDbContext();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
|
||||
|
||||
namespace ShardingCore.Sharding.Abstractions
|
||||
{
|
||||
public class EntityCreateDbContextBeforeEventArgs: EventArgs
|
||||
{
|
||||
public object Entity { get; }
|
||||
|
||||
public EntityCreateDbContextBeforeEventArgs(object entity)
|
||||
{
|
||||
Entity = entity;
|
||||
}
|
||||
}
|
||||
public class CreateDbContextBeforeEventArgs: EventArgs
|
||||
{
|
||||
public CreateDbContextStrategyEnum Strategy { get; }
|
||||
public string DataSourceName { get; }
|
||||
public IRouteTail RouteTail { get; }
|
||||
|
||||
public CreateDbContextBeforeEventArgs(CreateDbContextStrategyEnum strategy, string dataSourceName, IRouteTail routeTail)
|
||||
{
|
||||
Strategy = strategy;
|
||||
DataSourceName = dataSourceName;
|
||||
RouteTail = routeTail;
|
||||
}
|
||||
}
|
||||
public class CreateDbContextAfterEventArgs: EventArgs
|
||||
{
|
||||
public CreateDbContextStrategyEnum Strategy { get; }
|
||||
public string DataSourceName { get; }
|
||||
public IRouteTail RouteTail { get; }
|
||||
public DbContext DbContext { get; }
|
||||
|
||||
public CreateDbContextAfterEventArgs(CreateDbContextStrategyEnum strategy, string dataSourceName, IRouteTail routeTail,DbContext dbContext)
|
||||
{
|
||||
Strategy = strategy;
|
||||
DataSourceName = dataSourceName;
|
||||
RouteTail = routeTail;
|
||||
DbContext = dbContext;
|
||||
}
|
||||
}
|
||||
public class EntityCreateDbContextAfterEventArgs: EventArgs
|
||||
{
|
||||
public object Entity { get; }
|
||||
public DbContext DbContext { get; }
|
||||
|
||||
public EntityCreateDbContextAfterEventArgs(object entity,DbContext dbContext)
|
||||
{
|
||||
Entity = entity;
|
||||
DbContext = dbContext;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,10 +37,10 @@ namespace ShardingCore.Sharding.Enumerators.AggregateExtensions
|
|||
}
|
||||
else
|
||||
{
|
||||
var parameters = allProperties.Select(o => o.GetValue(source)).ToArray();
|
||||
if (anonType.GetConstructors().Length == 1 &&
|
||||
anonType.GetConstructors()[0].GetParameters().Length == allPropertyTypes.Length)
|
||||
{
|
||||
var parameters = allProperties.Select(o => o.GetValue(source)).ToArray();
|
||||
return (TSource)Activator.CreateInstance(anonType, parameters);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -35,6 +35,13 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
|
|||
/// <typeparam name="TShardingDbContext"></typeparam>
|
||||
public class ShardingDbContextExecutor : IShardingDbContextExecutor
|
||||
{
|
||||
|
||||
|
||||
public event EventHandler<EntityCreateDbContextBeforeEventArgs> EntityCreateDbContextBefore;
|
||||
public event EventHandler<EntityCreateDbContextAfterEventArgs> EntityCreateDbContextAfter;
|
||||
public event EventHandler<CreateDbContextBeforeEventArgs> CreateDbContextBefore;
|
||||
public event EventHandler<CreateDbContextAfterEventArgs> CreateDbContextAfter;
|
||||
|
||||
private readonly ILogger<ShardingDbContextExecutor> _logger;
|
||||
private readonly DbContext _shardingDbContext;
|
||||
|
||||
|
@ -106,19 +113,29 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
|
|||
public DbContext CreateDbContext(CreateDbContextStrategyEnum strategy, string dataSourceName,
|
||||
IRouteTail routeTail)
|
||||
{
|
||||
if (CreateDbContextBefore != null)
|
||||
{
|
||||
CreateDbContextBefore.Invoke(this,new CreateDbContextBeforeEventArgs(strategy,dataSourceName,routeTail));
|
||||
}
|
||||
|
||||
DbContext dbContext;
|
||||
if (CreateDbContextStrategyEnum.ShareConnection == strategy)
|
||||
{
|
||||
var dataSourceDbContext = GetDataSourceDbContext(dataSourceName);
|
||||
return dataSourceDbContext.CreateDbContext(routeTail);
|
||||
dbContext= dataSourceDbContext.CreateDbContext(routeTail);
|
||||
}
|
||||
else
|
||||
{
|
||||
var parallelDbContextOptions = CreateParallelDbContextOptions(dataSourceName, strategy);
|
||||
var dbContext =
|
||||
dbContext =
|
||||
_dbContextCreator.CreateDbContext(_shardingDbContext, parallelDbContextOptions, routeTail);
|
||||
dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
return dbContext;
|
||||
}
|
||||
if (CreateDbContextAfter != null)
|
||||
{
|
||||
CreateDbContextAfter.Invoke(this,new CreateDbContextAfterEventArgs(strategy,dataSourceName,routeTail,dbContext));
|
||||
}
|
||||
return dbContext;
|
||||
}
|
||||
|
||||
private DbContextOptions CreateParallelDbContextOptions(string dataSourceName,
|
||||
|
@ -136,12 +153,25 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
|
|||
|
||||
public DbContext CreateGenericDbContext<TEntity>(TEntity entity) where TEntity : class
|
||||
{
|
||||
|
||||
if (EntityCreateDbContextBefore != null)
|
||||
{
|
||||
EntityCreateDbContextBefore.Invoke(this,new EntityCreateDbContextBeforeEventArgs(entity));
|
||||
}
|
||||
|
||||
var realEntityType = _trackerManager.TranslateEntityType(entity.GetType());
|
||||
var dataSourceName = GetDataSourceName(entity,realEntityType);
|
||||
var tail = GetTableTail(dataSourceName, entity,realEntityType);
|
||||
|
||||
return CreateDbContext(CreateDbContextStrategyEnum.ShareConnection, dataSourceName,
|
||||
var dbContext = CreateDbContext(CreateDbContextStrategyEnum.ShareConnection, dataSourceName,
|
||||
_routeTailFactory.Create(tail));
|
||||
|
||||
if (EntityCreateDbContextAfter != null)
|
||||
{
|
||||
EntityCreateDbContextAfter.Invoke(this,new EntityCreateDbContextAfterEventArgs(entity,dbContext));
|
||||
}
|
||||
|
||||
return dbContext;
|
||||
}
|
||||
|
||||
public IVirtualDataSource GetVirtualDataSource()
|
||||
|
@ -190,6 +220,11 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
|
|||
return i;
|
||||
}
|
||||
|
||||
public DbContext GetShellDbContext()
|
||||
{
|
||||
return _shardingDbContext;
|
||||
}
|
||||
|
||||
public void NotifyShardingTransaction()
|
||||
{
|
||||
foreach (var dbContextCache in _dbContextCaches)
|
||||
|
@ -355,5 +390,7 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -191,7 +191,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
|
|||
var strategy = !IsParallelQuery()
|
||||
? CreateDbContextStrategyEnum.ShareConnection
|
||||
: CreateDbContextStrategyEnum.IndependentConnectionQuery;
|
||||
var dbContext = GetShardingDbContext().GetDbContext(sqlRouteUnit.DataSourceName,strategy , routeTailFactory.Create(sqlRouteUnit.TableRouteResult));
|
||||
var dbContext = GetShardingDbContext().GetShardingExecutor().CreateDbContext(strategy,sqlRouteUnit.DataSourceName, routeTailFactory.Create(sqlRouteUnit.TableRouteResult));
|
||||
_queryCompilerExecutor = new QueryCompilerExecutor(dbContext, GetQueryExpression());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
|
|||
var strategy = !IsParallelQuery()
|
||||
? CreateDbContextStrategyEnum.ShareConnection
|
||||
: CreateDbContextStrategyEnum.IndependentConnectionQuery;
|
||||
var dbContext = _shardingDbContext.GetDbContext(virtualDataSource.DefaultDataSourceName, strategy, routeTailFactory.Create(string.Empty));
|
||||
var dbContext = _shardingDbContext.GetShardingExecutor().CreateDbContext(strategy,virtualDataSource.DefaultDataSourceName, routeTailFactory.Create(string.Empty));
|
||||
_queryCompilerExecutor = new QueryCompilerExecutor(dbContext, _queryExpression);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ namespace ShardingCore.Sharding
|
|||
{
|
||||
var routeTail = _routeTailFactory.Create(sqlRouteUnit.TableRouteResult);
|
||||
|
||||
var dbContext = GetShardingDbContext().GetDbContext(sqlRouteUnit.DataSourceName, CreateDbContextStrategyEnum.IndependentConnectionQuery, routeTail);
|
||||
var dbContext = GetShardingDbContext().GetShardingExecutor().CreateDbContext(CreateDbContextStrategyEnum.IndependentConnectionQuery,sqlRouteUnit.DataSourceName, routeTail);
|
||||
_parallelDbContexts.TryAdd(dbContext, null);
|
||||
|
||||
return dbContext;
|
||||
|
|
|
@ -123,12 +123,11 @@ namespace ShardingCore
|
|||
shardingConfigOptions.ShardingMigrationConfigure?.Invoke(dbContextOptionsBuilder);
|
||||
var virtualDataSource = shardingRuntimeContext.GetVirtualDataSource();
|
||||
var connectionString = virtualDataSource.GetConnectionString(virtualDataSource.DefaultDataSourceName);
|
||||
var contextOptionsBuilder = virtualDataSource.ConfigurationParams
|
||||
virtualDataSource.ConfigurationParams
|
||||
.UseDbContextOptionsBuilder(connectionString, dbContextOptionsBuilder)
|
||||
.UseShardingMigrator()
|
||||
.UseSharding(shardingRuntimeContext);
|
||||
|
||||
virtualDataSource.ConfigurationParams.UseShellDbContextOptionBuilder(contextOptionsBuilder);
|
||||
virtualDataSource.ConfigurationParams.UseShellDbContextOptionBuilder(dbContextOptionsBuilder);
|
||||
return dbContextOptionsBuilder;
|
||||
}
|
||||
|
||||
|
@ -210,18 +209,27 @@ namespace ShardingCore
|
|||
return services;
|
||||
}
|
||||
|
||||
#pragma warning disable EF1001
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="optionsBuilder"></param>
|
||||
/// <param name="shardingRuntimeContext"></param>
|
||||
/// <returns></returns>
|
||||
public static DbContextOptionsBuilder UseSharding(
|
||||
this DbContextOptionsBuilder optionsBuilder, IShardingRuntimeContext shardingRuntimeContext)
|
||||
{
|
||||
return optionsBuilder.UseShardingWrapMark().UseShardingOptions(shardingRuntimeContext)
|
||||
.ReplaceService<IDbSetSource, ShardingDbSetSource>()
|
||||
return optionsBuilder
|
||||
.UseShardingWrapMark()
|
||||
.UseShardingMigrator()
|
||||
.UseShardingOptions(shardingRuntimeContext)
|
||||
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
|
||||
.ReplaceService<IChangeTrackerFactory, ShardingChangeTrackerFactory>()
|
||||
.ReplaceService<IDbContextTransactionManager,
|
||||
ShardingRelationalTransactionManager>()
|
||||
.ReplaceService<IRelationalTransactionFactory,
|
||||
ShardingRelationalTransactionFactory>();
|
||||
.ReplaceService<IDbContextTransactionManager,ShardingRelationalTransactionManager>()
|
||||
.ReplaceService<IStateManager,ShardingStateManager>()
|
||||
.ReplaceService<IRelationalTransactionFactory,ShardingRelationalTransactionFactory>();
|
||||
}
|
||||
#pragma warning restore EF1001
|
||||
|
||||
public static DbContextOptionsBuilder UseShardingMigrator(
|
||||
this DbContextOptionsBuilder optionsBuilder)
|
||||
|
@ -246,12 +254,10 @@ namespace ShardingCore
|
|||
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(shardingWrapExtension);
|
||||
return optionsBuilder;
|
||||
}
|
||||
|
||||
private static ShardingWrapOptionsExtension CreateOrGetShardingWrapExtension(
|
||||
this DbContextOptionsBuilder optionsBuilder)
|
||||
=> optionsBuilder.Options.FindExtension<ShardingWrapOptionsExtension>() ??
|
||||
new ShardingWrapOptionsExtension();
|
||||
|
||||
private static ShardingOptionsExtension CreateOrGetShardingOptionsExtension(
|
||||
this DbContextOptionsBuilder optionsBuilder, IShardingRuntimeContext shardingRuntimeContext) =>
|
||||
optionsBuilder.Options.FindExtension<ShardingOptionsExtension>() ??
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
<Compile Include="..\..\src\ShardingCore\**\*.cs" />
|
||||
<Compile Remove="..\..\src\ShardingCore\obj\**" />
|
||||
<Compile Remove="..\..\src\ShardingCore\bin\**" />
|
||||
<Compile Update="..\..\src\ShardingCore\EFCores\EFCore6x\ShardingStateManager.cs">
|
||||
<Link>EFCores\EFCore6x\ShardingStateManager.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.6" />
|
||||
|
|
Loading…
Reference in New Issue