优化多模型缓存bug和优化[#86] sqlserver备注生成bug

This commit is contained in:
xuejiaming 2021-12-22 17:04:38 +08:00
parent 8c9d3d7f41
commit 9e45d71964
17 changed files with 766 additions and 187 deletions

View File

@ -1,9 +1,9 @@
:start
::定义版本
set EFCORE2=2.3.1.92
set EFCORE3=3.3.1.92
set EFCORE5=5.3.1.92
set EFCORE6=6.3.1.92
set EFCORE2=2.3.1.93
set EFCORE3=3.3.1.93
set EFCORE5=5.3.1.93
set EFCORE6=6.3.1.93
::删除所有bin与obj下的文件
@echo off

View File

@ -21,7 +21,7 @@ namespace Sample.Migrations.EFCores
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128).HasComment("用户姓名");
builder.ToTable(nameof(ShardingWithDateTime));
}
}

View File

@ -27,9 +27,8 @@ namespace Sample.Migrations.EFCores
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128);
builder.Property(o => o.Name).HasMaxLength(128);
builder.Property(o => o.TextStr).IsRequired().HasMaxLength(128).HasDefaultValue("");
builder.Property(o => o.Name).HasMaxLength(128).HasComment("用户姓名");
builder.Property(o => o.TextStr).IsRequired().HasMaxLength(128).HasDefaultValue("").HasComment("值123");
builder.Property(o => o.TextStr1).IsRequired().HasMaxLength(128).HasDefaultValue("123");
builder.Property(o => o.TextStr2).IsRequired().HasMaxLength(128).HasDefaultValue("123");
builder.ToTable(nameof(ShardingWithMod));

View File

@ -7,19 +7,22 @@ using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sample.Migrations.EFCores;
#nullable disable
namespace Sample.Migrations.Migrations
{
[DbContext(typeof(DefaultShardingTableDbContext))]
[Migration("20211102072713_Init")]
partial class Init
[Migration("20211222075250_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.11")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
modelBuilder.Entity("Sample.Migrations.EFCores.NoShardingTable", b =>
{
@ -37,7 +40,7 @@ namespace Sample.Migrations.Migrations
b.HasKey("Id");
b.ToTable("NoShardingTable");
b.ToTable("NoShardingTable", (string)null);
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b =>
@ -55,11 +58,12 @@ namespace Sample.Migrations.Migrations
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
.HasColumnType("nvarchar(128)")
.HasComment("用户姓名");
b.HasKey("Id");
b.ToTable("ShardingWithDateTime");
b.ToTable("ShardingWithDateTime", (string)null);
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b =>
@ -74,14 +78,16 @@ namespace Sample.Migrations.Migrations
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
.HasColumnType("nvarchar(128)")
.HasComment("用户姓名");
b.Property<string>("TextStr")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("");
.HasDefaultValue("")
.HasComment("值123");
b.Property<string>("TextStr1")
.IsRequired()
@ -99,7 +105,7 @@ namespace Sample.Migrations.Migrations
b.HasKey("Id");
b.ToTable("ShardingWithMod");
b.ToTable("ShardingWithMod", (string)null);
});
#pragma warning restore 612, 618
}

View File

@ -1,9 +1,11 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Sample.Migrations.Migrations
{
public partial class Init : Migration
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
@ -25,7 +27,7 @@ namespace Sample.Migrations.Migrations
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),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true, comment: "用户姓名"),
Age = table.Column<int>(type: "int", nullable: false),
CreateTime = table.Column<DateTime>(type: "datetime2", nullable: false)
},
@ -39,9 +41,9 @@ namespace Sample.Migrations.Migrations
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),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true, comment: "用户姓名"),
Age = table.Column<int>(type: "int", nullable: false),
TextStr = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false, defaultValue: ""),
TextStr = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false, defaultValue: "", comment: "值123"),
TextStr1 = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false, defaultValue: "123"),
TextStr2 = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false, defaultValue: "123")
},

View File

@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sample.Migrations.EFCores;
#nullable disable
namespace Sample.Migrations.Migrations
{
[DbContext(typeof(DefaultShardingTableDbContext))]
@ -15,9 +17,10 @@ namespace Sample.Migrations.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.11")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
modelBuilder.Entity("Sample.Migrations.EFCores.NoShardingTable", b =>
{
@ -35,7 +38,7 @@ namespace Sample.Migrations.Migrations
b.HasKey("Id");
b.ToTable("NoShardingTable");
b.ToTable("NoShardingTable", (string)null);
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b =>
@ -53,11 +56,12 @@ namespace Sample.Migrations.Migrations
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
.HasColumnType("nvarchar(128)")
.HasComment("用户姓名");
b.HasKey("Id");
b.ToTable("ShardingWithDateTime");
b.ToTable("ShardingWithDateTime", (string)null);
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b =>
@ -72,14 +76,16 @@ namespace Sample.Migrations.Migrations
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
.HasColumnType("nvarchar(128)")
.HasComment("用户姓名");
b.Property<string>("TextStr")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("");
.HasDefaultValue("")
.HasComment("值123");
b.Property<string>("TextStr1")
.IsRequired()
@ -97,7 +103,7 @@ namespace Sample.Migrations.Migrations
b.HasKey("Id");
b.ToTable("ShardingWithMod");
b.ToTable("ShardingWithMod", (string)null);
});
#pragma warning restore 612, 618
}

View File

@ -35,13 +35,21 @@ namespace Sample.SqlServer.Controllers
[HttpGet]
public async Task<IActionResult> Get2x()
{
await _defaultTableDbContext.AddAsync(new SysUserMod()
Console.WriteLine("------------------Get2x------------------------");
using (var dbContext =
DbContextHelper.CreateDbContextByString(
"Data Source=localhost;Initial Catalog=ShardingCoreDBXA;Integrated Security=True;"))
{
Id = Guid.NewGuid().ToString("n"),
Age = 9,
AgeGroup = 10, Name = "SysUserModTest"
});
await _defaultTableDbContext.SaveChangesAsync();
await dbContext.AddAsync(new SysUserMod()
{
Id = Guid.NewGuid().ToString("n"),
Age = 9,
AgeGroup = 10,
Name = "SysUserModTest"
});
await dbContext.SaveChangesAsync();
}
Console.WriteLine("------------------Get2x------------------------");
return Ok();
}
[HttpGet]

View File

@ -0,0 +1,16 @@
using Microsoft.EntityFrameworkCore;
using Sample.SqlServer.DbContexts;
using ShardingCore;
namespace Sample.SqlServer
{
public class DbContextHelper
{
public static DbContext CreateDbContextByString(string connectionString)
{
var dbContextOptionsBuilder = new DbContextOptionsBuilder<DefaultShardingDbContext>();
dbContextOptionsBuilder.UseSqlServer(connectionString).UseSharding<DefaultShardingDbContext>();
return new DefaultShardingDbContext(dbContextOptionsBuilder.Options);
}
}
}

View File

@ -0,0 +1,111 @@
#if EFCORE2
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Exceptions;
using ShardingCore.Sharding.Abstractions;
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace ShardingCore.EFCores
{
public class ShardingModelSource: ModelSource, IShardingModelSource
{
private readonly object _syncObject = new object();
private readonly ConcurrentDictionary<object, Lazy<IModel>> _models = new ConcurrentDictionary<object, Lazy<IModel>>();
/// <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 ShardingModelSource( ModelSourceDependencies dependencies):base(dependencies)
{
Check.NotNull(dependencies, nameof(dependencies));
Dependencies = dependencies;
}
/// <summary>
/// Dependencies used to create a <see cref="ModelSource" />
/// </summary>
protected override ModelSourceDependencies Dependencies { get; }
/// <summary>
/// Returns the model from the cache, or creates a model if it is not present in the cache.
/// </summary>
/// <param name="context"> The context the model is being produced for. </param>
/// <param name="conventionSetBuilder"> The convention set to use when creating the model. </param>
/// <param name="validator"> The validator to verify the model can be successfully used with the context. </param>
/// <returns> The model to be used. </returns>
public override IModel GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
{
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
{
var multiModel = CreateModel(context, conventionSetBuilder, validator);
return multiModel;
}
}
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context);
if (!_models.TryGetValue(cacheKey, out var model))
{
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
}
try
{
if (!_models.TryGetValue(cacheKey, out model))
{
model = new Lazy<IModel>(
() => CreateModel(context, conventionSetBuilder, validator),
LazyThreadSafetyMode.ExecutionAndPublication);
_models.TryAdd(cacheKey, model);
}
}
finally
{
Monitor.Exit(_syncObject);
}
}
return model.Value;
}
public IModelCacheKeyFactory GetModelCacheKeyFactory()
{
return Dependencies.ModelCacheKeyFactory;
}
public object GetSyncObject()
{
return _syncObject;
}
public void Remove(object key)
{
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
}
try
{
_models.TryRemove(key, out var x);
}
finally
{
Monitor.Exit(_syncObject);
}
}
}
}
#endif

View File

@ -0,0 +1,124 @@
#if EFCORE3
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
using Microsoft.Extensions.Caching.Memory;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Exceptions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.EFCores
{
public class ShardingModelSource: ModelSource, IShardingModelSource
{
private readonly object _syncObject = new object();
/// <summary>
/// Creates a new <see cref="ModelSource" /> instance.
/// </summary>
/// <param name="dependencies"> The dependencies to use. </param>
public ShardingModelSource( ModelSourceDependencies dependencies):base(dependencies)
{
Check.NotNull(dependencies, nameof(dependencies));
Dependencies = dependencies;
}
/// <summary>
/// Dependencies used to create a <see cref="ModelSource" />
/// </summary>
protected override ModelSourceDependencies Dependencies { get; }
/// <summary>
/// Returns the model from the cache, or creates a model if it is not present in the cache.
/// </summary>
/// <param name="context"> The context the model is being produced for. </param>
/// <param name="conventionSetBuilder"> The convention set to use when creating the model. </param>
/// <returns> The model to be used. </returns>
public override IModel GetModel(
DbContext context,
IConventionSetBuilder conventionSetBuilder)
{
var priority = CacheItemPriority.High;
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail)
{
if (singleQueryRouteTail.IsShardingTableQuery())
{
priority = CacheItemPriority.Normal;
}
}
else if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
{
var multiModel = CreateModel(context, conventionSetBuilder);
return multiModel;
}
}
var cache = Dependencies.MemoryCache;
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context);
if (!cache.TryGetValue(cacheKey, out IModel model))
{
// Make sure OnModelCreating really only gets called once, since it may not be thread safe.
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
}
try
{
if (!cache.TryGetValue(cacheKey, out model))
{
model = CreateModel(context, conventionSetBuilder);
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = 200, Priority = priority });
}
}
finally
{
Monitor.Exit(_syncObject);
}
}
return model;
}
public IModelCacheKeyFactory GetModelCacheKeyFactory()
{
return Dependencies.ModelCacheKeyFactory;
}
public object GetSyncObject()
{
return _syncObject;
}
public void Remove(object key)
{
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
}
try
{
var cache = Dependencies.MemoryCache;
cache.Remove(key);
}
finally
{
Monitor.Exit(_syncObject);
}
}
}
}
#endif

View File

@ -0,0 +1,140 @@
#if EFCORE5
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
using Microsoft.Extensions.Caching.Memory;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Exceptions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.EFCores
{
public class ShardingModelSource : ModelSource, IShardingModelSource
{
private readonly object _syncObject = new object();
/// <summary>
/// Creates a new <see cref="ModelSource" /> instance.
/// </summary>
/// <param name="dependencies"> The dependencies to use. </param>
public ShardingModelSource([NotNull] ModelSourceDependencies dependencies) : base(dependencies)
{
Dependencies = dependencies;
}
/// <summary>
/// Dependencies used to create a <see cref="ModelSource" />
/// </summary>
protected override ModelSourceDependencies Dependencies { get; }
/// <summary>
/// Returns the model from the cache, or creates a model if it is not present in the cache.
/// </summary>
/// <param name="context"> The context the model is being produced for. </param>
/// <param name="conventionSetBuilder"> The convention set to use when creating the model. </param>
/// <returns> The model to be used. </returns>
[Obsolete("Use the overload with ModelDependencies")]
public override IModel GetModel(
DbContext context,
IConventionSetBuilder conventionSetBuilder)
{
throw new ShardingCoreNotSupportException("Use the overload with ModelDependencies");
}
/// <summary>
/// Returns the model from the cache, or creates a model if it is not present in the cache.
/// </summary>
/// <param name="context"> The context the model is being produced for. </param>
/// <param name="conventionSetBuilder"> The convention set to use when creating the model. </param>
/// <param name="modelDependencies"> The dependencies object for the model. </param>
/// <returns> The model to be used. </returns>
public override IModel GetModel(
DbContext context,
IConventionSetBuilder conventionSetBuilder,
ModelDependencies modelDependencies)
{
var priority = CacheItemPriority.High;
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail)
{
if (singleQueryRouteTail.IsShardingTableQuery())
{
priority = CacheItemPriority.Normal;
}
}
else if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
{
var multiModel = CreateModel(context, conventionSetBuilder, modelDependencies);
return multiModel;
}
}
var cache = Dependencies.MemoryCache;
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context);
if (!cache.TryGetValue(cacheKey, out IModel model))
{
// Make sure OnModelCreating really only gets called once, since it may not be thread safe.
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
}
try
{
if (!cache.TryGetValue(cacheKey, out model))
{
model = CreateModel(context, conventionSetBuilder, modelDependencies);
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = 200, Priority = priority });
}
}
finally
{
Monitor.Exit(_syncObject);
}
}
return model;
}
public IModelCacheKeyFactory GetModelCacheKeyFactory()
{
return Dependencies.ModelCacheKeyFactory;
}
public object GetSyncObject()
{
return _syncObject;
}
public void Remove(object key)
{
// Make sure OnModelCreating really only gets called once, since it may not be thread safe.
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
}
try
{
var cache = Dependencies.MemoryCache;
cache.Remove(key);
}
finally
{
Monitor.Exit(_syncObject);
}
}
}
}
#endif

View File

@ -0,0 +1,160 @@

#if EFCORE6
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.Extensions.Caching.Memory;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Exceptions;
using ShardingCore.Sharding.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ShardingCore.EFCores
{
public class ShardingModelSource : ModelSource, IShardingModelSource
{
private readonly object _syncObject = new();
public ShardingModelSource(ModelSourceDependencies dependencies) : base(dependencies)
{
Check.NotNull(dependencies, nameof(dependencies));
Dependencies = dependencies;
}
/// <summary>
/// Dependencies for this service.
/// </summary>
protected override ModelSourceDependencies Dependencies { get; }
/// <summary>
/// Returns the model from the cache, or creates a model if it is not present in the cache.
/// </summary>
/// <param name="context">The context the model is being produced for.</param>
/// <param name="conventionSetBuilder">The convention set to use when creating the model.</param>
/// <returns>The model to be used.</returns>
[Obsolete("Use the overload with ModelCreationDependencies")]
public override IModel GetModel(
DbContext context,
IConventionSetBuilder conventionSetBuilder)
{
throw new ShardingCoreNotSupportException("Use the overload with ModelCreationDependencies");
}
/// <summary>
/// Returns the model from the cache, or creates a model if it is not present in the cache.
/// </summary>
/// <param name="context">The context the model is being produced for.</param>
/// <param name="conventionSetBuilder">The convention set to use when creating the model.</param>
/// <param name="modelDependencies">The dependencies object for the model.</param>
/// <returns>The model to be used.</returns>
[Obsolete("Use the overload with ModelCreationDependencies")]
public override IModel GetModel(
DbContext context,
IConventionSetBuilder conventionSetBuilder,
ModelDependencies modelDependencies)
{
throw new ShardingCoreNotSupportException("Use the overload with ModelCreationDependencies");
}
/// <summary>
/// Gets the model to be used.
/// </summary>
/// <param name="context">The context the model is being produced for.</param>
/// <param name="modelCreationDependencies">The dependencies object used during the creation of the model.</param>
/// <param name="designTime">Whether the model should contain design-time configuration.</param>
/// <returns>The model to be used.</returns>
public override IModel GetModel(
DbContext context,
ModelCreationDependencies modelCreationDependencies,
bool designTime)
{
var priority = CacheItemPriority.High;
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail)
{
if (singleQueryRouteTail.IsShardingTableQuery())
{
priority = CacheItemPriority.Normal;
}
}
else if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
{
var multiModel = this.CreateModel(context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
multiModel = modelCreationDependencies.ModelRuntimeInitializer.Initialize(multiModel, designTime, modelCreationDependencies.ValidationLogger);
return multiModel;
}
}
var cache = Dependencies.MemoryCache;
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context, designTime);
if (!cache.TryGetValue(cacheKey, out IModel model))
{
// Make sure OnModelCreating really only gets called once, since it may not be thread safe.
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
}
try
{
if (!cache.TryGetValue(cacheKey, out model))
{
model = CreateModel(
context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
model = modelCreationDependencies.ModelRuntimeInitializer.Initialize(
model, designTime, modelCreationDependencies.ValidationLogger);
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = 200, Priority = priority });
}
}
finally
{
Monitor.Exit(_syncObject);
}
}
return model;
}
public IModelCacheKeyFactory GetModelCacheKeyFactory()
{
return Dependencies.ModelCacheKeyFactory;
}
public object GetSyncObject()
{
return _syncObject;
}
public void Remove(object key)
{
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
}
try
{
var cache = Dependencies.MemoryCache;
cache.Remove(key);
}
finally
{
Monitor.Exit(_syncObject);
}
}
}
}
#endif

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace ShardingCore.EFCores
{
public interface IShardingModelSource
{
IModelCacheKeyFactory GetModelCacheKeyFactory();
object GetSyncObject();
void Remove(object key);
}
}

View File

@ -1,87 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Sharding.Abstractions;
#if !EFCORE2
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
#endif
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
//using Microsoft.EntityFrameworkCore;
//using Microsoft.EntityFrameworkCore.Infrastructure;
//using Microsoft.EntityFrameworkCore.Metadata;
//using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;
//using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
//using ShardingCore.Sharding.Abstractions;
//#if !EFCORE2
//using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
//#endif
namespace ShardingCore.EFCores
{
public class ShardingModelSource:ModelSource
{
public ShardingModelSource(ModelSourceDependencies dependencies) : base(dependencies)
{
}
#if !EFCORE2&&!EFCORE3&&!EFCORE5&&!EFCORE6
1
#endif
//namespace ShardingCore.EFCores
//{
// public class ShardingModelSource:ModelSource
// {
// public ShardingModelSource(ModelSourceDependencies dependencies) : base(dependencies)
// {
// }
//#if !EFCORE2&&!EFCORE3&&!EFCORE5&&!EFCORE6
// 1
//#endif
#if EFCORE6
//#if EFCORE6
public override IModel GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, bool designTime)
{
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
{
var model = this.CreateModel(context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
model = modelCreationDependencies.ModelRuntimeInitializer.Initialize(model, designTime, modelCreationDependencies.ValidationLogger);
return model;
}
}
return base.GetModel(context, modelCreationDependencies, designTime);
}
#endif
#if EFCORE5
public override IModel GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
{
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
{
var model = this.CreateModel(context, conventionSetBuilder, modelDependencies);
return model;
}
}
return base.GetModel(context, conventionSetBuilder, modelDependencies);
}
#endif
#if EFCORE3
public override IModel GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
{
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
{
var model = this.CreateModel(context, conventionSetBuilder);
return model;
}
}
return base.GetModel(context, conventionSetBuilder);
}
#endif
// public override IModel GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, bool designTime)
// {
// if (context is IShardingTableDbContext shardingTableDbContext)
// {
// if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
// {
// var model = this.CreateModel(context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
// model = modelCreationDependencies.ModelRuntimeInitializer.Initialize(model, designTime, modelCreationDependencies.ValidationLogger);
// return model;
// }
// }
// return base.GetModel(context, modelCreationDependencies, designTime);
// }
//#endif
//#if EFCORE5
// public override IModel GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
// {
// if (context is IShardingTableDbContext shardingTableDbContext)
// {
// if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
// {
// var model = this.CreateModel(context, conventionSetBuilder, modelDependencies);
// return model;
// }
// }
// return base.GetModel(context, conventionSetBuilder, modelDependencies);
// }
//#endif
//#if EFCORE3
// public override IModel GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
// {
// if (context is IShardingTableDbContext shardingTableDbContext)
// {
// if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
// {
// var model = this.CreateModel(context, conventionSetBuilder);
// return model;
// }
// }
// return base.GetModel(context, conventionSetBuilder);
// }
//#endif
#if EFCORE2
public override IModel GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
{
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
{
var model = this.CreateModel(context, conventionSetBuilder, validator);
return model;
}
}
return base.GetModel(context, conventionSetBuilder, validator);
}
#endif
}
}
//#if EFCORE2
// public override IModel GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
// {
// if (context is IShardingTableDbContext shardingTableDbContext)
// {
// if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
// {
// var model = this.CreateModel(context, conventionSetBuilder, validator);
// return model;
// }
// }
// return base.GetModel(context, conventionSetBuilder, validator);
// }
//#endif
// }
//}

View File

@ -0,0 +1,21 @@
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 ShardingCoreNotSupportException : ShardingCoreException
{
public ShardingCoreNotSupportException(string message) : base(message)
{
}
public ShardingCoreNotSupportException(string message, Exception innerException) : base(message, innerException)
{
}
}
}

View File

@ -15,6 +15,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.EFCores;
using ShardingCore.Utils;
namespace ShardingCore.Extensions
@ -199,50 +200,33 @@ namespace ShardingCore.Extensions
public static void RemoveModelCache(this DbContext dbContext)
{
#if EFCORE6
var dependencies = dbContext.GetService<ModelCreationDependencies>();
var dependenciesModelSource = dependencies.ModelSource as ModelSource;
var modelSourceDependencies =
dependenciesModelSource.GetPropertyValue("Dependencies") as ModelSourceDependencies;
IMemoryCache memoryCache = modelSourceDependencies.MemoryCache;
object key1 = modelSourceDependencies.ModelCacheKeyFactory.Create(dbContext,true);
memoryCache.Remove(key1);
object key2 = modelSourceDependencies.ModelCacheKeyFactory.Create(dbContext,false);
memoryCache.Remove(key2);
var shardingModelSource = dbContext.GetService<IModelSource>() as IShardingModelSource;
var modelCacheKeyFactory = shardingModelSource.GetModelCacheKeyFactory();
object key1 = modelCacheKeyFactory.Create(dbContext,true);
shardingModelSource.Remove(key1);
object key2 = modelCacheKeyFactory.Create(dbContext,false);
shardingModelSource.Remove(key2);
#endif
#if EFCORE5
var dependencies = dbContext.GetService<IModelCreationDependencies>();
var dependenciesModelSource = dependencies.ModelSource as ModelSource;
var modelSourceDependencies =
dependenciesModelSource.GetPropertyValue("Dependencies") as ModelSourceDependencies;
IMemoryCache memoryCache = modelSourceDependencies.MemoryCache;
object key1 = modelSourceDependencies.ModelCacheKeyFactory.Create(dbContext);
memoryCache.Remove(key1);
var shardingModelSource = dbContext.GetService<IModelSource>() as IShardingModelSource;
var modelCacheKeyFactory = shardingModelSource.GetModelCacheKeyFactory();
object key1 = modelCacheKeyFactory.Create(dbContext);
shardingModelSource.Remove(key1);
#endif
#if EFCORE3
var modelSource = dbContext.GetService<IModelSource>();
var modelSourceImpl = modelSource as ModelSource;
var modelSourceDependencies =
modelSourceImpl.GetPropertyValue("Dependencies") as ModelSourceDependencies;
IMemoryCache memoryCache = modelSourceDependencies.MemoryCache;
object key1 = modelSourceDependencies.ModelCacheKeyFactory.Create(dbContext);
memoryCache.Remove(key1);
var shardingModelSource = dbContext.GetService<IModelSource>() as IShardingModelSource;
var modelCacheKeyFactory = shardingModelSource.GetModelCacheKeyFactory();
object key1 = modelCacheKeyFactory.Create(dbContext);
shardingModelSource.Remove(key1);
#endif
#if EFCORE2
var modelSource = dbContext.GetService<IModelSource>();
var modelSourceImpl = modelSource as ModelSource;
var modelSourceDependencies =
modelSourceImpl.GetPropertyValue("Dependencies") as ModelSourceDependencies;
var models =
typeof(ModelSource).GetTypeFieldValue(modelSourceImpl, "_models") as ConcurrentDictionary<object, Lazy<IModel>>;
object key1 = modelSourceDependencies.ModelCacheKeyFactory.Create(dbContext);
models.TryRemove(key1, out var del);
var shardingModelSource = dbContext.GetService<IModelSource>() as IShardingModelSource;
var modelCacheKeyFactory = shardingModelSource.GetModelCacheKeyFactory();
object key1 = modelCacheKeyFactory.Create(dbContext);
shardingModelSource.Remove(key1);
#endif
}
@ -253,32 +237,10 @@ namespace ShardingCore.Extensions
/// <returns></returns>
public static object GetModelCacheSyncObject(this DbContext dbContext)
{
#if EFCORE6
var dependencies = dbContext.GetService<ModelCreationDependencies>();
var syncObject = typeof(ModelSource).GetTypeFieldValue(dependencies.ModelSource, "_syncObject");
return syncObject;
#endif
#if EFCORE5
var dependencies = dbContext.GetService<IModelCreationDependencies>();
var syncObject = typeof(ModelSource).GetTypeFieldValue(dependencies.ModelSource, "_syncObject");
return syncObject;
#endif
#if EFCORE3
var modelSource = dbContext.GetService<IModelSource>();
var syncObject = typeof(ModelSource).GetTypeFieldValue(modelSource, "_syncObject");
return syncObject;
#endif
#if EFCORE2
return sLock;
#endif
IShardingModelSource shardingModelSource = dbContext.GetService<IModelSource>() as IShardingModelSource;
return shardingModelSource.GetSyncObject();
}
private static object sLock = new object();
public static IEnumerable<object> GetPrimaryKeyValues<TEntity>(TEntity entity,IKey primaryKey) where TEntity : class
{

View File

@ -97,6 +97,10 @@ namespace ShardingCore.Helpers
sqlGenerationHelper.DelimitIdentifier(aReplace.sourceName),
sqlGenerationHelper.DelimitIdentifier(aReplace.targetName));
});
if (newCmd.Contains("EXEC sp_addextendedproperty 'MS_Description', @description, 'SCHEMA', @defaultSchema, 'TABLE'"))
{
newCmd=newCmd.Replace($"EXEC sp_addextendedproperty 'MS_Description', @description, 'SCHEMA', @defaultSchema, 'TABLE', N'{absTableName}'", $"EXEC sp_addextendedproperty 'MS_Description', @description, 'SCHEMA', @defaultSchema, 'TABLE', N'{aShardingTable}'");
}
resList.Add(newCmd);
});
}
@ -118,16 +122,19 @@ namespace ShardingCore.Helpers
};
string name = operation.GetPropertyValue("Name") as string;
if (!string.IsNullOrWhiteSpace(name) && !(operation is ColumnOperation))
if (!string.IsNullOrWhiteSpace(name))
{
string[] patterns = new string[] { $"^()({sourceTableName})()$", $"^()({sourceTableName})(_.*?)$", $"^(.*?_)({sourceTableName})(_.*?)$", $"^(.*?_)({sourceTableName})()$" };
foreach (var aPattern in patterns)
if (!(operation is ColumnOperation columnOperation))
{
if (Regex.IsMatch(name, aPattern))
string[] patterns = new string[] { $"^()({sourceTableName})()$", $"^()({sourceTableName})(_.*?)$", $"^(.*?_)({sourceTableName})(_.*?)$", $"^(.*?_)({sourceTableName})()$" };
foreach (var aPattern in patterns)
{
var newName = new Regex(aPattern).Replace(name, "${1}" + targetTableName + "$3");
resList.Add((name, newName));
break;
if (Regex.IsMatch(name, aPattern))
{
var newName = new Regex(aPattern).Replace(name, "${1}" + targetTableName + "$3");
resList.Add((name, newName));
break;
}
}
}
}