[#47]支持配置创建分表分库无需通过接口

This commit is contained in:
xuejiaming 2021-10-29 10:44:48 +08:00
parent 31b62f4c19
commit c1e1042e1a
86 changed files with 3882 additions and 413 deletions

View File

@ -6,7 +6,7 @@
---
<div align="center">
<p> <a href="https://gitee.com/dotnetchina/sharding-core">Gitee Star</a> 助力dotnet 生态 <a href="https://github.com/xuejmnet/sharding-core">Github Star</a> </p>
<p><a href="https://github.com/xuejmnet/sharding-core">Github Source Code</a> 助力dotnet 生态 <a href="https://gitee.com/dotnetchina/sharding-core">Gitee Source Code</a> </p>
</div>
---

View File

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ShardingCore.Bootstrapers;
using ShardingCore.Extensions.ShardingPageExtensions;
namespace Sample.BulkConsole

View File

@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.DependencyInjection;
using Sample.Migrations.EFCores;
using ShardingCore;
using ShardingCore.Bootstrapers;
namespace Sample.Migrations
{

View File

@ -13,6 +13,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using Sample.Migrations.EFCores;
using ShardingCore;
using ShardingCore.Bootstrapers;
namespace Sample.Migrations
{

View File

@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
using Sample.MySql.DbContexts;
using Sample.MySql.Domain.Entities;
using ShardingCore;
using ShardingCore.Bootstrapers;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;

View File

@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Sample.SqlServer.DbContexts;
using Sample.SqlServer.Domain.Entities;
using ShardingCore;
using ShardingCore.Bootstrapers;
namespace Sample.SqlServer
{

View File

@ -17,7 +17,7 @@ namespace Sample.SqlServer.Domain.Entities
/// <summary>
/// 用户Id用于分表
/// </summary>
[ShardingTableKey(TailPrefix = "_")]
[ShardingTableKey(TableSeparator = "_")]
public string Id { get; set; }
/// <summary>
/// 用户名称

View File

@ -12,6 +12,7 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Sample.SqlServer3x.Domain.Entities;
using ShardingCore;
using ShardingCore.Bootstrapers;
namespace Sample.SqlServer3x
{

View File

@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
using Sample.SqlServerShardingDataSource.DbContexts;
using Sample.SqlServerShardingDataSource.Domain.Entities;
using ShardingCore;
using ShardingCore.Bootstrapers;
namespace Sample.SqlServerShardingDataSource
{

View File

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore;
using ShardingCore.Bootstrapers;
namespace Samples.AutoByDate.SqlServer
{

View File

@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Logging;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.EntityShardingMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.TrackerManagers;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
@ -15,6 +16,10 @@ using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
using ShardingCore.Jobs;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.TableCreator;
using ShardingCore.Utils;
@ -60,7 +65,7 @@ namespace ShardingCore.Bootstrapers
{
var shardingEntityType = _entityType.ClrType;
_trackerManager.AddDbContextModel(shardingEntityType);
var entityMetadata = new EntityMetadata(shardingEntityType, _virtualTableName,_entityType.FindPrimaryKey().Properties.Select(o=>o.PropertyInfo).ToList());
var entityMetadata = new EntityMetadata(shardingEntityType, _virtualTableName,typeof(TShardingDbContext),_entityType.FindPrimaryKey().Properties.Select(o=>o.PropertyInfo).ToList());
_entityMetadataManager.AddEntityMetadata(entityMetadata);
//设置标签
if (_shardingConfigOption.TryGetVirtualDataSourceRoute<TEntity>(out var virtualDataSourceRouteType))
@ -74,8 +79,10 @@ namespace ShardingCore.Bootstrapers
entityMetadataAutoBindInitializer.Initialize(entityMetadata);
}
//配置分库信息
var entityMetadataDataSourceConfiguration = dataSourceRoute.CreateEntityMetadataDataSourceConfiguration();
entityMetadataDataSourceConfiguration?.Configure(creatEntityMetadataDataSourceBuilder);
if(dataSourceRoute is IEntityMetadataDataSourceConfiguration<TEntity> entityMetadataDataSourceConfiguration)
{
entityMetadataDataSourceConfiguration.Configure(creatEntityMetadataDataSourceBuilder);
}
_virtualDataSource.AddVirtualDataSourceRoute(dataSourceRoute);
@ -92,14 +99,32 @@ namespace ShardingCore.Bootstrapers
entityMetadataAutoBindInitializer.Initialize(entityMetadata);
}
//配置分表信息
var createEntityMetadataTableConfiguration = virtualTableRoute.CreateEntityMetadataTableConfiguration();
createEntityMetadataTableConfiguration?.Configure(entityMetadataTableBuilder);
if (virtualTableRoute is IEntityMetadataTableConfiguration<TEntity> createEntityMetadataTableConfiguration)
{
createEntityMetadataTableConfiguration.Configure(entityMetadataTableBuilder);
}
//创建虚拟表
var virtualTable = CreateVirtualTable(virtualTableRoute,entityMetadata);
_virtualTableManager.AddVirtualTable(virtualTable);
//检测校验分表分库对象元数据
entityMetadata.CheckMetadata();
//创建表
CreateDataTable(_dataSourceName, virtualTable);
//添加任务
if (virtualTableRoute is IJob routeJob&& routeJob.StartJob())
{
var jobManager = ShardingContainer.GetService<IJobManager>();
var jobEntries = JobTypeParser.Parse(virtualTableRoute.GetType());
jobEntries.ForEach(o =>
{
o.JobName = $"{routeJob.JobName}:{o.JobName}";
});
foreach (var jobEntry in jobEntries)
{
jobManager.AddJob(jobEntry);
}
}
}
}
private void CreateDataTable(string dataSourceName, IVirtualTable virtualTable)

View File

@ -1,7 +1,4 @@
using System;
using System.Threading.Tasks;
namespace ShardingCore
namespace ShardingCore.Bootstrapers
{
/*
* @Author: xjm

View File

@ -1,10 +1,12 @@
using ShardingCore.Extensions;
using System;
using System.Collections.Generic;
using ShardingCore.Bootstrapers;
using System.Threading.Tasks;
using ShardingCore.Extensions;
using ShardingCore.Jobs;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Sharding.MergeEngines.ParallelControl;
namespace ShardingCore
namespace ShardingCore.Bootstrapers
{
/*
* @Author: xjm
@ -32,6 +34,15 @@ namespace ShardingCore
var instance = (IShardingDbContextBootstrapper)Activator.CreateInstance(typeof(ShardingDbContextBootstrapper<>).GetGenericType0(shardingConfigOption.ShardingDbContextType), shardingConfigOption);
instance.Init();
}
var jobManager = ShardingContainer.GetService<IJobManager>();
if (jobManager != null && jobManager.HasAnyJob())
{
Task.Factory.StartNew(async () =>
{
await ShardingContainer.GetService<JobRunnerService>().StartAsync();
}, TaskCreationOptions.LongRunning);
}
}
}

View File

@ -8,10 +8,11 @@ namespace ShardingCore.Core.EntityMetadatas
{
public class EntityMetadata
{
public EntityMetadata(Type entityType, string virtualTableName, IReadOnlyList<PropertyInfo> primaryKeyProperties)
public EntityMetadata(Type entityType, string virtualTableName,Type shardingDbContextType, IReadOnlyList<PropertyInfo> primaryKeyProperties)
{
EntityType = entityType;
VirtualTableName = virtualTableName;
ShardingDbContextType = shardingDbContextType;
PrimaryKeyProperties = primaryKeyProperties;
IsSingleKey= PrimaryKeyProperties.Count == 1;
}
@ -23,6 +24,9 @@ namespace ShardingCore.Core.EntityMetadatas
/// 分表的原表名 original table name in db exclude tail
/// </summary>
public string VirtualTableName { get; }
public Type ShardingDbContextType { get; }
/// <summary>
/// 主键
/// </summary>

View File

@ -0,0 +1,34 @@
using System;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.EntityMetadatas
{
public interface IEntityMetadataManager
{
/// <summary>
/// 添加元数据
/// </summary>
/// <param name="entityMetadata"></param>
/// <returns></returns>
bool AddEntityMetadata(EntityMetadata entityMetadata);
/// <summary>
/// 是否分表
/// </summary>
/// <param name="entityType"></param>
/// <returns></returns>
bool IsShardingTable(Type entityType);
/// <summary>
/// 是否分库
/// </summary>
/// <param name="entityType"></param>
/// <returns></returns>
bool IsShardingDataSource(Type entityType);
/// <summary>
/// 尝试获取
/// </summary>
/// <param name="entityType"></param>
/// <returns></returns>
EntityMetadata TryGet(Type entityType);
}
}

View File

@ -4,33 +4,6 @@ using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.EntityMetadatas
{
public interface IEntityMetadataManager
{
/// <summary>
/// 添加元数据
/// </summary>
/// <param name="entityMetadata"></param>
/// <returns></returns>
bool AddEntityMetadata(EntityMetadata entityMetadata);
/// <summary>
/// 是否分表
/// </summary>
/// <param name="entityType"></param>
/// <returns></returns>
bool IsShardingTable(Type entityType);
/// <summary>
/// 是否分库
/// </summary>
/// <param name="entityType"></param>
/// <returns></returns>
bool IsShardingDataSource(Type entityType);
/// <summary>
/// 尝试获取
/// </summary>
/// <param name="entityType"></param>
/// <returns></returns>
EntityMetadata TryGet(Type entityType);
}
/// <summary>
/// 分片 对象元数据信息管理
/// </summary>

View File

@ -24,7 +24,7 @@ namespace ShardingCore.Core.QueryRouteManagers.Abstractions
void Assert(List<string> allDataSources, List<string> resultDataSources);
}
public interface IDataSourceRouteAssert<T> : IDataSourceRouteAssert where T : class, IShardingDataSource
public interface IDataSourceRouteAssert<T> : IDataSourceRouteAssert where T : class
{
}

View File

@ -18,7 +18,7 @@ namespace ShardingCore.Core.QueryRouteManagers.Abstractions
void Assert(List<IPhysicTable> allPhysicTables, List<IPhysicTable> resultPhysicTables);
}
public interface ITableRouteAssert<T> : ITableRouteAssert where T : class,IShardingTable
public interface ITableRouteAssert<T> : ITableRouteAssert where T : class
{
}

View File

@ -19,7 +19,7 @@ namespace ShardingCore.Core
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ShardingTableKeyAttribute : Attribute
{
public const string DEFAULT_TAIL_PREFIX = "_";
public const string DEFAULT_TABLE_SEPARATOR = "_";
/// <summary>
/// 是否需要在启动的时候创建表
@ -29,6 +29,6 @@ namespace ShardingCore.Core
/// <summary>
/// 分表尾巴前缀
/// </summary>
public string TailPrefix { get; set; } = DEFAULT_TAIL_PREFIX;
public string TableSeparator { get; set; } = DEFAULT_TABLE_SEPARATOR;
}
}

View File

@ -1,64 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace ShardingCore.Core.VirtualDatabase
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/9/16 9:30:04
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingEntityConfig
{
/// <summary>
/// 分表类型 sharding entity type
/// </summary>
public Type EntityType { get; set; }
/// <summary>
/// 是否多数据源
/// </summary>
public bool IsMultiDataSourceMapping { get; set; }
/// <summary>
/// 是否分表
/// </summary>
public bool IsMultiTableMapping { get; set; }
/// <summary>
/// 分库字段
/// </summary>
public string ShardingDataSourceField { get; set; }
/// <summary>
/// 主键名称
/// </summary>
public string SinglePrimaryKeyFieldName { get; set; }
/// <summary>
/// 启动时是否建表 auto create data source when start app
/// </summary>
public bool? AutoCreateDataSourceTable { get; set; }
/// <summary>
/// 分表字段 sharding table field
/// </summary>
public string ShardingTableField { get; set; }
/// <summary>
/// 分表的原表名 original table name in db exclude tail
/// </summary>
public string VirtualTableName { get; set; }
/// <summary>
/// 启动时是否建表 auto create table when start app
/// </summary>
public bool? AutoCreateTable { get; set; }
/// <summary>
/// 分表尾巴后缀 table sharding tail prefix
/// </summary>
public string TailPrefix { get; set; } = "_";
}
}

View File

@ -68,7 +68,7 @@ namespace ShardingCore.Core.VirtualDatabase.VirtualDataSources
{
if(!_entityMetadataManager.IsShardingDataSource(entityType))
throw new InvalidOperationException(
$"entity type :[{entityType.FullName}] not impl [{nameof(IShardingDataSource)}]");
$"entity type :[{entityType.FullName}] not configure sharding data source");
if (!_dataSourceVirtualRoutes.TryGetValue(entityType, out var dataSourceVirtualRoute))
throw new InvalidOperationException(
@ -111,7 +111,7 @@ namespace ShardingCore.Core.VirtualDatabase.VirtualDataSources
public bool AddVirtualDataSourceRoute(IVirtualDataSourceRoute virtualDataSourceRoute)
{
if (!virtualDataSourceRoute.EntityMetadata.IsShardingDataSource())
throw new InvalidOperationException($"{virtualDataSourceRoute.EntityMetadata.EntityType.FullName} should impl {nameof(IShardingDataSource)}");
throw new InvalidOperationException($"{virtualDataSourceRoute.EntityMetadata.EntityType.FullName} should configure sharding data source");
return _dataSourceVirtualRoutes.TryAdd(virtualDataSourceRoute.EntityMetadata.EntityType, virtualDataSourceRoute);
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using ShardingCore.Bootstrapers;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase;

View File

@ -22,7 +22,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
public abstract class AbstractShardingFilterVirtualDataSourceRoute<T, TKey> : AbstractVirtualDataSourceRoute<T, TKey> where T : class, IShardingDataSource
public abstract class AbstractShardingFilterVirtualDataSourceRoute<T, TKey> : AbstractVirtualDataSourceRoute<T, TKey> where T : class
{
public ShardingRouteContext CurrentShardingRouteContext =>

View File

@ -21,7 +21,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
public abstract class AbstractShardingOperatorVirtualDataSourceRoute<T, TKey> : AbstractShardingFilterVirtualDataSourceRoute<T, TKey> where T : class, IShardingDataSource
public abstract class AbstractShardingOperatorVirtualDataSourceRoute<T, TKey> : AbstractShardingFilterVirtualDataSourceRoute<T, TKey> where T : class
{
protected override List<string> DoRouteWithPredicate(List<string> allDataSourceNames, IQueryable queryable)
{

View File

@ -14,7 +14,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
* @Date: Friday, 18 December 2020 14:33:01
* @Email: 326308290@qq.com
*/
public abstract class AbstractVirtualDataSourceRoute<T, TKey> : IVirtualDataSourceRoute<T>, IEntityMetadataAutoBindInitializer where T : class, IShardingDataSource
public abstract class AbstractVirtualDataSourceRoute<T, TKey> : IVirtualDataSourceRoute<T>, IEntityMetadataAutoBindInitializer where T : class
{
public EntityMetadata EntityMetadata { get; private set; }
private readonly DoOnlyOnce _doOnlyOnce = new DoOnlyOnce();
@ -76,5 +76,9 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
public abstract List<string> GetAllDataSourceNames();
public abstract bool AddDataSourceName(string dataSourceName);
public void Configure(EntityMetadataDataSourceBuilder<T> builder)
{
}
}
}

View File

@ -52,17 +52,12 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
}
public interface IVirtualDataSourceRoute<T> : IVirtualDataSourceRoute where T : class
public interface IVirtualDataSourceRoute<T> : IVirtualDataSourceRoute, IEntityMetadataDataSourceConfiguration<T> where T : class
{
/// <summary>
/// 返回null就是表示不开启分页配置
/// </summary>
/// <returns></returns>
IPaginationConfiguration<T> CreatePaginationConfiguration();
/// <summary>
/// 创建分库配置
/// </summary>
/// <returns></returns>
IEntityMetadataDataSourceConfiguration<T> CreateEntityMetadataDataSourceConfiguration();
}
}

View File

@ -13,12 +13,12 @@ namespace ShardingCore.Core.VirtualRoutes
{
private readonly IQueryable _queryable;
private readonly IShardingDataSource _shardingDataSource;
private readonly object _shardingDataSource;
private readonly object _shardingKeyValue;
private readonly Expression _predicate;
public ShardingDataSourceRouteConfig(IQueryable queryable=null,IShardingDataSource shardingDataSource=null,object shardingKeyValue=null,Expression predicate=null)
public ShardingDataSourceRouteConfig(IQueryable queryable=null,object shardingDataSource=null,object shardingKeyValue=null,Expression predicate=null)
{
_queryable = queryable;
_shardingDataSource = shardingDataSource;
@ -35,7 +35,7 @@ namespace ShardingCore.Core.VirtualRoutes
return _shardingKeyValue;
}
public IShardingDataSource GetShardingDataSource()
public object GetShardingDataSource()
{
return _shardingDataSource;
}

View File

@ -24,7 +24,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
public abstract class AbstractShardingFilterVirtualTableRoute<T, TKey> : AbstractVirtualTableRoute<T, TKey> where T : class, IShardingTable
public abstract class AbstractShardingFilterVirtualTableRoute<T, TKey> : AbstractVirtualTableRoute<T, TKey> where T : class
{
public ShardingRouteContext CurrentShardingRouteContext =>
ShardingContainer.GetService<IShardingRouteManager>().Current;

View File

@ -17,7 +17,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
* @Date: Saturday, 19 December 2020 19:55:24
* @Email: 326308290@qq.com
*/
public abstract class AbstractShardingOperatorVirtualTableRoute<T, TKey> : AbstractShardingFilterVirtualTableRoute<T, TKey> where T : class, IShardingTable
public abstract class AbstractShardingOperatorVirtualTableRoute<T, TKey> : AbstractShardingFilterVirtualTableRoute<T, TKey> where T : class
{
protected override List<IPhysicTable> DoRouteWithPredicate(List<IPhysicTable> allPhysicTables, IQueryable queryable)
{

View File

@ -18,7 +18,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
* @Date: Friday, 18 December 2020 14:33:01
* @Email: 326308290@qq.com
*/
public abstract class AbstractVirtualTableRoute<T, TKey> : IVirtualTableRoute<T>, IEntityMetadataAutoBindInitializer where T : class, IShardingTable
public abstract class AbstractVirtualTableRoute<T, TKey> : IVirtualTableRoute<T>, IEntityMetadataAutoBindInitializer where T : class
{
private readonly DoOnlyOnce _doOnlyOnce = new DoOnlyOnce();
@ -77,5 +77,9 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
/// <returns></returns>
public abstract List<string> GetAllTails();
public virtual void Configure(EntityMetadataTableBuilder<T> builder)
{
}
}
}

View File

@ -46,7 +46,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
}
public interface IVirtualTableRoute<T> : IVirtualTableRoute where T : class
public interface IVirtualTableRoute<T> : IVirtualTableRoute, IEntityMetadataTableConfiguration<T> where T : class
{
/// <summary>
/// 返回null就是表示不开启分页配置
@ -54,6 +54,5 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
/// <returns></returns>
IPaginationConfiguration<T> CreatePaginationConfiguration();
IEntityMetadataTableConfiguration<T> CreateEntityMetadataTableConfiguration();
}
}

View File

@ -44,7 +44,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntity);
var physicTables = virtualTable.RouteTo(new ShardingTableRouteConfig(tableRouteRuleContext.Queryable));
var physicTables = virtualTable.RouteTo(new ShardingTableRouteConfig(queryable: tableRouteRuleContext.Queryable));
if (!routeMaps.ContainsKey(virtualTable))
{
routeMaps.Add(virtualTable, physicTables.ToHashSet());

View File

@ -12,12 +12,12 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
public class ShardingTableRouteConfig
{
private readonly IQueryable _queryable;
private readonly IShardingTable _shardingTable;
private readonly object _shardingTable;
private readonly object _shardingKeyValue;
private readonly Expression _predicate;
public ShardingTableRouteConfig(IQueryable queryable=null,IShardingTable shardingTable=null,object shardingKeyValue=null,Expression predicate=null)
public ShardingTableRouteConfig(IQueryable queryable=null,object shardingTable=null,object shardingKeyValue=null,Expression predicate=null)
{
_queryable = queryable;
_shardingTable = shardingTable;
@ -34,7 +34,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
return _shardingKeyValue;
}
public IShardingTable GetShardingEntity()
public object GetShardingEntity()
{
return _shardingTable;
}

View File

@ -26,8 +26,10 @@ using ShardingCore.TableCreator;
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Bootstrapers;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.EFCores.OptionsExtensions;
using ShardingCore.Jobs;
namespace ShardingCore
{
@ -219,6 +221,8 @@ namespace ShardingCore
services.TryAddSingleton<IShardingPageManager, ShardingPageManager>();
services.TryAddSingleton<IShardingPageAccessor, ShardingPageAccessor>();
services.TryAddSingleton<IShardingBootstrapper, ShardingBootstrapper>();
services.AddShardingJob();
return services;
}
public static DbContextOptionsBuilder UseSharding<TShardingDbContext>(this DbContextOptionsBuilder optionsBuilder) where TShardingDbContext : DbContext, IShardingDbContext

View File

@ -81,7 +81,7 @@ namespace ShardingCore.Extensions
}
public static void RemoveDbContextRelationModelSaveOnlyThatIsNamedType<T>(this DbContext dbContext)
where T : IShardingTable
where T:class
{
RemoveDbContextRelationModelSaveOnlyThatIsNamedType(dbContext, typeof(T));
}

View File

@ -25,7 +25,7 @@ namespace ShardingCore.Extensions
/// <param name="shardingRouteContext"></param>
/// <param name="dataSources"></param>
/// <returns>任何一个dataSources被添加成功就返回成功</returns>
public static bool TryCreateOrAddMustDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] dataSources) where TEntity : class, IShardingDataSource
public static bool TryCreateOrAddMustDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] dataSources) where TEntity : class
{
return TryCreateOrAddMustDataSource(shardingRouteContext, typeof(TEntity), dataSources);
}
@ -60,7 +60,7 @@ namespace ShardingCore.Extensions
/// <param name="shardingRouteContext"></param>
/// <param name="dataSources"></param>
/// <returns>任何一个dataSources被添加成功就返回成功</returns>
public static bool TryCreateOrAddHintDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] dataSources) where TEntity : class, IShardingDataSource
public static bool TryCreateOrAddHintDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] dataSources) where TEntity : class
{
return TryCreateOrAddHintDataSource(shardingRouteContext, typeof(TEntity), dataSources);
}
@ -95,7 +95,7 @@ namespace ShardingCore.Extensions
/// <param name="shardingRouteContext"></param>
/// <param name="dataSources"></param>
/// <returns></returns>
public static bool TryCreateOrAddAssertDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params IDataSourceRouteAssert<TEntity>[] dataSources) where TEntity : class, IShardingDataSource
public static bool TryCreateOrAddAssertDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params IDataSourceRouteAssert<TEntity>[] dataSources) where TEntity : class
{
return TryCreateOrAddAssertDataSource(shardingRouteContext, typeof(TEntity), dataSources);
}
@ -123,7 +123,7 @@ namespace ShardingCore.Extensions
public static bool TryGetMustDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> dataSources) where TEntity : class, IShardingDataSource
public static bool TryGetMustDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> dataSources) where TEntity : class
{
return TryGetMustDataSource(shardingRouteContext,typeof(TEntity),out dataSources);
}
@ -143,7 +143,7 @@ namespace ShardingCore.Extensions
dataSources = shardingRouteContext.MustDataSource[entityType];
return true;
}
public static bool TryGetHintDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> dataSources) where TEntity : class,IShardingDataSource
public static bool TryGetHintDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> dataSources) where TEntity : class
{
return TryGetHintDataSource(shardingRouteContext,typeof(TEntity),out dataSources);
}
@ -164,7 +164,7 @@ namespace ShardingCore.Extensions
return true;
}
public static bool TryGetAssertDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out ICollection<IDataSourceRouteAssert> dataSources)where TEntity : class,IShardingDataSource
public static bool TryGetAssertDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out ICollection<IDataSourceRouteAssert> dataSources)where TEntity : class
{
return TryGetAssertDataSource(shardingRouteContext,typeof(TEntity), out dataSources);
}

View File

@ -25,7 +25,7 @@ namespace ShardingCore.Extensions
/// <param name="shardingRouteContext"></param>
/// <param name="tails"></param>
/// <returns>任何一个tails被添加成功就返回成功</returns>
public static bool TryCreateOrAddMustTail<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] tails) where TEntity : class, IShardingTable
public static bool TryCreateOrAddMustTail<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] tails) where TEntity : class
{
return TryCreateOrAddMustTail(shardingRouteContext, typeof(TEntity), tails);
}
@ -60,7 +60,7 @@ namespace ShardingCore.Extensions
/// <param name="shardingRouteContext"></param>
/// <param name="tails"></param>
/// <returns>任何一个tails被添加成功就返回成功</returns>
public static bool TryCreateOrAddHintTail<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] tails) where TEntity : class, IShardingTable
public static bool TryCreateOrAddHintTail<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] tails) where TEntity : class
{
return TryCreateOrAddHintTail(shardingRouteContext, typeof(TEntity), tails);
}
@ -95,7 +95,7 @@ namespace ShardingCore.Extensions
/// <param name="shardingRouteContext"></param>
/// <param name="tails"></param>
/// <returns></returns>
public static bool TryCreateOrAddAssertTail<TEntity>(this ShardingRouteContext shardingRouteContext, params ITableRouteAssert<TEntity>[] tails) where TEntity : class, IShardingTable
public static bool TryCreateOrAddAssertTail<TEntity>(this ShardingRouteContext shardingRouteContext, params ITableRouteAssert<TEntity>[] tails) where TEntity : class
{
return TryCreateOrAddAssertTail(shardingRouteContext, typeof(TEntity), tails);
}
@ -123,7 +123,7 @@ namespace ShardingCore.Extensions
public static bool TryGetMustTail<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> tail) where TEntity : class,IShardingTable
public static bool TryGetMustTail<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> tail) where TEntity : class
{
return TryGetMustTail(shardingRouteContext,typeof(TEntity),out tail);
}
@ -143,7 +143,7 @@ namespace ShardingCore.Extensions
tail = shardingRouteContext.MustTable[entityType];
return true;
}
public static bool TryGetHintTail<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> tail) where TEntity : class,IShardingTable
public static bool TryGetHintTail<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> tail) where TEntity : class
{
return TryGetHintTail(shardingRouteContext,typeof(TEntity),out tail);
}
@ -164,7 +164,7 @@ namespace ShardingCore.Extensions
return true;
}
public static bool TryGetAssertTail<TEntity>(this ShardingRouteContext shardingRouteContext, out ICollection<ITableRouteAssert> tail)where TEntity : class,IShardingTable
public static bool TryGetAssertTail<TEntity>(this ShardingRouteContext shardingRouteContext, out ICollection<ITableRouteAssert> tail)where TEntity : class
{
return TryGetAssertTail(shardingRouteContext,typeof(TEntity), out tail);
}

View File

@ -75,7 +75,7 @@ namespace ShardingCore.Extensions
public static string GetTableTail<TEntity>(this IVirtualTableManager virtualTableManager,
TEntity entity) where TEntity : class
{
var physicTable = virtualTableManager.GetVirtualTable(entity.GetType()).RouteTo(new ShardingTableRouteConfig(null, entity as IShardingTable, null))[0];
var physicTable = virtualTableManager.GetVirtualTable(entity.GetType()).RouteTo(new ShardingTableRouteConfig(shardingTable: entity))[0];
return physicTable.Tail;
}
public static string GetTableTail<TEntity>(this IVirtualTableManager virtualTableManager,

View File

@ -23,7 +23,7 @@ namespace ShardingCore.Extensions
{
return virtualDataSource.RouteTo(entity.GetType(),
new ShardingDataSourceRouteConfig(shardingDataSource: entity as IShardingDataSource))[0];
new ShardingDataSourceRouteConfig(shardingDataSource: entity))[0];
}
public static List<string> GetDataSourceNames<TEntity>(this IVirtualDataSource virtualDataSource, Expression<Func<TEntity, bool>> where)

View File

@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
namespace ShardingCore.Utils
namespace ShardingCore.Helpers
{
public class EntityMetadataHelper
{
@ -37,7 +35,7 @@ namespace ShardingCore.Utils
? (bool?) null
: (shardingKey.AutoCreateTableOnStart == ShardingKeyAutoCreateTableEnum.Create);
builder.AutoCreateTable(autoCreateTable);
builder.TableSeparator(shardingKey.TailPrefix);
builder.TableSeparator(shardingKey.TableSeparator);
shardingTableCount++;
}
}

View File

@ -0,0 +1,8 @@
namespace ShardingCore.Jobs.Abstaractions
{
internal interface IJob
{
string JobName { get; }
bool StartJob();
}
}

View File

@ -0,0 +1,16 @@
namespace ShardingCore.Jobs.Abstaractions
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 08 January 2021 22:19:57
* @Email: 326308290@qq.com
*/
internal interface IJobExecutor
{
void Run();
bool IsRunning();
bool StartJob();
void Complete();
}
}

View File

@ -0,0 +1,16 @@
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Jobs.Impls;
namespace ShardingCore.Jobs.Abstaractions
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 08 January 2021 08:22:41
* @Email: 326308290@qq.com
*/
internal interface IJobFactory
{
object CreateJobInstance(IServiceScope scope,JobEntry jobEntry);
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using ShardingCore.Jobs.Impls;
namespace ShardingCore.Jobs.Abstaractions
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 06 January 2021 13:10:13
* @Email: 326308290@qq.com
*/
internal interface IJobManager
{
void AddJob(JobEntry jobEntry);
bool HasAnyJob();
List<JobEntry> GetNowRunJobs();
DateTime? GetNextJobUtcTime();
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace ShardingCore.Jobs.Abstaractions
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 08 January 2021 22:18:30
* @Email: 326308290@qq.com
*/
public interface IJobTrigger
{
DateTime NextJobRunUtcTime();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
/*
* Copyright 2004-2009 James House
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
using System.Collections;
namespace ShardingCore.Jobs.Cron
{
/// <summary>
/// Represents a collection ob objects that contains no duplicate elements.
/// </summary>
internal interface ISet : ICollection, IList
{
/// <summary>
/// Adds a new element to the Collection if it is not already present.
/// </summary>
/// <param name="obj">The object to add to the collection.</param>
/// <returns>Returns true if the object was added to the collection, otherwise false.</returns>
new bool Add(object obj);
/// <summary>
/// Adds all the elements of the specified collection to the Set.
/// </summary>
/// <param name="c">Collection of objects to add.</param>
/// <returns>true</returns>
bool AddAll(ICollection c);
/// <summary>
/// Returns the first item in the set.
/// </summary>
/// <returns>First object.</returns>
object First();
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2004-2009 James House
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
using ShardingCore.Jobs.Cron;
namespace ShardingCore.Jobs
{
/// <summary>
/// A sorted set.
/// </summary>
internal interface ISortedSet : ISet
{
/// <summary>
/// Returns a portion of the list whose elements are greater than the limit object parameter.
/// </summary>
/// <param name="limit">The start element of the portion to extract.</param>
/// <returns>The portion of the collection whose elements are greater than the limit object parameter.</returns>
ISortedSet TailSet(object limit);
}
}

View File

@ -0,0 +1,170 @@
/*
* Copyright 2004-2009 James House
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
using System;
using System.Collections;
namespace ShardingCore.Jobs.Cron
{
/// <summary>
/// SupportClass for the TreeSet class.
/// </summary>
[Serializable]
internal class TreeSet : ArrayList, ISortedSet
{
private readonly IComparer comparator = Comparer.Default;
/// <summary>
/// Initializes a new instance of the <see cref="TreeSet"/> class.
/// </summary>
public TreeSet()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TreeSet"/> class.
/// </summary>
/// <param name="c">The <see cref="T:System.Collections.ICollection"/> whose elements are copied to the new list.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="c"/> is <see langword="null"/>.</exception>
public TreeSet(ICollection c)
{
AddAll(c);
}
/// <summary>
/// Initializes a new instance of the <see cref="TreeSet"/> class.
/// </summary>
/// <param name="c">The c.</param>
public TreeSet(IComparer c)
{
comparator = c;
}
/// <summary>
/// Unmodifiables the tree set.
/// </summary>
/// <param name="collection">The collection.</param>
/// <returns></returns>
public static TreeSet UnmodifiableTreeSet(ICollection collection)
{
ArrayList items = new ArrayList(collection);
items = ReadOnly(items);
return new TreeSet(items);
}
/// <summary>
/// Gets the IComparator object used to sort this set.
/// </summary>
public IComparer Comparator
{
get { return comparator; }
}
private bool AddWithoutSorting(object obj)
{
bool inserted;
if (!(inserted = Contains(obj)))
{
base.Add(obj);
}
return !inserted;
}
/// <summary>
/// Adds a new element to the ArrayList if it is not already present and sorts the ArrayList.
/// </summary>
/// <param name="obj">Element to insert to the ArrayList.</param>
/// <returns>TRUE if the new element was inserted, FALSE otherwise.</returns>
public new bool Add(object obj)
{
bool inserted = AddWithoutSorting(obj);
Sort(comparator);
return inserted;
}
/// <summary>
/// Adds all the elements of the specified collection that are not present to the list.
/// </summary>
/// <param name="c">Collection where the new elements will be added</param>
/// <returns>Returns true if at least one element was added to the collection.</returns>
public bool AddAll(ICollection c)
{
IEnumerator e = new ArrayList(c).GetEnumerator();
bool added = false;
while (e.MoveNext())
{
if (AddWithoutSorting(e.Current))
{
added = true;
}
}
Sort(comparator);
return added;
}
/// <summary>
/// Returns the first item in the set.
/// </summary>
/// <returns>First object.</returns>
public object First()
{
return this[0];
}
/// <summary>
/// Determines whether an element is in the the current TreeSetSupport collection. The IComparer defined for
/// the current set will be used to make comparisons between the elements already inserted in the collection and
/// the item specified.
/// </summary>
/// <param name="item">The object to be locatet in the current collection.</param>
/// <returns>true if item is found in the collection; otherwise, false.</returns>
public override bool Contains(object item)
{
IEnumerator tempEnumerator = GetEnumerator();
while (tempEnumerator.MoveNext())
{
if (comparator.Compare(tempEnumerator.Current, item) == 0)
{
return true;
}
}
return false;
}
/// <summary>
/// Returns a portion of the list whose elements are greater than the limit object parameter.
/// </summary>
/// <param name="limit">The start element of the portion to extract.</param>
/// <returns>The portion of the collection whose elements are greater than the limit object parameter.</returns>
public ISortedSet TailSet(object limit)
{
ISortedSet newList = new TreeSet();
int i = 0;
while ((i < Count) && (comparator.Compare(this[i], limit) < 0))
{
i++;
}
for (; i < Count; i++)
{
newList.Add(this[i]);
}
return newList;
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls;
namespace ShardingCore.Jobs
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 07 January 2021 13:34:52
* @Email: 326308290@qq.com
*/
internal static class DIExtension
{
public static IServiceCollection AddShardingJob(this IServiceCollection services, Action<JobGlobalOptions> config=null)
{
var option = new JobGlobalOptions();
config?.Invoke(option);
services.AddSingleton(sp => option).AddSingleton<IJobManager, InMemoryJobManager>()
.AddSingleton<JobRunnerService>()
.AddSingleton<IJobFactory, DefaultJobFactory>();
return services;
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
using ShardingCore.Jobs.Abstaractions;
namespace ShardingCore.Jobs.Extensions
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 06 January 2021 13:08:55
* @Email: 326308290@qq.com
*/
internal static class CommonExtension
{
public static bool IsJobType(this Type entityType)
{
if (entityType == null)
throw new ArgumentNullException(nameof(entityType));
return typeof(IJob).IsAssignableFrom(entityType);
}
public static bool IsAsyncMethod(this MethodInfo method)
{
return (typeof(Task).IsAssignableFrom(method.ReturnType));
}
}
}

View File

@ -0,0 +1,59 @@
using System;
namespace ShardingCore.Jobs.Impls.Attributes
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 06 January 2021 13:04:57
* @Email: 326308290@qq.com
*/
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
internal class JobRunAttribute:Attribute
{
/// <summary>
/// 任务名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime BeginUtcTime => GetBeginUtcTime();
/// <summary>
/// 任务开始时间优先级最高,格式:yyyy/MM/dd HH:mm:ss、yyyy-MM-dd HH:mm:ss
/// </summary>
public string Begin { get; set; }
private DateTime GetBeginUtcTime()
{
if (!string.IsNullOrWhiteSpace(Begin))
{
var localTime = Convert.ToDateTime(Begin);
var utcOffset = TimeZoneInfo.Local.BaseUtcOffset.TotalMilliseconds;
return localTime.AddMilliseconds(-utcOffset);
}
else
{
return DateTime.UtcNow;
}
}
/// <summary>
/// 默认每分钟执行
/// </summary>
public string Cron { get; set; } = "0 * * * * ? *";
/// <summary>
/// 如果正在运行就跳过
/// </summary>
public bool SkipIfRunning { get; set; } = true;
/// <summary>
/// 是否从di容器中获取
/// </summary>
public bool CreateFromServiceProvider { get; set; } = false;
/// <summary>
/// 是否马上执行在程序启动后 需要优先满足Begin条件
/// </summary>
public bool RunOnceOnStart { get; set; } = false;
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Jobs.Abstaractions;
namespace ShardingCore.Jobs.Impls
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 08 January 2021 08:25:24
* @Email: 326308290@qq.com
*/
internal class DefaultJobFactory:IJobFactory
{
public object CreateJobInstance(IServiceScope scope,JobEntry jobEntry)
{
if (jobEntry.CreateFromServiceProvider)
{
return scope.ServiceProvider.GetService(jobEntry.JobClass);
}
var args = jobEntry.JobClass.GetConstructors()
.First()
.GetParameters()
.Select(x =>
{
if (x.ParameterType == typeof(IServiceProvider))
return scope.ServiceProvider;
else
return scope.ServiceProvider.GetService(x.ParameterType);
})
.ToArray();
return Activator.CreateInstance(jobEntry.JobClass, args);
}
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Jobs.Abstaractions;
namespace ShardingCore.Jobs.Impls
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 06 January 2021 13:11:38
* @Email: 326308290@qq.com
*/
internal class InMemoryJobManager : IJobManager
{
private readonly List<JobEntry> _jobs = new List<JobEntry>();
public void AddJob(JobEntry jobEntry)
{
if (_jobs.Any(job => job.JobName == jobEntry.JobName))
throw new ArgumentException($"发现重复的任务名称:{jobEntry.JobName},请确认");
_jobs.Add(jobEntry);
}
public bool HasAnyJob()
{
return _jobs.Any();
}
public List<JobEntry> GetNowRunJobs()
{
var now = DateTime.UtcNow;
return _jobs.Where(o => o.NextUtcTime.HasValue && o.NextUtcTime.Value <= now&&!o.Running).ToList();
}
public DateTime? GetNextJobUtcTime()
{
var waitRunJobs = _jobs.Where(o => o.NextUtcTime.HasValue&&!o.Running).ToArray();
if (!waitRunJobs.Any())
return null;
return waitRunJobs.Min(o => o.NextUtcTime.Value);
}
}
}

View File

@ -0,0 +1,79 @@
using System;
using System.Reflection;
using System.Threading;
namespace ShardingCore.Jobs.Impls
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 06 January 2021 13:13:23
* @Email: 326308290@qq.com
*/
internal class JobEntry
{
/// <summary>
/// 保证多线程只有一个清理操作
/// </summary>
private const int running = 1;
/// <summary>
/// 为运行
/// </summary>
private const int unrunning = 0;
/// <summary>
/// 任务名称
/// </summary>
public string JobName { get; set; }
public Type JobClass { get; set; }
public MethodInfo JobMethod { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime BeginUtcTime { get; set; }
/// <summary>
/// 表达式
/// </summary>
public string Cron { get; set; }
/// <summary>
/// 是否跳过如果正在运行
/// </summary>
public bool SkipIfRunning { get; set; }
/// <summary>
/// 是否从di容器中获取
/// </summary>
public bool CreateFromServiceProvider { get; set; }
/// <summary>
/// 下次运行时间
/// </summary>
public DateTime? NextUtcTime { get; set; }
/// <summary>
/// 是否正在运行
/// </summary>
public bool Running => runStatus == running;
private int runStatus = unrunning;
public bool StartRun()
{
if (SkipIfRunning)
return Interlocked.CompareExchange(ref runStatus, running, unrunning) == unrunning;
return true;
}
public void CompleteRun()
{
if (SkipIfRunning)
runStatus = unrunning;
}
}
}

View File

@ -0,0 +1,16 @@
namespace ShardingCore.Jobs.Impls
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 08 January 2021 08:16:08
* @Email: 326308290@qq.com
*/
internal class JobGlobalOptions
{
/// <summary>
/// 延迟启动时间
/// </summary>
public int DelaySecondsOnStart { get; set; } = 10;
}
}

View File

@ -0,0 +1,175 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Cron;
using ShardingCore.Jobs.Extensions;
using ShardingCore.Jobs.Impls;
namespace ShardingCore.Jobs
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 06 January 2021 13:00:11
* @Email: 326308290@qq.com
*/
internal class JobRunnerService
{
private readonly IServiceProvider _serviceProvider;
private readonly JobGlobalOptions _jobGlobalOptions;
private readonly IJobManager _jobManager;
private readonly ILogger<JobRunnerService> _logger;
private readonly IJobFactory _jobFactory;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private const long DEFAULT_MILLIS = 1000L;
/// <summary>
/// 最大休眠时间30秒
/// </summary>
private const long MAX_DELAY_MILLIS = 30000L;
public JobRunnerService(IServiceProvider serviceProvider,JobGlobalOptions jobGlobalOptions, IJobManager jobManager, ILogger<JobRunnerService> logger, IJobFactory jobFactory)
{
_serviceProvider = serviceProvider;
_jobGlobalOptions = jobGlobalOptions;
_jobManager = jobManager;
_logger = logger;
_jobFactory = jobFactory;
}
//private void Init()
//{
// var assemblies = AssemblyHelper.CurrentDomain.GetAssemblies();
// foreach (var x in assemblies)
// {
// // 查找接口为Job的类
// var types = x.DefinedTypes.Where(y => y.IsJobType()).ToList();
// foreach (var y in types)
// {
// var jobs = JobTypeParser.Parse(y.AsType());
// foreach (var job in jobs)
// {
// _jobManager.AddJob(job);
// }
// }
// }
//}
public async Task StartAsync()
{
if (_jobGlobalOptions.DelaySecondsOnStart > 0)
await Task.Delay(TimeSpan.FromSeconds(_jobGlobalOptions.DelaySecondsOnStart),_cts.Token);
while (!_cts.Token.IsCancellationRequested)
{
var delayMs = 0L;
try
{
delayMs = LoopJobAndGetWaitMillis();
}
catch (Exception e)
{
_logger.LogError($"job runner service exception : {e}");
await Task.Delay((int) DEFAULT_MILLIS, _cts.Token);
}
if (delayMs > 0)
await Task.Delay((int) Math.Min(MAX_DELAY_MILLIS, delayMs), _cts.Token); //最大休息为MAX_DELAY_MILLIS
}
}
public Task StopAsync()
{
_cts.Cancel();
return Task.CompletedTask;
}
/// <summary>
///
/// </summary>
/// <returns>next utc time that job when restart</returns>
private long LoopJobAndGetWaitMillis()
{
var beginTime = UtcTime.CurrentTimeMillis();
var costTime = 0L;
var runJobs = _jobManager.GetNowRunJobs();
if (!runJobs.Any())
{
var minJobUtcTime = _jobManager.GetNextJobUtcTime();
if (!minJobUtcTime.HasValue)
{
//return wait one second
costTime = UtcTime.CurrentTimeMillis() - beginTime;
if (DEFAULT_MILLIS < costTime)
return 0L;
return DEFAULT_MILLIS - costTime;
}
else
{
//return next job run time
return UtcTime.InputUtcTimeMillis(minJobUtcTime.Value) - beginTime;
}
}
foreach (var job in runJobs)
{
DoJob(job);
}
costTime = UtcTime.CurrentTimeMillis() - beginTime;
if (costTime > DEFAULT_MILLIS)
{
return 0L;
}
return DEFAULT_MILLIS - costTime;
}
private void DoJob(JobEntry jobEntry)
{
if (jobEntry.StartRun())
{
Task.Factory.StartNew(async () =>
{
try
{
using (var scope = _serviceProvider.CreateScope())
{
var job = _jobFactory.CreateJobInstance(scope, jobEntry);
if (job == null)
_logger.LogWarning($"### job [{jobEntry.JobName}] cant created, create method :{(jobEntry.CreateFromServiceProvider ? "from service provider" : "activator")}");
var method = jobEntry.JobMethod;
var @params = method.GetParameters().Select(x => scope.ServiceProvider.GetService(x.ParameterType)).ToArray();
_logger.LogInformation($"### job [{jobEntry.JobName}] start success.");
if (method.IsAsyncMethod())
{
if (method.Invoke(job, @params) is Task task)
await task;
}
else
{
method.Invoke(job, @params);
}
_logger.LogInformation($"### job [{jobEntry.JobName}] invoke complete.");
jobEntry.NextUtcTime = new CronExpression(jobEntry.Cron).GetTimeAfter(DateTime.UtcNow);
if (!jobEntry.NextUtcTime.HasValue)
_logger.LogWarning($"### job [{jobEntry.JobName}] is stopped.");
}
}
catch (Exception e)
{
_logger.LogError($"### job [{jobEntry.JobName}] invoke fail : {e}.");
}
finally
{
jobEntry.CompleteRun();
}
});
}
}
}
}

View File

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using ShardingCore.Jobs.Cron;
using ShardingCore.Jobs.Extensions;
using ShardingCore.Jobs.Impls;
using ShardingCore.Jobs.Impls.Attributes;
namespace ShardingCore.Jobs
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 06 January 2021 15:48:59
* @Email: 326308290@qq.com
*/
internal class JobTypeParser
{
private JobTypeParser(){}
public static List<JobEntry> Parse(Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (!type.IsJobType())
throw new NotSupportedException(type.FullName);
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
var list = new List<JobEntry>();
foreach (var method in methods)
{
var jobRun = method.GetCustomAttribute<JobRunAttribute>();
if ( jobRun!= null)
{
var jobEntry = new JobEntry()
{
BeginUtcTime = jobRun.BeginUtcTime,
Cron = jobRun.Cron,
JobName = jobRun.Name ?? (type.Name + "." + method.Name),
NextUtcTime = GetNextRunUtcTime(jobRun),
SkipIfRunning = jobRun.SkipIfRunning,
CreateFromServiceProvider = jobRun.CreateFromServiceProvider,
JobClass = type,
JobMethod = method
};
list.Add(jobEntry);
}
}
return list;
}
/// <summary>
/// 判断时间是否满足启动时间如果满足就判断是需要在程序启动时就执行一次,如果需要就返回当前时间,如果不需要就按启动时间生成下次执行时间
/// </summary>
/// <param name="jobRun"></param>
/// <returns></returns>
private static DateTime? GetNextRunUtcTime(JobRunAttribute jobRun)
{
var utcNow = DateTime.UtcNow;
if (utcNow >= jobRun.BeginUtcTime)
{
if (jobRun.RunOnceOnStart)
{
return utcNow;
}
}
return new CronExpression(jobRun.Cron).GetTimeAfter(jobRun.BeginUtcTime);
}
}
}

View File

@ -0,0 +1,25 @@
using System;
namespace ShardingCore.Jobs
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 07 January 2021 13:01:53
* @Email: 326308290@qq.com
*/
internal class UtcTime
{
private UtcTime(){}
private static readonly long UtcStartTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
public static long CurrentTimeMillis()
{
return (DateTime.UtcNow.Ticks - UtcStartTicks) / 10000;
}
public static long InputUtcTimeMillis(DateTime utcTime)
{
return (utcTime.Ticks - UtcStartTicks) / 10000;
}
}
}

View File

@ -1,251 +1,252 @@
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Core.VirtualDatabase;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
//using System;
//using System.Collections;
//using System.Linq;
//using System.Linq.Expressions;
//using ShardingCore.Core.EntityMetadatas;
//using ShardingCore.Core.VirtualDatabase;
//using ShardingCore.Core.VirtualRoutes;
//using ShardingCore.Exceptions;
//using ShardingCore.Extensions;
namespace ShardingCore.Core.Internal.Visitors
{
/*
* @Author: xjm
* @Description:
* @Date: Saturday, 06 February 2021 09:38:22
* @Email: 326308290@qq.com
*/
public class QueryableRouteShardingDataSourceDiscoverVisitor<TKey> : ExpressionVisitor
{
private readonly ShardingEntityConfig _shardingEntityBaseType;
private readonly Func<object, TKey> _shardingKeyConvert;
private readonly Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> _keyToDataSourceWithFilter;
private Expression<Func<string, bool>> _where = x => true;
//namespace ShardingCore.Core.Internal.Visitors
//{
///*
//* @Author: xjm
//* @Description:
//* @Date: Saturday, 06 February 2021 09:38:22
//* @Email: 326308290@qq.com
//*/
// public class QueryableRouteShardingDataSourceDiscoverVisitor<TKey> : ExpressionVisitor
// {
// private readonly EntityMetadata _entityMetadata;
// private readonly Func<object, TKey> _shardingKeyConvert;
// private readonly Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> _keyToDataSourceWithFilter;
// private Expression<Func<string, bool>> _where = x => true;
public QueryableRouteShardingDataSourceDiscoverVisitor(ShardingEntityConfig shardingEntityBaseType, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToDataSourceWithFilter)
{
_shardingEntityBaseType = shardingEntityBaseType;
_shardingKeyConvert = shardingKeyConvert;
_keyToDataSourceWithFilter = keyToDataSourceWithFilter;
}
// public QueryableRouteShardingDataSourceDiscoverVisitor(EntityMetadata entityMetadata, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToDataSourceWithFilter)
// {
// _entityMetadata = entityMetadata;
// _shardingKeyConvert = shardingKeyConvert;
// _keyToDataSourceWithFilter = keyToDataSourceWithFilter;
// }
public Func<string, bool> GetDataSourceFilter()
{
return _where.Compile();
}
// public Func<string, bool> GetDataSourceFilter()
// {
// return _where.Compile();
// }
private bool IsShardingKey(Expression expression)
{
return expression is MemberExpression member
&& member.Expression.Type == _shardingEntityBaseType.EntityType
&& member.Member.Name == _shardingEntityBaseType.ShardingDataSourceField;
}
/// <summary>
/// 方法是否包含shardingKey
/// </summary>
/// <param name="methodCallExpression"></param>
/// <returns></returns>
private bool IsMethodWrapShardingKey(MethodCallExpression methodCallExpression)
{
if (methodCallExpression.Arguments.IsNotEmpty())
{
for (int i = 0; i < methodCallExpression.Arguments.Count; i++)
{
var isShardingKey = methodCallExpression.Arguments[i] is MemberExpression member
&& member.Expression.Type == _shardingEntityBaseType.EntityType
&& member.Member.Name == _shardingEntityBaseType.ShardingTableField;
if (isShardingKey) return true;
}
}
// private bool IsShardingKey(Expression expression)
// {
// return expression is MemberExpression member
// && member.Expression.Type == _entityMetadata.EntityType
// && member.Member.Name == _entityMetadata.ShardingDataSourceProperty.Name;
// }
// /// <summary>
// /// 方法是否包含shardingKey
// /// </summary>
// /// <param name="methodCallExpression"></param>
// /// <returns></returns>
// private bool IsMethodWrapShardingKey(MethodCallExpression methodCallExpression)
// {
// if (methodCallExpression.Arguments.IsNotEmpty())
// {
// for (int i = 0; i < methodCallExpression.Arguments.Count; i++)
// {
// var isShardingKey = methodCallExpression.Arguments[i] is MemberExpression member
// && member.Expression.Type == _entityMetadata.EntityType
// && member.Member.Name == _entityMetadata.ShardingDataSourceProperty.Name;
// if (isShardingKey) return true;
// }
// }
return false;
}
private bool IsConstantOrMember(Expression expression)
{
return expression is ConstantExpression
|| (expression is MemberExpression member && (member.Expression is ConstantExpression || member.Expression is MemberExpression || member.Expression is MemberExpression));
}
// return false;
// }
// private bool IsConstantOrMember(Expression expression)
// {
// return expression is ConstantExpression
// || (expression is MemberExpression member && (member.Expression is ConstantExpression || member.Expression is MemberExpression || member.Expression is MemberExpression));
// }
private object GetFieldValue(Expression expression)
{
if (expression is ConstantExpression)
return (expression as ConstantExpression).Value;
if (expression is UnaryExpression)
{
UnaryExpression unary = expression as UnaryExpression;
LambdaExpression lambda = Expression.Lambda(unary.Operand);
Delegate fn = lambda.Compile();
return fn.DynamicInvoke(null);
}
// private object GetFieldValue(Expression expression)
// {
// if (expression is ConstantExpression)
// return (expression as ConstantExpression).Value;
// if (expression is UnaryExpression)
// {
// UnaryExpression unary = expression as UnaryExpression;
// LambdaExpression lambda = Expression.Lambda(unary.Operand);
// Delegate fn = lambda.Compile();
// return fn.DynamicInvoke(null);
// }
if (expression is MemberExpression member1Expression)
{
return Expression.Lambda(member1Expression).Compile().DynamicInvoke();
}
// if (expression is MemberExpression member1Expression)
// {
// return Expression.Lambda(member1Expression).Compile().DynamicInvoke();
// }
throw new ShardingKeyGetValueException("cant get value " + expression);
}
// throw new ShardingKeyGetValueException("cant get value " + expression);
// }
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.Name == nameof(Queryable.Where))
{
if (node.Arguments[1] is UnaryExpression unaryExpression)
{
if (unaryExpression.Operand is LambdaExpression lambdaExpression)
{
var newWhere = Resolve(lambdaExpression);
_where = _where.And(newWhere);
}
}
}
// protected override Expression VisitMethodCall(MethodCallExpression node)
// {
// if (node.Method.Name == nameof(Queryable.Where))
// {
// if (node.Arguments[1] is UnaryExpression unaryExpression)
// {
// if (unaryExpression.Operand is LambdaExpression lambdaExpression)
// {
// var newWhere = Resolve(lambdaExpression);
// _where = _where.And(newWhere);
// }
// }
// }
return base.VisitMethodCall(node);
}
// return base.VisitMethodCall(node);
// }
private Expression<Func<string, bool>> Resolve(Expression expression)
{
if (expression is LambdaExpression)
{
LambdaExpression lambda = expression as LambdaExpression;
expression = lambda.Body;
return Resolve(expression);
}
// private Expression<Func<string, bool>> Resolve(Expression expression)
// {
// if (expression is LambdaExpression)
// {
// LambdaExpression lambda = expression as LambdaExpression;
// expression = lambda.Body;
// return Resolve(expression);
// }
if (expression is BinaryExpression binaryExpression) //解析二元运算符
{
return ParseGetWhere(binaryExpression);
}
// if (expression is BinaryExpression binaryExpression) //解析二元运算符
// {
// return ParseGetWhere(binaryExpression);
// }
if (expression is UnaryExpression) //解析一元运算符
{
UnaryExpression unary = expression as UnaryExpression;
if (unary.Operand is MethodCallExpression methodCall1Expression)
{
// return ResolveLinqToObject(unary.Operand, false);
return ResolveInFunc(methodCall1Expression, unary.NodeType != ExpressionType.Not);
}
}
// if (expression is UnaryExpression) //解析一元运算符
// {
// UnaryExpression unary = expression as UnaryExpression;
// if (unary.Operand is MethodCallExpression methodCall1Expression)
// {
// // return ResolveLinqToObject(unary.Operand, false);
// return ResolveInFunc(methodCall1Expression, unary.NodeType != ExpressionType.Not);
// }
// }
if (expression is MethodCallExpression methodCallExpression) //解析扩展方法
{
return ResolveInFunc(methodCallExpression, true);
}
return o => true;
}
// if (expression is MethodCallExpression methodCallExpression) //解析扩展方法
// {
// return ResolveInFunc(methodCallExpression, true);
// }
// return o => true;
// }
private Expression<Func<string, bool>> ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
{
if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name) && IsMethodWrapShardingKey(methodCallExpression))
{
object arrayObject = null;
if (methodCallExpression.Object != null)
{
if (methodCallExpression.Object is MemberExpression member1Expression)
{
arrayObject = Expression.Lambda(member1Expression).Compile().DynamicInvoke();
}
else if (methodCallExpression.Object is ListInitExpression member2Expression)
{
arrayObject = Expression.Lambda(member2Expression).Compile().DynamicInvoke();
}
}
else if (methodCallExpression.Arguments[0] is MemberExpression member2Expression)
{
arrayObject = Expression.Lambda(member2Expression).Compile().DynamicInvoke();
}
else if (methodCallExpression.Arguments[0] is NewArrayExpression member3Expression)
{
arrayObject = Expression.Lambda(member3Expression).Compile().DynamicInvoke();
}
// private Expression<Func<string, bool>> ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
// {
// if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name) && IsMethodWrapShardingKey(methodCallExpression))
// {
// object arrayObject = null;
// if (methodCallExpression.Object != null)
// {
// if (methodCallExpression.Object is MemberExpression member1Expression)
// {
// arrayObject = Expression.Lambda(member1Expression).Compile().DynamicInvoke();
// }
// else if (methodCallExpression.Object is ListInitExpression member2Expression)
// {
// arrayObject = Expression.Lambda(member2Expression).Compile().DynamicInvoke();
// }
// }
// else if (methodCallExpression.Arguments[0] is MemberExpression member2Expression)
// {
// arrayObject = Expression.Lambda(member2Expression).Compile().DynamicInvoke();
// }
// else if (methodCallExpression.Arguments[0] is NewArrayExpression member3Expression)
// {
// arrayObject = Expression.Lambda(member3Expression).Compile().DynamicInvoke();
// }
if (arrayObject != null)
{
var enumerable = (IEnumerable) arrayObject;
Expression<Func<string, bool>> contains = x => false;
if (!@in)
contains = x => true;
foreach (var item in enumerable)
{
var keyValue = _shardingKeyConvert(item);
var eq = _keyToDataSourceWithFilter(keyValue, @in ? ShardingOperatorEnum.Equal : ShardingOperatorEnum.NotEqual);
if (@in)
contains = contains.Or(eq);
else
contains = contains.And(eq);
}
// if (arrayObject != null)
// {
// var enumerable = (IEnumerable) arrayObject;
// Expression<Func<string, bool>> contains = x => false;
// if (!@in)
// contains = x => true;
// foreach (var item in enumerable)
// {
// var keyValue = _shardingKeyConvert(item);
// var eq = _keyToDataSourceWithFilter(keyValue, @in ? ShardingOperatorEnum.Equal : ShardingOperatorEnum.NotEqual);
// if (@in)
// contains = contains.Or(eq);
// else
// contains = contains.And(eq);
// }
return contains;
}
}
// return contains;
// }
// }
return x => true;
}
// return x => true;
// }
private Expression<Func<string, bool>> ParseGetWhere(BinaryExpression binaryExpression)
{
Expression<Func<string, bool>> left = x => true;
Expression<Func<string, bool>> right = x => true;
// private Expression<Func<string, bool>> ParseGetWhere(BinaryExpression binaryExpression)
// {
// Expression<Func<string, bool>> left = x => true;
// Expression<Func<string, bool>> right = x => true;
//递归获取
if (binaryExpression.Left is BinaryExpression)
left = ParseGetWhere(binaryExpression.Left as BinaryExpression);
if (binaryExpression.Left is MethodCallExpression methodCallExpression)
left = Resolve(methodCallExpression);
// //递归获取
// if (binaryExpression.Left is BinaryExpression)
// left = ParseGetWhere(binaryExpression.Left as BinaryExpression);
// if (binaryExpression.Left is MethodCallExpression methodCallExpression)
// left = Resolve(methodCallExpression);
if (binaryExpression.Left is UnaryExpression unaryExpression)
left = Resolve(unaryExpression);
// if (binaryExpression.Left is UnaryExpression unaryExpression)
// left = Resolve(unaryExpression);
if (binaryExpression.Right is BinaryExpression)
right = ParseGetWhere(binaryExpression.Right as BinaryExpression);
// if (binaryExpression.Right is BinaryExpression)
// right = ParseGetWhere(binaryExpression.Right as BinaryExpression);
//组合
if (binaryExpression.NodeType == ExpressionType.AndAlso)
{
return left.And(right);
}
else if (binaryExpression.NodeType == ExpressionType.OrElse)
{
return left.Or(right);
}
//单个
else
{
bool paramterAtLeft;
object value = null;
// //组合
// if (binaryExpression.NodeType == ExpressionType.AndAlso)
// {
// return left.And(right);
// }
// else if (binaryExpression.NodeType == ExpressionType.OrElse)
// {
// return left.Or(right);
// }
// //单个
// else
// {
// bool paramterAtLeft;
// object value = null;
if (IsShardingKey(binaryExpression.Left) && IsConstantOrMember(binaryExpression.Right))
{
paramterAtLeft = true;
value = GetFieldValue(binaryExpression.Right);
}
else if (IsConstantOrMember(binaryExpression.Left) && IsShardingKey(binaryExpression.Right))
{
paramterAtLeft = false;
value = GetFieldValue(binaryExpression.Left);
}
else
return x => true;
// if (IsShardingKey(binaryExpression.Left) && IsConstantOrMember(binaryExpression.Right))
// {
// paramterAtLeft = true;
// value = GetFieldValue(binaryExpression.Right);
// }
// else if (IsConstantOrMember(binaryExpression.Left) && IsShardingKey(binaryExpression.Right))
// {
// paramterAtLeft = false;
// value = GetFieldValue(binaryExpression.Left);
// }
// else
// return x => true;
var op = binaryExpression.NodeType switch
{
ExpressionType.GreaterThan => paramterAtLeft ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan,
ExpressionType.GreaterThanOrEqual => paramterAtLeft ? ShardingOperatorEnum.GreaterThanOrEqual : ShardingOperatorEnum.LessThanOrEqual,
ExpressionType.LessThan => paramterAtLeft ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan,
ExpressionType.LessThanOrEqual => paramterAtLeft ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual,
ExpressionType.Equal => ShardingOperatorEnum.Equal,
ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
_ => ShardingOperatorEnum.UnKnown
};
// var op = binaryExpression.NodeType switch
// {
// ExpressionType.GreaterThan => paramterAtLeft ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan,
// ExpressionType.GreaterThanOrEqual => paramterAtLeft ? ShardingOperatorEnum.GreaterThanOrEqual : ShardingOperatorEnum.LessThanOrEqual,
// ExpressionType.LessThan => paramterAtLeft ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan,
// ExpressionType.LessThanOrEqual => paramterAtLeft ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual,
// ExpressionType.Equal => ShardingOperatorEnum.Equal,
// ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
// _ => ShardingOperatorEnum.UnKnown
// };
if (value == null)
return x => true;
// if (value == null)
// return x => true;
var keyValue = _shardingKeyConvert(value);
return _keyToDataSourceWithFilter(keyValue, op);
}
}
}
}
// var keyValue = _shardingKeyConvert(value);
// return _keyToDataSourceWithFilter(keyValue, op);
// }
// }
// }
//}

View File

@ -12,16 +12,15 @@ namespace ShardingCore.TableCreator
* @Date: Monday, 21 December 2020 11:22:08
* @Email: 326308290@qq.com
*/
public interface IShardingTableCreator<TShardingDbContext> where TShardingDbContext : DbContext, IShardingDbContext
public interface IShardingTableCreator
{
/// <summary>
/// 创建表
/// </summary>
/// <param name="dataSourceName"></param>
/// <param name="tail"></param>
/// <typeparam name="T"></typeparam>
void CreateTable<T>(string dataSourceName, string tail) where T : class, IShardingTable;
void CreateTable<T>(string dataSourceName, string tail) where T : class;
/// <summary>
/// 创建表
/// </summary>
@ -31,4 +30,8 @@ namespace ShardingCore.TableCreator
/// <exception cref="ShardingCreateException"></exception>
void CreateTable(string dataSourceName, Type shardingEntityType, string tail);
}
public interface IShardingTableCreator<TShardingDbContext>: IShardingTableCreator where TShardingDbContext : DbContext, IShardingDbContext
{
}
}

View File

@ -44,7 +44,7 @@ namespace ShardingCore.TableCreator
_routeTailFactory = routeTailFactory;
}
public void CreateTable< T>(string dataSourceName, string tail) where T : class, IShardingTable
public void CreateTable<T>(string dataSourceName, string tail) where T : class
{
CreateTable(dataSourceName,typeof(T), tail);
}

View File

@ -23,24 +23,24 @@ namespace ShardingCore.Utils
*/
public class ShardingUtil
{
/// <summary>
/// ·Ö¿â·ÓɹýÂË
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <param name="queryable"></param>
/// <param name="shardingEntityBaseType"></param>
/// <param name="shardingKeyConvert"></param>
/// <param name="keyToTailExpression"></param>
/// <returns></returns>
public static Func<string, bool> GetRouteDataSourceFilter<TKey>(IQueryable queryable, ShardingEntityConfig shardingEntityBaseType, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToTailExpression)
{
QueryableRouteShardingDataSourceDiscoverVisitor<TKey> visitor = new QueryableRouteShardingDataSourceDiscoverVisitor<TKey>(shardingEntityBaseType, shardingKeyConvert, keyToTailExpression);
visitor.Visit(queryable.Expression);
///// <summary>
///// ·Ö¿â·ÓɹýÂË
///// </summary>
///// <typeparam name="TKey"></typeparam>
///// <param name="queryable"></param>
///// <param name="entityMetadata"></param>
///// <param name="shardingKeyConvert"></param>
///// <param name="keyToTailExpression"></param>
///// <returns></returns>
//public static Func<string, bool> GetRouteDataSourceFilter<TKey>(IQueryable queryable, EntityMetadata entityMetadata, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToTailExpression)
//{
// QueryableRouteShardingDataSourceDiscoverVisitor<TKey> visitor = new QueryableRouteShardingDataSourceDiscoverVisitor<TKey>(entityMetadata, shardingKeyConvert, keyToTailExpression);
return visitor.GetDataSourceFilter();
}
// visitor.Visit(queryable.Expression);
// return visitor.GetDataSourceFilter();
//}
/// <summary>
/// 分表路由过滤
/// </summary>

View File

@ -15,7 +15,7 @@ namespace ShardingCore.VirtualRoutes.Abstractions
/// time type is date time
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> : AbstractShardingOperatorVirtualTableRoute<T, DateTime> where T : class, IShardingTable
public abstract class AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> : AbstractShardingOperatorVirtualTableRoute<T, DateTime> where T : class
{
/// <summary>
/// how convert object to date time

View File

@ -14,7 +14,7 @@ namespace ShardingCore.VirtualRoutes.Abstractions
/// sharding table route by time stamp (ms)
/// </summary>
/// <typeparam name="T">entity</typeparam>
public abstract class AbstractShardingTimeKeyLongVirtualTableRoute<T> : AbstractShardingOperatorVirtualTableRoute<T, long> where T : class, IShardingTable
public abstract class AbstractShardingTimeKeyLongVirtualTableRoute<T> : AbstractShardingOperatorVirtualTableRoute<T, long> where T : class
{
/// <summary>
/// how convert object to long

View File

@ -3,7 +3,14 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.TableCreator;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Days
@ -14,7 +21,7 @@ namespace ShardingCore.VirtualRoutes.Days
* @Date: Wednesday, 27 January 2021 08:41:05
* @Email: 326308290@qq.com
*/
public abstract class AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<T>:AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> where T:class,IShardingTable
public abstract class AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<T>:AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> where T:class
{
/// <summary>
/// begin time use fixed time eg.new DateTime(20xx,xx,xx)
@ -77,6 +84,58 @@ namespace ShardingCore.VirtualRoutes.Days
}
}
}
/// <summary>
/// 每天5点执行,启动的时候执行以下
/// </summary>
[JobRun(Name = "定时创建表", Cron = "0 0 5 * * ?", RunOnceOnStart = true)]
public virtual void AutoShardingTableCreate()
{
var virtualDataSource = (IVirtualDataSource)ShardingContainer.GetService(typeof(IVirtualDataSource<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var tableCreator = (IShardingTableCreator)ShardingContainer.GetService(typeof(IShardingTableCreator<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(1);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
try
{
tableCreator.CreateTable(virtualDataSource.DefaultDataSourceName, typeof(T), tail);
}
catch (Exception e)
{
//ignore
}
}
/// <summary>
/// 每天晚上23点59分执行
/// </summary>
[JobRun(Name = "定时添加虚拟表", Cron = "0 55 23 * * ?")]
public virtual void AutoShardingTableAdd()
{
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(1);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
}
public virtual string JobName =>
$"{EntityMetadata?.ShardingDbContextType?.Name}:{EntityMetadata?.EntityType?.Name}";
public virtual bool StartJob()
{
return false;
}
}
}

View File

@ -1,10 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.TableCreator;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Days
@ -15,7 +24,7 @@ namespace ShardingCore.VirtualRoutes.Days
* @Date: Wednesday, 27 January 2021 08:56:38
* @Email: 326308290@qq.com
*/
public abstract class AbstractSimpleShardingDayKeyLongVirtualTableRoute<T>:AbstractShardingTimeKeyLongVirtualTableRoute<T> where T:class,IShardingTable
public abstract class AbstractSimpleShardingDayKeyLongVirtualTableRoute<T>:AbstractShardingTimeKeyLongVirtualTableRoute<T>,IJob where T:class
{
public abstract DateTime GetBeginTime();
public override List<string> GetAllTails()
@ -72,5 +81,58 @@ namespace ShardingCore.VirtualRoutes.Days
}
}
}
/// <summary>
/// 每天5点执行,启动的时候执行以下
/// </summary>
[JobRun(Name = "定时创建表", Cron = "0 0 5 * * ?", RunOnceOnStart = true)]
public virtual void AutoShardingTableCreate()
{
var virtualDataSource = (IVirtualDataSource)ShardingContainer.GetService(typeof(IVirtualDataSource<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var tableCreator = (IShardingTableCreator)ShardingContainer.GetService(typeof(IShardingTableCreator<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(1);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
try
{
tableCreator.CreateTable(virtualDataSource.DefaultDataSourceName, typeof(T), tail);
}
catch (Exception e)
{
//ignore
}
}
/// <summary>
/// 每天晚上23点59分执行
/// </summary>
[JobRun(Name = "定时添加虚拟表", Cron = "0 55 23 * * ?")]
public virtual void AutoShardingTableAdd()
{
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(1);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
}
public virtual string JobName =>
$"{EntityMetadata?.ShardingDbContextType?.Name}:{EntityMetadata?.EntityType?.Name}";
public virtual bool StartJob()
{
return false;
}
}
}

View File

@ -19,7 +19,7 @@ namespace ShardingCore.VirtualRoutes.Mods
/// 分表字段为int的取模分表
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class AbstractSimpleShardingModKeyIntVirtualTableRoute<T>: AbstractShardingOperatorVirtualTableRoute<T,int> where T:class,IShardingTable
public abstract class AbstractSimpleShardingModKeyIntVirtualTableRoute<T>: AbstractShardingOperatorVirtualTableRoute<T,int> where T:class
{
protected readonly int Mod;
protected readonly int TailLength;

View File

@ -4,9 +4,16 @@ using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.TableCreator;
namespace ShardingCore.VirtualRoutes.Mods
{
@ -20,7 +27,7 @@ namespace ShardingCore.VirtualRoutes.Mods
/// 分表字段为string的取模分表
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class AbstractSimpleShardingModKeyStringVirtualTableRoute<T>: AbstractShardingOperatorVirtualTableRoute<T,string> where T:class,IShardingTable
public abstract class AbstractSimpleShardingModKeyStringVirtualTableRoute<T>: AbstractShardingOperatorVirtualTableRoute<T,string> where T:class
{
protected readonly int Mod;
protected readonly int TailLength;

View File

@ -3,8 +3,15 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.TableCreator;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Months
@ -15,7 +22,7 @@ namespace ShardingCore.VirtualRoutes.Months
* @Date: Wednesday, 27 January 2021 12:27:09
* @Email: 326308290@qq.com
*/
public abstract class AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<T> : AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> where T : class, IShardingTable
public abstract class AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<T> : AbstractShardingTimeKeyDateTimeVirtualTableRoute<T>,IJob where T : class
{
public abstract DateTime GetBeginTime();
public override List<string> GetAllTails()
@ -69,6 +76,61 @@ namespace ShardingCore.VirtualRoutes.Months
}
}
}
/// <summary>
/// 每个月20号5点会创建对应的表
/// </summary>
[JobRun(Name = "定时创建表", Cron = "0 0 5 20 * ?", RunOnceOnStart = true)]
public virtual void AutoShardingTableCreate()
{
var virtualDataSource = (IVirtualDataSource)ShardingContainer.GetService(typeof(IVirtualDataSource<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var tableCreator = (IShardingTableCreator)ShardingContainer.GetService(typeof(IShardingTableCreator<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(3);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
try
{
tableCreator.CreateTable(virtualDataSource.DefaultDataSourceName, typeof(T), tail);
}
catch (Exception e)
{
//ignore
}
}
/// <summary>
/// 每月最后一天需要程序自己判断是不是最后一天
/// </summary>
[JobRun(Name = "定时添加虚拟表", Cron = "0 55 23 28,29,30,31 * ?")]
public virtual void AutoShardingTableAdd()
{
var nowDateTime = DateTime.Now.Date;
var lastMonthDay = ShardingCoreHelper.GetNextMonthFirstDay(nowDateTime).AddDays(-1);
if (lastMonthDay.Date != nowDateTime)
return;
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(7);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
}
public virtual string JobName =>
$"{EntityMetadata?.ShardingDbContextType?.Name}:{EntityMetadata?.EntityType?.Name}";
public virtual bool StartJob()
{
return false;
}
}
}

View File

@ -3,8 +3,15 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.TableCreator;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Months
@ -15,7 +22,7 @@ namespace ShardingCore.VirtualRoutes.Months
* @Date: Wednesday, 27 January 2021 13:09:52
* @Email: 326308290@qq.com
*/
public abstract class AbstractSimpleShardingMonthKeyLongVirtualTableRoute<T>:AbstractShardingTimeKeyLongVirtualTableRoute<T> where T:class,IShardingTable
public abstract class AbstractSimpleShardingMonthKeyLongVirtualTableRoute<T>:AbstractShardingTimeKeyLongVirtualTableRoute<T>,IJob where T:class
{
public abstract DateTime GetBeginTime();
public override List<string> GetAllTails()
@ -72,6 +79,61 @@ namespace ShardingCore.VirtualRoutes.Months
}
}
}
/// <summary>
/// 每个月20号5点会创建对应的表
/// </summary>
[JobRun(Name = "定时创建表", Cron = "0 0 5 20 * ?", RunOnceOnStart = true)]
public virtual void AutoShardingTableCreate()
{
var virtualDataSource = (IVirtualDataSource)ShardingContainer.GetService(typeof(IVirtualDataSource<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var tableCreator = (IShardingTableCreator)ShardingContainer.GetService(typeof(IShardingTableCreator<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(3);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
try
{
tableCreator.CreateTable(virtualDataSource.DefaultDataSourceName, typeof(T), tail);
}
catch (Exception e)
{
//ignore
}
}
/// <summary>
/// 每月最后一天需要程序自己判断是不是最后一天
/// </summary>
[JobRun(Name = "定时添加虚拟表", Cron = "0 55 23 28,29,30,31 * ?")]
public virtual void AutoShardingTableAdd()
{
var nowDateTime = DateTime.Now.Date;
var lastMonthDay = ShardingCoreHelper.GetNextMonthFirstDay(nowDateTime).AddDays(-1);
if (lastMonthDay.Date != nowDateTime)
return;
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(7);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
}
public virtual string JobName =>
$"{EntityMetadata?.ShardingDbContextType?.Name}:{EntityMetadata?.EntityType?.Name}";
public virtual bool StartJob()
{
return false;
}
}
}

View File

@ -3,8 +3,15 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.TableCreator;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Weeks
@ -15,7 +22,7 @@ namespace ShardingCore.VirtualRoutes.Weeks
* @Date: Wednesday, 27 January 2021 12:40:27
* @Email: 326308290@qq.com
*/
public abstract class AbstractSimpleShardingWeekKeyDateTimeVirtualTableRoute<T> : AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> where T : class, IShardingTable
public abstract class AbstractSimpleShardingWeekKeyDateTimeVirtualTableRoute<T> : AbstractShardingTimeKeyDateTimeVirtualTableRoute<T>,IJob where T : class
{
public abstract DateTime GetBeginTime();
public override List<string> GetAllTails()
@ -71,6 +78,55 @@ namespace ShardingCore.VirtualRoutes.Weeks
}
}
}
/// <summary>
/// 每周五 5点
/// </summary>
[JobRun(Name = "定时创建表", Cron = "0 0 5 ? * 6", RunOnceOnStart = true)]
public virtual void AutoShardingTableCreate()
{
var virtualDataSource = (IVirtualDataSource)ShardingContainer.GetService(typeof(IVirtualDataSource<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var tableCreator = (IShardingTableCreator)ShardingContainer.GetService(typeof(IShardingTableCreator<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(3);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
try
{tableCreator.CreateTable(virtualDataSource.DefaultDataSourceName, typeof(T), tail);
}
catch (Exception e)
{
//ignore
}
}
/// <summary>
/// 每周末晚上23点55分添加数据
/// </summary>
[JobRun(Name = "定时添加虚拟表", Cron = "0 55 23 ? * 1")]
public virtual void AutoShardingTableAdd()
{
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(3);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
}
public virtual string JobName =>
$"{EntityMetadata?.ShardingDbContextType?.Name}:{EntityMetadata?.EntityType?.Name}";
public virtual bool StartJob()
{
return false;
}
}
}

View File

@ -3,8 +3,15 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.TableCreator;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Weeks
@ -15,7 +22,7 @@ namespace ShardingCore.VirtualRoutes.Weeks
* @Date: Wednesday, 27 January 2021 13:12:50
* @Email: 326308290@qq.com
*/
public abstract class AbstractSimpleShardingWeekKeyLongVirtualTableRoute<T> : AbstractShardingTimeKeyLongVirtualTableRoute<T> where T : class, IShardingTable
public abstract class AbstractSimpleShardingWeekKeyLongVirtualTableRoute<T> : AbstractShardingTimeKeyLongVirtualTableRoute<T>,IJob where T : class
{
public abstract DateTime GetBeginTime();
@ -75,5 +82,55 @@ namespace ShardingCore.VirtualRoutes.Weeks
}
}
}
/// <summary>
/// 每周五 5点
/// </summary>
[JobRun(Name = "定时创建表", Cron = "0 0 5 ? * 6", RunOnceOnStart = true)]
public virtual void AutoShardingTableCreate()
{
var virtualDataSource = (IVirtualDataSource)ShardingContainer.GetService(typeof(IVirtualDataSource<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var tableCreator = (IShardingTableCreator)ShardingContainer.GetService(typeof(IShardingTableCreator<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(3);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
try
{
tableCreator.CreateTable(virtualDataSource.DefaultDataSourceName, typeof(T), tail);
}
catch (Exception e)
{
//ignore
}
}
/// <summary>
/// 每周末晚上23点55分添加数据
/// </summary>
[JobRun(Name = "定时添加虚拟表", Cron = "0 55 23 ? * 1")]
public virtual void AutoShardingTableAdd()
{
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(3);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
}
public virtual string JobName =>
$"{EntityMetadata?.ShardingDbContextType?.Name}:{EntityMetadata?.EntityType?.Name}";
public virtual bool StartJob()
{
return false;
}
}
}

View File

@ -3,7 +3,14 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.TableCreator;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Years
@ -14,7 +21,7 @@ namespace ShardingCore.VirtualRoutes.Years
* @Date: Wednesday, 27 January 2021 13:00:57
* @Email: 326308290@qq.com
*/
public abstract class AbstractSimpleShardingYearKeyDateTimeVirtualTableRoute<T> : AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> where T : class, IShardingTable
public abstract class AbstractSimpleShardingYearKeyDateTimeVirtualTableRoute<T> : AbstractShardingTimeKeyDateTimeVirtualTableRoute<T>,IJob where T : class
{
public abstract DateTime GetBeginTime();
public override List<string> GetAllTails()
@ -67,5 +74,55 @@ namespace ShardingCore.VirtualRoutes.Years
}
}
}
/// <summary>
/// 每年12月20号自动创建表
/// </summary>
[JobRun(Name = "定时创建表", Cron = "0 0 5 20 12 ?", RunOnceOnStart = true)]
public virtual void AutoShardingTableCreate()
{
var virtualDataSource = (IVirtualDataSource)ShardingContainer.GetService(typeof(IVirtualDataSource<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var tableCreator = (IShardingTableCreator)ShardingContainer.GetService(typeof(IShardingTableCreator<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddMonths(1);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
try
{
tableCreator.CreateTable(virtualDataSource.DefaultDataSourceName, typeof(T), tail);
}
catch (Exception e)
{
//ignore
}
}
/// <summary>
/// 每年12月最后一天添加下一年的数据
/// </summary>
[JobRun(Name = "定时添加虚拟表", Cron = "0 55 23 31 12 ?")]
public virtual void AutoShardingTableAdd()
{
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(7);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
}
public virtual string JobName =>
$"{EntityMetadata?.ShardingDbContextType?.Name}:{EntityMetadata?.EntityType?.Name}";
public virtual bool StartJob()
{
return false;
}
}
}

View File

@ -3,8 +3,15 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Extensions;
using ShardingCore.Helpers;
using ShardingCore.Jobs.Abstaractions;
using ShardingCore.Jobs.Impls.Attributes;
using ShardingCore.TableCreator;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Years
@ -15,7 +22,7 @@ namespace ShardingCore.VirtualRoutes.Years
* @Date: Wednesday, 27 January 2021 13:17:24
* @Email: 326308290@qq.com
*/
public abstract class AbstractSimpleShardingYearKeyLongVirtualTableRoute<T> : AbstractShardingTimeKeyLongVirtualTableRoute<T> where T : class, IShardingTable
public abstract class AbstractSimpleShardingYearKeyLongVirtualTableRoute<T> : AbstractShardingTimeKeyLongVirtualTableRoute<T>,IJob where T : class
{
public abstract DateTime GetBeginTime();
public override List<string> GetAllTails()
@ -72,5 +79,56 @@ namespace ShardingCore.VirtualRoutes.Years
}
}
}
/// <summary>
/// 每年12月20号自动创建表
/// </summary>
[JobRun(Name = "定时创建表", Cron = "0 0 5 20 12 ?", RunOnceOnStart = true)]
public virtual void AutoShardingTableCreate()
{
var virtualDataSource = (IVirtualDataSource)ShardingContainer.GetService(typeof(IVirtualDataSource<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var tableCreator = (IShardingTableCreator)ShardingContainer.GetService(typeof(IShardingTableCreator<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddMonths(1);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
try
{
tableCreator.CreateTable(virtualDataSource.DefaultDataSourceName, typeof(T), tail);
}
catch (Exception e)
{
//ignore
}
}
/// <summary>
/// 每年12月最后一天添加下一年的数据
/// </summary>
[JobRun(Name = "定时添加虚拟表", Cron = "0 55 23 31 12 ?")]
public virtual void AutoShardingTableAdd()
{
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
var virtualTable = virtualTableManager.GetVirtualTable(typeof(T));
if (virtualTable == null)
{
return;
}
var now = DateTime.Now.Date.AddDays(7);
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
}
public virtual string JobName =>
$"{EntityMetadata?.ShardingDbContextType?.Name}:{EntityMetadata?.EntityType?.Name}";
public virtual bool StartJob()
{
return false;
}
}
}

View File

@ -13,7 +13,7 @@ namespace ShardingCore.Test50.MySql.Domain.Entities
/// <summary>
/// 用户Id用于分表
/// </summary>
[ShardingTableKey(TailPrefix = "_")]
[ShardingTableKey(TableSeparator = "_")]
public string Id { get; set; }
/// <summary>
/// 用户名称

View File

@ -13,7 +13,7 @@
// /// <summary>
// /// 分表分库range切分
// /// </summary>
// [ShardingKey(TailPrefix = "_",AutoCreateTableOnStart = true)]
// [ShardingKey(TableSeparator = "_",AutoCreateTableOnStart = true)]
// public string Id { get; set; }
// /// <summary>
// /// 姓名

View File

@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ShardingCore.Bootstrapers;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
using ShardingCore.Test50.MySql.Domain.Entities;

View File

@ -8,12 +8,13 @@ namespace ShardingCore.Test50.Domain.Entities
* @Date: Thursday, 14 January 2021 15:36:43
* @Email: 326308290@qq.com
*/
public class SysUserMod:IShardingTable
public class SysUserMod
//:IShardingTable
{
/// <summary>
/// 用户Id用于分表
/// </summary>
[ShardingTableKey(TailPrefix = "_")]
//[ShardingTableKey(TableSeparator = "_")]
public string Id { get; set; }
/// <summary>
/// 用户名称

View File

@ -1,3 +1,4 @@
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Test50.Domain.Entities;
using ShardingCore.VirtualRoutes.Mods;
@ -17,5 +18,10 @@ namespace ShardingCore.Test50.Shardings
{
}
public override void Configure(EntityMetadataTableBuilder<SysUserMod> builder)
{
builder.ShardingProperty(o => o.Id);
builder.TableSeparator("_");
}
}
}

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using ShardingCore.Bootstrapers;
#if EFCORE5SQLSERVER
using ShardingCore.SqlServer;

View File

@ -13,7 +13,7 @@ namespace ShardingCore.Test50_2x.Domain.Entities
/// <summary>
/// 用户Id用于分表
/// </summary>
[ShardingTableKey(TailPrefix = "_")]
[ShardingTableKey(TableSeparator = "_")]
public string Id { get; set; }
/// <summary>
/// 用户名称

View File

@ -8,6 +8,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ShardingCore.Bootstrapers;
using ShardingCore.EFCores;
using ShardingCore.Test50_2x.Domain.Entities;
using ShardingCore.Test50_2x.Shardings;

View File

@ -13,7 +13,7 @@ namespace ShardingCore.Test50_3x.Domain.Entities
/// <summary>
/// 用户Id用于分表
/// </summary>
[ShardingTableKey(TailPrefix = "_")]
[ShardingTableKey(TableSeparator = "_")]
public string Id { get; set; }
/// <summary>
/// 用户名称

View File

@ -7,6 +7,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ShardingCore.Bootstrapers;
using ShardingCore.Test50_3x.Domain.Entities;
using ShardingCore.Test50_3x.Shardings;