添加codefirst并且优化自动追踪

This commit is contained in:
xuejiaming 2021-10-07 04:53:54 +08:00
parent 2a9d3fff98
commit 47ca273377
38 changed files with 900 additions and 32 deletions

View File

@ -45,6 +45,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src5x", "src5x", "{EB1C9149
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.5x", "src5x\ShardingCore.5x\ShardingCore.5x.csproj", "{68A9F118-EF0A-4D03-8845-77D084561A28}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.5x", "src5x\ShardingCore.5x\ShardingCore.5x.csproj", "{68A9F118-EF0A-4D03-8845-77D084561A28}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Migrations", "samples\Sample.Migrations\Sample.Migrations.csproj", "{648DCBBE-BE8F-4EAC-8367-FE7BC558DA8C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -111,6 +113,10 @@ Global
{68A9F118-EF0A-4D03-8845-77D084561A28}.Debug|Any CPU.Build.0 = Debug|Any CPU {68A9F118-EF0A-4D03-8845-77D084561A28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68A9F118-EF0A-4D03-8845-77D084561A28}.Release|Any CPU.ActiveCfg = Release|Any CPU {68A9F118-EF0A-4D03-8845-77D084561A28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68A9F118-EF0A-4D03-8845-77D084561A28}.Release|Any CPU.Build.0 = Release|Any CPU {68A9F118-EF0A-4D03-8845-77D084561A28}.Release|Any CPU.Build.0 = Release|Any CPU
{648DCBBE-BE8F-4EAC-8367-FE7BC558DA8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{648DCBBE-BE8F-4EAC-8367-FE7BC558DA8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{648DCBBE-BE8F-4EAC-8367-FE7BC558DA8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{648DCBBE-BE8F-4EAC-8367-FE7BC558DA8C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -131,6 +137,7 @@ Global
{E4DAA43A-B64D-45CF-81B8-7B8FD338D686} = {CC2C88C0-65F2-445D-BE78-973B840FE281} {E4DAA43A-B64D-45CF-81B8-7B8FD338D686} = {CC2C88C0-65F2-445D-BE78-973B840FE281}
{0193E3CF-F2FD-449A-B2D5-7F68E551FDBF} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} {0193E3CF-F2FD-449A-B2D5-7F68E551FDBF} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73}
{68A9F118-EF0A-4D03-8845-77D084561A28} = {EB1C9149-78C9-4D99-BE3F-B80FE2015E96} {68A9F118-EF0A-4D03-8845-77D084561A28} = {EB1C9149-78C9-4D99-BE3F-B80FE2015E96}
{648DCBBE-BE8F-4EAC-8367-FE7BC558DA8C} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8C07A667-E8B4-43C7-8053-721584BAD291} SolutionGuid = {8C07A667-E8B4-43C7-8053-721584BAD291}

View File

@ -82,7 +82,7 @@ namespace Sample.BulkConsole
var queryable = myShardingDbContext.Set<Order>().Where(o => o.CreateTime >= b).OrderBy(o => o.CreateTime); var queryable = myShardingDbContext.Set<Order>().Where(o => o.CreateTime >= b).OrderBy(o => o.CreateTime);
var startNew1 = Stopwatch.StartNew(); var startNew1 = Stopwatch.StartNew();
int skip = 0, take = 10; int skip = 0, take = 1000;
for (int i = 20000; i < 30000; i++) for (int i = 20000; i < 30000; i++)
{ {
skip = take * i; skip = take * i;

View File

@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Sample.Migrations.EFCores;
namespace Sample.Migrations.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
private readonly DefaultShardingTableDbContext _context;
public WeatherForecastController(ILogger<WeatherForecastController> logger,DefaultShardingTableDbContext context)
{
_logger = logger;
_context = context;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
_context.Database.Migrate();
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}

View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.DependencyInjection;
using Sample.Migrations.EFCores;
using ShardingCore;
namespace Sample.Migrations
{
public class DefaultDesignTimeDbContextFactory: IDesignTimeDbContextFactory<DefaultShardingTableDbContext>
{
static DefaultDesignTimeDbContextFactory()
{
var services = new ServiceCollection();
services.AddShardingDbContext<DefaultShardingTableDbContext, DefaultTableDbContext>(
o =>
o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;")
.ReplaceService<IMigrationsSqlGenerator, ShardingSqlServerMigrationsSqlGenerator<DefaultShardingTableDbContext>>()
).Begin(o =>
{
o.CreateShardingTableOnStart = true;
o.EnsureCreatedWithOutShardingTable = true;
o.AutoTrackEntity = true;
})
.AddShardingQuery((conStr, builder) => builder.UseSqlServer(conStr)
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking))
.AddShardingTransaction((connection, builder) =>
builder.UseSqlServer(connection))
.AddDefaultDataSource("ds0",
"Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;")
.AddShardingTableRoute(o =>
{
o.AddShardingTableRoute<ShardingWithModVirtualTableRoute>();
o.AddShardingTableRoute<ShardingWithDateTimeVirtualTableRoute>();
}).End();
services.AddLogging();
var buildServiceProvider = services.BuildServiceProvider();
ShardingContainer.SetServices(buildServiceProvider);
new ShardingBootstrapper(buildServiceProvider).Start();
}
public DefaultShardingTableDbContext CreateDbContext(string[] args)
{
var dbContextOptions = new DbContextOptionsBuilder<DefaultShardingTableDbContext>().UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;").Options;
return new DefaultShardingTableDbContext(dbContextOptions);
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding;
namespace Sample.Migrations.EFCores
{
public class DefaultShardingTableDbContext:AbstractShardingDbContext<DefaultTableDbContext>
{
public DefaultShardingTableDbContext(DbContextOptions options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new NoShardingTableMap());
modelBuilder.ApplyConfiguration(new ShardingWithModMap());
modelBuilder.ApplyConfiguration(new ShardingWithDateTimeMap());
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Sharding.Abstractions;
namespace Sample.Migrations.EFCores
{
public class DefaultTableDbContext:DbContext,IShardingTableDbContext
{
public DefaultTableDbContext(DbContextOptions<DefaultTableDbContext> options):base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new NoShardingTableMap());
modelBuilder.ApplyConfiguration(new ShardingWithModMap());
modelBuilder.ApplyConfiguration(new ShardingWithDateTimeMap());
}
public IRouteTail RouteTail { get; set; }
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Sample.Migrations.EFCores
{
public class NoShardingTable
{
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class NoShardingTableMap : IEntityTypeConfiguration<NoShardingTable>
{
public void Configure(EntityTypeBuilder<NoShardingTable> builder)
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128);
builder.ToTable(nameof(NoShardingTable));
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using ShardingCore.Helpers;
using ShardingCore.Sharding.Abstractions;
namespace Sample.Migrations.EFCores
{
/// <summary>
/// https://github.com/Coldairarrow/EFCore.Sharding/blob/master/src/EFCore.Sharding.SqlServer/ShardingSqlServerMigrationsSqlGenerator.cs
/// </summary>
public class ShardingSqlServerMigrationsSqlGenerator<TShardingDbContext> : SqlServerMigrationsSqlGenerator where TShardingDbContext:DbContext,IShardingDbContext
{
public ShardingSqlServerMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, IRelationalAnnotationProvider migrationsAnnotations) : base(dependencies, migrationsAnnotations)
{
}
protected override void Generate(
MigrationOperation operation,
IModel model,
MigrationCommandListBuilder builder)
{
var oldCmds = builder.GetCommandList().ToList();
base.Generate(operation, model, builder);
var newCmds = builder.GetCommandList().ToList();
var addCmds = newCmds.Where(x => !oldCmds.Contains(x)).ToList();
MigrationHelper.Generate<TShardingDbContext>(operation, builder, Dependencies.SqlGenerationHelper, addCmds);
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ShardingCore.Core;
using ShardingCore.VirtualRoutes.Months;
namespace Sample.Migrations.EFCores
{
public class ShardingWithDateTime:IShardingTable
{
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
[ShardingTableKey]
public DateTime CreateTime { get; set; }
}
public class ShardingWithDateTimeMap : IEntityTypeConfiguration<ShardingWithDateTime>
{
public void Configure(EntityTypeBuilder<ShardingWithDateTime> builder)
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128);
builder.ToTable(nameof(ShardingWithDateTime));
}
}
public class ShardingWithDateTimeVirtualTableRoute : AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<ShardingWithDateTime>
{
public override DateTime GetBeginTime()
{
return new DateTime(2021, 9, 1);
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ShardingCore.Core;
using ShardingCore.VirtualRoutes.Mods;
using ShardingCore.VirtualRoutes.Months;
namespace Sample.Migrations.EFCores
{
public class ShardingWithMod:IShardingTable
{
[ShardingTableKey]
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class ShardingWithModMap : IEntityTypeConfiguration<ShardingWithMod>
{
public void Configure(EntityTypeBuilder<ShardingWithMod> builder)
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128);
builder.ToTable(nameof(ShardingWithMod));
}
}
public class ShardingWithModVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<ShardingWithMod>
{
public ShardingWithModVirtualTableRoute() : base(2, 3)
{
}
}
}

View File

@ -0,0 +1,86 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sample.Migrations.EFCores;
namespace Sample.Migrations.Migrations.ShardingMigrations
{
[DbContext(typeof(DefaultShardingTableDbContext))]
[Migration("20211006202136_EFCoreSharding")]
partial class EFCoreSharding
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.10")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Sample.Migrations.EFCores.NoShardingTable", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("NoShardingTable");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<DateTime>("CreateTime")
.HasColumnType("datetime2");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("ShardingWithDateTime");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("ShardingWithMod");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,63 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Sample.Migrations.Migrations.ShardingMigrations
{
public partial class EFCoreSharding : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "NoShardingTable",
columns: table => new
{
Id = table.Column<string>(type: "varchar(128)", unicode: false, maxLength: 128, nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Age = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_NoShardingTable", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ShardingWithDateTime",
columns: table => new
{
Id = table.Column<string>(type: "varchar(128)", unicode: false, maxLength: 128, nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Age = table.Column<int>(type: "int", nullable: false),
CreateTime = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ShardingWithDateTime", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ShardingWithMod",
columns: table => new
{
Id = table.Column<string>(type: "varchar(128)", unicode: false, maxLength: 128, nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Age = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ShardingWithMod", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "NoShardingTable");
migrationBuilder.DropTable(
name: "ShardingWithDateTime");
migrationBuilder.DropTable(
name: "ShardingWithMod");
}
}
}

View File

@ -0,0 +1,84 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sample.Migrations.EFCores;
namespace Sample.Migrations.Migrations.ShardingMigrations
{
[DbContext(typeof(DefaultShardingTableDbContext))]
partial class DefaultShardingTableDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.10")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Sample.Migrations.EFCores.NoShardingTable", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("NoShardingTable");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<DateTime>("CreateTime")
.HasColumnType("datetime2");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("ShardingWithDateTime");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("ShardingWithMod");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sample.Migrations
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

View File

@ -0,0 +1,31 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:7924",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Sample.Migrations": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,78 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using Sample.Migrations.EFCores;
using ShardingCore;
namespace Sample.Migrations
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddShardingDbContext<DefaultShardingTableDbContext, DefaultTableDbContext>(
o =>
o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;")
.ReplaceService<IMigrationsSqlGenerator,ShardingSqlServerMigrationsSqlGenerator<DefaultShardingTableDbContext>>()
).Begin(o =>
{
o.CreateShardingTableOnStart = false;
o.EnsureCreatedWithOutShardingTable = false;
o.AutoTrackEntity = true;
})
.AddShardingQuery((conStr, builder) => builder.UseSqlServer(conStr)
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking))
.AddShardingTransaction((connection, builder) =>
builder.UseSqlServer(connection))
.AddDefaultDataSource("ds0",
"Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;")
.AddShardingTableRoute(o =>
{
o.AddShardingTableRoute<ShardingWithModVirtualTableRoute>();
o.AddShardingTableRoute<ShardingWithDateTimeVirtualTableRoute>();
}).End();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();
shardingBootstrapper.Start();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace Sample.Migrations
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

View File

@ -34,7 +34,7 @@
// [HttpGet] // [HttpGet]
// public async Task<IActionResult> Get() // public async Task<IActionResult> Get()
// { // {
// var taleAllTails = _virtualTableManager.GetVirtualTable(typeof(SysUserLogByMonth)).GetTaleAllTails(); // var taleAllTails = _virtualTableManager.GetVirtualTable(typeof(SysUserLogByMonth)).GetTableAllTails();
// //
// //
// var result = await _defaultTableDbContext.Set<SysTest>().AnyAsync(); // var result = await _defaultTableDbContext.Set<SysTest>().AnyAsync();

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
@ -38,6 +39,8 @@ namespace Sample.SqlServer
o.CreateShardingTableOnStart = true; o.CreateShardingTableOnStart = true;
o.EnsureCreatedWithOutShardingTable = true; o.EnsureCreatedWithOutShardingTable = true;
o.AutoTrackEntity = true; o.AutoTrackEntity = true;
o.ParallelQueryMaxThreadCount = 100;
o.ParallelQueryTimeOut=TimeSpan.FromSeconds(10);
}) })
.AddShardingQuery((conStr, builder) => builder.UseSqlServer(conStr).UseLoggerFactory(efLogger) .AddShardingQuery((conStr, builder) => builder.UseSqlServer(conStr).UseLoggerFactory(efLogger)
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)) .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking))

View File

@ -34,7 +34,6 @@ namespace ShardingCore.Core.VirtualDatabase.VirtualDataSources
public List<string> RouteTo(Type entityType,ShardingDataSourceRouteConfig routeRouteConfig) public List<string> RouteTo(Type entityType,ShardingDataSourceRouteConfig routeRouteConfig)
{ {
var shardingEntityConfig = ShardingUtil.Parse(entityType);
var virtualDataSourceRoute = GetRoute( entityType); var virtualDataSourceRoute = GetRoute( entityType);
if (routeRouteConfig.UseQueryable()) if (routeRouteConfig.UseQueryable())
@ -46,7 +45,10 @@ namespace ShardingCore.Core.VirtualDatabase.VirtualDataSources
shardingKeyValue = routeRouteConfig.GetShardingKeyValue(); shardingKeyValue = routeRouteConfig.GetShardingKeyValue();
if (routeRouteConfig.UseEntity()) if (routeRouteConfig.UseEntity())
{
var shardingEntityConfig = ShardingUtil.Parse(entityType);
shardingKeyValue = routeRouteConfig.GetShardingDataSource().GetPropertyValue(shardingEntityConfig.ShardingDataSourceField); shardingKeyValue = routeRouteConfig.GetShardingDataSource().GetPropertyValue(shardingEntityConfig.ShardingDataSourceField);
}
if (shardingKeyValue != null) if (shardingKeyValue != null)
{ {

View File

@ -111,7 +111,7 @@ namespace ShardingCore.Core.VirtualTables
return GetVirtualRoute(); return GetVirtualRoute();
} }
public List<string> GetTaleAllTails() public List<string> GetTableAllTails()
{ {
return _physicTables.Keys.Select(o => o.Tail).ToList(); return _physicTables.Keys.Select(o => o.Tail).ToList();
} }

View File

@ -77,7 +77,7 @@ namespace ShardingCore.Core.VirtualTables
/// <see cref="ShardingBootstrapper"/> CreateDateTables /// <see cref="ShardingBootstrapper"/> CreateDateTables
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
List<string> GetTaleAllTails(); List<string> GetTableAllTails();
} }
public interface IVirtualTable<T> : IVirtualTable where T : class,IShardingTable public interface IVirtualTable<T> : IVirtualTable where T : class,IShardingTable

View File

@ -41,7 +41,7 @@ namespace ShardingCore.EFCores
var singleQueryRouteTail = (ISingleQueryRouteTail) shardingTableDbContext.RouteTail; var singleQueryRouteTail = (ISingleQueryRouteTail) shardingTableDbContext.RouteTail;
var tail = singleQueryRouteTail.GetTail(); var tail = singleQueryRouteTail.GetTail();
var virtualTableManager = ShardingContainer.GetService<IVirtualTableManager<TShardingDbContext>>(); var virtualTableManager = ShardingContainer.GetService<IVirtualTableManager<TShardingDbContext>>();
var typeMap = virtualTableManager.GetAllVirtualTables().Where(o => o.GetTaleAllTails().Contains(tail)).Select(o => o.EntityType).ToHashSet(); var typeMap = virtualTableManager.GetAllVirtualTables().Where(o => o.GetTableAllTails().Contains(tail)).Select(o => o.EntityType).ToHashSet();
//设置分表 //设置分表
var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o => o.ClrType.IsShardingTable() && typeMap.Contains(o.ClrType)); var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o => o.ClrType.IsShardingTable() && typeMap.Contains(o.ClrType));

View File

@ -162,16 +162,9 @@ namespace ShardingCore.Extensions
var primaryKeyValue = ShardingKeyUtil.GetPrimaryKeyValues(entity); var primaryKeyValue = ShardingKeyUtil.GetPrimaryKeyValues(entity);
if (primaryKeyValue.IsEmpty()) if (primaryKeyValue.IsEmpty())
return null; return null;
var entry = context.ChangeTracker.Entries<TEntity>().FirstOrDefault(e => primaryKeyValue.SequenceEqual(ShardingKeyUtil.GetPrimaryKeyValues(e.Entity))); var entry = context.ChangeTracker.Entries<TEntity>().FirstOrDefault(e =>e.State != EntityState.Detached&&primaryKeyValue.SequenceEqual(ShardingKeyUtil.GetPrimaryKeyValues(e.Entity)));
if (entry != null)
{
if (entry.State != EntityState.Detached)
{
return entry.Entity;
}
}
return null; return entry?.Entity;
} }
} }

View File

@ -0,0 +1,159 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Helpers
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/10/6 8:11:59
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
/// <summary>
/// https://github.com/Coldairarrow/EFCore.Sharding/blob/master/src/EFCore.Sharding/Migrations/MigrationHelper.cs
/// </summary>
public class MigrationHelper
{
private MigrationHelper() { }
public static void Generate<TShardingDContext>(
MigrationOperation operation,
MigrationCommandListBuilder builder,
ISqlGenerationHelper sqlGenerationHelper,
List<MigrationCommand> addCmds
) where TShardingDContext:DbContext,IShardingDbContext
{
addCmds.ForEach(aAddCmd =>
{
var shardingCmds = BuildShardingCmds<TShardingDContext>(operation, aAddCmd.CommandText, sqlGenerationHelper);
//针对builder的原始表进行移除
shardingCmds.ForEach(aShardingCmd =>
{
builder.Append(aShardingCmd)
.EndCommand();
});
});
}
private static List<string> BuildShardingCmds<TShardingDContext>(MigrationOperation operation, string sourceCmd, ISqlGenerationHelper sqlGenerationHelper)
where TShardingDContext : DbContext, IShardingDbContext
{
//所有MigrationOperation定义
//https://github.com/dotnet/efcore/tree/b970bf29a46521f40862a01db9e276e6448d3cb0/src/EFCore.Relational/Migrations/Operations
//ColumnOperation仅替换Table
//其余其余都是将Name和Table使用分表名替换
var virtualTableManager = ShardingContainer.GetService<IVirtualTableManager<TShardingDContext>>();
var allVirtualTables = virtualTableManager.GetAllVirtualTables();
var existsShardingTables = allVirtualTables.ToDictionary(o => o.ShardingConfig.VirtualTableName, o => o.GetAllPhysicTables().Select(p=>p.FullName).ToList());
//Dictionary<string, List<string>> _existsShardingTables
// = Cache.ServiceProvider.GetService<ShardingContainer>().ExistsShardingTables;
List<string> resList = new List<string>();
string absTableName = string.Empty;
string name = operation.GetPropertyValue("Name") as string;
string tableName = operation.GetPropertyValue("Table") as string;
string pattern = string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName);
Func<KeyValuePair<string, List<string>>, bool> where = x =>
existsShardingTables.Any(y =>x.Key==y.Key&& Regex.IsMatch(name, BuildPattern(y.Key)));
if (!string.IsNullOrWhiteSpace(tableName))
{
absTableName = tableName;
}
else if (!string.IsNullOrWhiteSpace(name) && existsShardingTables.Any(x => where(x)))
{
absTableName = existsShardingTables.Where(x => where(x)).FirstOrDefault().Key;
}
//分表
if (!string.IsNullOrWhiteSpace(absTableName) && existsShardingTables.ContainsKey(absTableName))
{
var shardings = existsShardingTables[absTableName];
shardings.ForEach(aShardingTable =>
{
string newCmd = sourceCmd;
GetReplaceGroups(operation, absTableName, aShardingTable).ForEach(aReplace =>
{
newCmd = newCmd.Replace(
sqlGenerationHelper.DelimitIdentifier(aReplace.sourceName),
sqlGenerationHelper.DelimitIdentifier(aReplace.targetName));
});
resList.Add(newCmd);
});
}
return resList;
string BuildPattern(string absTableName)
{
return string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName);
}
}
private static List<(string sourceName, string targetName)> GetReplaceGroups(
MigrationOperation operation, string sourceTableName, string targetTableName)
{
List<(string sourceName, string targetName)> resList =
new List<(string sourceName, string targetName)>
{
(sourceTableName, targetTableName)
};
string name = operation.GetPropertyValue("Name") as string;
if (!string.IsNullOrWhiteSpace(name) && !(operation is ColumnOperation))
{
string[] patterns = new string[] { $"^()({sourceTableName})()$", $"^()({sourceTableName})(_.*?)$", $"^(.*?_)({sourceTableName})(_.*?)$", $"^(.*?_)({sourceTableName})()$" };
foreach (var aPattern in patterns)
{
if (Regex.IsMatch(name, aPattern))
{
var newName = new Regex(aPattern).Replace(name, "${1}" + targetTableName + "$3");
resList.Add((name, newName));
break;
}
}
}
Func<PropertyInfo, bool> listPropertyWhere = x =>
x.PropertyType.IsGenericType
&& x.PropertyType.GetGenericTypeDefinition() == typeof(List<>)
&& typeof(MigrationOperation).IsAssignableFrom(x.PropertyType.GetGenericArguments()[0]);
//其它
operation.GetType().GetProperties()
.Where(x => x.Name != "Name"
&& x.Name != "Table"
&& x.PropertyType != typeof(object)
&& (typeof(MigrationOperation).IsAssignableFrom(x.PropertyType) || listPropertyWhere(x))
)
.ToList()
.ForEach(aProperty =>
{
var propertyValue = aProperty.GetValue(operation);
if (propertyValue is MigrationOperation propertyOperation)
{
resList.AddRange(GetReplaceGroups(propertyOperation, sourceTableName, targetTableName));
}
else if (listPropertyWhere(aProperty))
{
foreach (var aValue in (IEnumerable)propertyValue)
{
resList.AddRange(GetReplaceGroups((MigrationOperation)aValue, sourceTableName, targetTableName));
}
}
});
return resList;
}
}
}

View File

@ -34,7 +34,7 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, DbContext>> _dbContextCaches = new ConcurrentDictionary<string, ConcurrentDictionary<string, DbContext>>(); private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, DbContext>> _dbContextCaches = new ConcurrentDictionary<string, ConcurrentDictionary<string, DbContext>>();
public IShardingTransaction CurrentShardingTransaction { get; private set; } public IShardingTransaction CurrentShardingTransaction { get; private set; }
private readonly IVirtualDataSource<TShardingDbContext> _virtualDataSource; private readonly IVirtualDataSource<TShardingDbContext> _virtualDataSource;
private readonly IVirtualTableManager _virtualTableManager; private readonly IVirtualTableManager<TShardingDbContext> _virtualTableManager;
private readonly IShardingDbContextFactory<TShardingDbContext> _shardingDbContextFactory; private readonly IShardingDbContextFactory<TShardingDbContext> _shardingDbContextFactory;
private readonly IShardingDbContextOptionsBuilderConfig _shardingDbContextOptionsBuilderConfig; private readonly IShardingDbContextOptionsBuilderConfig _shardingDbContextOptionsBuilderConfig;
private readonly IRouteTailFactory _routeTailFactory; private readonly IRouteTailFactory _routeTailFactory;

View File

@ -14,10 +14,10 @@ namespace ShardingCore
{ {
private readonly IEnumerable<IShardingConfigOption> _shardingConfigOptions; private readonly IEnumerable<IShardingConfigOption> _shardingConfigOptions;
public ShardingBootstrapper(IServiceProvider serviceProvider, IEnumerable<IShardingConfigOption> shardingConfigOptions) public ShardingBootstrapper(IServiceProvider serviceProvider)
{ {
ShardingContainer.SetServices(serviceProvider); ShardingContainer.SetServices(serviceProvider);
_shardingConfigOptions = shardingConfigOptions; _shardingConfigOptions = ShardingContainer.GetServices<IShardingConfigOption>();
} }
public void Start() public void Start()

View File

@ -26,11 +26,11 @@ namespace ShardingCore.VirtualRoutes.Days
/// <returns></returns> /// <returns></returns>
public override List<string> GetAllTails() public override List<string> GetAllTails()
{ {
var beginTime = GetBeginTime(); var beginTime = GetBeginTime().Date;
var tails=new List<string>(); var tails=new List<string>();
//提前创建表 //提前创建表
var nowTimeStamp = DateTime.Now.AddDays(1).Date; var nowTimeStamp = DateTime.Now.Date;
if (beginTime > nowTimeStamp) if (beginTime > nowTimeStamp)
throw new ArgumentException("begin time error"); throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime; var currentTimeStamp = beginTime;

View File

@ -20,11 +20,11 @@ namespace ShardingCore.VirtualRoutes.Days
public abstract DateTime GetBeginTime(); public abstract DateTime GetBeginTime();
public override List<string> GetAllTails() public override List<string> GetAllTails()
{ {
var beginTime = GetBeginTime(); var beginTime = GetBeginTime().Date;
var tails=new List<string>(); var tails=new List<string>();
//提前创建表 //提前创建表
var nowTimeStamp = DateTime.Now.AddDays(1).Date; var nowTimeStamp = DateTime.Now.Date;
if (beginTime > nowTimeStamp) if (beginTime > nowTimeStamp)
throw new ArgumentException("begin time error"); throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime; var currentTimeStamp = beginTime;

View File

@ -23,7 +23,7 @@ namespace ShardingCore.VirtualRoutes.Months
var tails=new List<string>(); var tails=new List<string>();
//提前创建表 //提前创建表
var nowTimeStamp =ShardingCoreHelper.GetNextMonthFirstDay(DateTime.Now); var nowTimeStamp =ShardingCoreHelper.GetCurrentMonthFirstDay(DateTime.Now);
if (beginTime > nowTimeStamp) if (beginTime > nowTimeStamp)
throw new ArgumentException("begin time error"); throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime; var currentTimeStamp = beginTime;

View File

@ -23,7 +23,7 @@ namespace ShardingCore.VirtualRoutes.Months
var tails=new List<string>(); var tails=new List<string>();
//提前创建表 //提前创建表
var nowTimeStamp =ShardingCoreHelper.GetNextMonthFirstDay(DateTime.Now); var nowTimeStamp =ShardingCoreHelper.GetCurrentMonthFirstDay(DateTime.Now);
if (beginTime > nowTimeStamp) if (beginTime > nowTimeStamp)
throw new ArgumentException("begin time error"); throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime; var currentTimeStamp = beginTime;

View File

@ -19,11 +19,11 @@ namespace ShardingCore.VirtualRoutes.Weeks
public abstract DateTime GetBeginTime(); public abstract DateTime GetBeginTime();
public override List<string> GetAllTails() public override List<string> GetAllTails()
{ {
var beginTime = GetBeginTime(); var beginTime = GetBeginTime().Date;
var tails=new List<string>(); var tails=new List<string>();
//提前创建表 //提前创建表
var nowTimeStamp = DateTime.Now.AddDays(7).Date; var nowTimeStamp = DateTime.Now.Date;
if (beginTime > nowTimeStamp) if (beginTime > nowTimeStamp)
throw new ArgumentException("begin time error"); throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime; var currentTimeStamp = beginTime;

View File

@ -19,11 +19,11 @@ namespace ShardingCore.VirtualRoutes.Weeks
public abstract DateTime GetBeginTime(); public abstract DateTime GetBeginTime();
public override List<string> GetAllTails() public override List<string> GetAllTails()
{ {
var beginTime = GetBeginTime(); var beginTime = GetBeginTime().Date;
var tails=new List<string>(); var tails=new List<string>();
//提前创建表 //提前创建表
var nowTimeStamp = DateTime.Now.AddDays(7).Date; var nowTimeStamp = DateTime.Now.Date;
if (beginTime > nowTimeStamp) if (beginTime > nowTimeStamp)
throw new ArgumentException("begin time error"); throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime; var currentTimeStamp = beginTime;

View File

@ -18,11 +18,11 @@ namespace ShardingCore.VirtualRoutes.Years
public abstract DateTime GetBeginTime(); public abstract DateTime GetBeginTime();
public override List<string> GetAllTails() public override List<string> GetAllTails()
{ {
var beginTime = GetBeginTime(); var beginTime = GetBeginTime().Date;
var tails=new List<string>(); var tails=new List<string>();
//提前创建表 //提前创建表
var nowTimeStamp = DateTime.Now.AddYears(1).Date; var nowTimeStamp = DateTime.Now.Date;
if (beginTime > nowTimeStamp) if (beginTime > nowTimeStamp)
throw new ArgumentException("begin time error"); throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime; var currentTimeStamp = beginTime;

View File

@ -19,11 +19,11 @@ namespace ShardingCore.VirtualRoutes.Years
public abstract DateTime GetBeginTime(); public abstract DateTime GetBeginTime();
public override List<string> GetAllTails() public override List<string> GetAllTails()
{ {
var beginTime = GetBeginTime(); var beginTime = GetBeginTime().Date;
var tails=new List<string>(); var tails=new List<string>();
//提前创建表 //提前创建表
var nowTimeStamp = DateTime.Now.AddYears(1).Date; var nowTimeStamp = DateTime.Now.Date;
if (beginTime > nowTimeStamp) if (beginTime > nowTimeStamp)
throw new ArgumentException("begin time error"); throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime; var currentTimeStamp = beginTime;