完成第一版本的多字段sharding [#82]
This commit is contained in:
parent
c03e679901
commit
167c44be53
|
@ -58,7 +58,6 @@ namespace ShardingCore6x
|
|||
{
|
||||
o.CreateShardingTableOnStart = true;
|
||||
o.EnsureCreatedWithOutShardingTable = true;
|
||||
o.AutoTrackEntity = false;
|
||||
}).AddShardingTransaction((connection, builder) => builder
|
||||
//.UseMySql(connection, new MySqlServerVersion(new Version()))
|
||||
.UseSqlServer(connection)
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace ShardingCore6x.ShardingDbContexts
|
|||
{
|
||||
internal class OrderVirtualTableRoute:AbstractSimpleShardingModKeyStringVirtualTableRoute<Order>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public OrderVirtualTableRoute() : base(2, 5)
|
||||
{
|
||||
|
|
|
@ -39,7 +39,6 @@ namespace ShardingCoreBenchmark5x
|
|||
{
|
||||
o.CreateShardingTableOnStart = true;
|
||||
o.EnsureCreatedWithOutShardingTable = true;
|
||||
o.AutoTrackEntity = false;
|
||||
}).AddShardingTransaction((connection, builder) => builder.UseSqlServer(connection))
|
||||
.AddDefaultDataSource("ds0", "Data Source=localhost;Initial Catalog=db2;Integrated Security=True;")
|
||||
.AddShardingTableRoute(op =>
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace Sample.BulkConsole
|
|||
{
|
||||
o.CreateShardingTableOnStart = true;
|
||||
o.EnsureCreatedWithOutShardingTable = true;
|
||||
o.AutoTrackEntity = true;
|
||||
})
|
||||
.AddShardingTransaction((connection, builder) =>
|
||||
builder.UseSqlServer(connection).UseLoggerFactory(efLogger))
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace Sample.Migrations
|
|||
{
|
||||
o.CreateShardingTableOnStart = false;
|
||||
o.EnsureCreatedWithOutShardingTable = false;
|
||||
o.AutoTrackEntity = true;
|
||||
})
|
||||
.AddShardingTransaction((connection, builder) =>
|
||||
builder.UseSqlServer(connection))
|
||||
|
|
|
@ -19,7 +19,6 @@ builder.Services.AddControllers();
|
|||
builder.Services.AddShardingDbContext<DefaultDbContext>((conStr, builder) => builder.UseSqlServer(conStr).UseLoggerFactory(efLogger))
|
||||
.Begin(o =>
|
||||
{
|
||||
o.AutoTrackEntity = true;
|
||||
o.CreateShardingTableOnStart = true;
|
||||
o.EnsureCreatedWithOutShardingTable = true;
|
||||
})
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace Sample.SqlServer.Shardings
|
|||
return $"{dateOfMonth:yyyyMM}";
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(int shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(int shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Sample.SqlServer.Shardings
|
|||
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = ShardingKeyToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace Sample.SqlServer
|
|||
{
|
||||
o.CreateShardingTableOnStart = true;
|
||||
o.EnsureCreatedWithOutShardingTable = true;
|
||||
o.AutoTrackEntity = true;
|
||||
o.MaxQueryConnectionsLimit = Environment.ProcessorCount;
|
||||
o.ConnectionMode = ConnectionModeEnum.SYSTEM_AUTO;
|
||||
//if SysTest entity not exists in db and db is exists
|
||||
|
|
|
@ -40,7 +40,6 @@ namespace Sample.SqlServerShardingAll
|
|||
builder.UseSqlServer(conStr).UseLoggerFactory(efLogger);
|
||||
}).Begin(op =>
|
||||
{
|
||||
op.AutoTrackEntity = true;
|
||||
//如果您使用code-first建议选择false
|
||||
op.CreateShardingTableOnStart = true;
|
||||
//如果您使用code-first建议修改为fsle
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace Sample.SqlServerShardingDataSource
|
|||
builder.UseSqlServer(conStr).UseLoggerFactory(efLogger);
|
||||
}).Begin(op =>
|
||||
{
|
||||
op.AutoTrackEntity = true;
|
||||
//如果您使用code-first建议选择false
|
||||
op.CreateShardingTableOnStart = true;
|
||||
//如果您使用code-first建议修改为false
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
|
||||
namespace Sample.SqlServerShardingTable.Common
|
||||
{
|
||||
public class IdHelper
|
||||
{
|
||||
private IdHelper(){}
|
||||
private static SnowflakeId _snowflakeId;
|
||||
|
||||
static IdHelper()
|
||||
{
|
||||
_snowflakeId = new SnowflakeId(1,3);
|
||||
}
|
||||
|
||||
public static long NextId()
|
||||
{
|
||||
return _snowflakeId.NextId();
|
||||
}
|
||||
|
||||
public static DateTime FromId(long id)
|
||||
{
|
||||
return SnowflakeId.AnalyzeIdToDateTime(id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Sample.SqlServerShardingTable.Common
|
||||
{/// <summary>
|
||||
/// 雪花ID
|
||||
/// Twitter_Snowflake
|
||||
/// SnowFlake的结构如下(每部分用-分开)
|
||||
/// 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
|
||||
/// 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
|
||||
/// 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)得到的值),
|
||||
/// 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
|
||||
/// 这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。
|
||||
/// 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
|
||||
/// 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
|
||||
/// 总共加起来刚好64位,为一个Long型。
|
||||
/// SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),
|
||||
/// 并且效率较高,经测试,SnowFlake单机每秒都能够产生出极限4,096,000个ID来
|
||||
/// </summary>
|
||||
public class SnowflakeId
|
||||
{
|
||||
|
||||
// 开始时间截 (new DateTime(2020, 1, 1).ToUniversalTime() - Jan1st1970).TotalMilliseconds
|
||||
private const long twepoch = 1577808000000L;
|
||||
|
||||
// 机器id所占的位数
|
||||
private const int workerIdBits = 5;
|
||||
|
||||
// 数据标识id所占的位数
|
||||
private const int datacenterIdBits = 5;
|
||||
|
||||
// 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
|
||||
private const long maxWorkerId = -1L ^ (-1L << workerIdBits);
|
||||
|
||||
// 支持的最大数据标识id,结果是31
|
||||
private const long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
|
||||
|
||||
// 序列在id中占的位数
|
||||
private const int sequenceBits = 12;
|
||||
|
||||
// 数据标识id向左移17位(12+5)
|
||||
private const int datacenterIdShift = sequenceBits + workerIdBits;
|
||||
|
||||
// 机器ID向左移12位
|
||||
private const int workerIdShift = sequenceBits;
|
||||
|
||||
|
||||
// 时间截向左移22位(5+5+12)
|
||||
private const int timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
||||
|
||||
// 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
|
||||
private const long sequenceMask = -1L ^ (-1L << sequenceBits);
|
||||
|
||||
// 数据中心ID(0~31)
|
||||
public long datacenterId { get; private set; }
|
||||
|
||||
// 工作机器ID(0~31)
|
||||
public long workerId { get; private set; }
|
||||
|
||||
// 毫秒内序列(0~4095)
|
||||
public long sequence { get; private set; }
|
||||
|
||||
// 上次生成ID的时间截
|
||||
public long lastTimestamp { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 雪花ID
|
||||
/// </summary>
|
||||
/// <param name="datacenterId">数据中心ID</param>
|
||||
/// <param name="workerId">工作机器ID</param>
|
||||
public SnowflakeId(long datacenterId, long workerId)
|
||||
{
|
||||
if (datacenterId > maxDatacenterId || datacenterId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("datacenter Id can't be greater than {0} or less than 0", maxDatacenterId));
|
||||
}
|
||||
if (workerId > maxWorkerId || workerId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0", maxWorkerId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
this.datacenterId = datacenterId;
|
||||
this.sequence = 0L;
|
||||
this.lastTimestamp = -1L;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得下一个ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public long NextId()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp();
|
||||
if (timestamp > lastTimestamp) //时间戳改变,毫秒内序列重置
|
||||
{
|
||||
sequence = 0L;
|
||||
}
|
||||
else if (timestamp == lastTimestamp) //如果是同一时间生成的,则进行毫秒内序列
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence == 0) //毫秒内序列溢出
|
||||
{
|
||||
timestamp = GetNextTimestamp(lastTimestamp); //阻塞到下一个毫秒,获得新的时间戳
|
||||
}
|
||||
}
|
||||
else //当前时间小于上一次ID生成的时间戳,证明系统时钟被回拨,此时需要做回拨处理
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence > 0)
|
||||
{
|
||||
timestamp = lastTimestamp; //停留在最后一次时间戳上,等待系统时间追上后即完全度过了时钟回拨问题。
|
||||
}
|
||||
else //毫秒内序列溢出
|
||||
{
|
||||
timestamp = lastTimestamp + 1; //直接进位到下一个毫秒
|
||||
}
|
||||
//throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", lastTimestamp - timestamp));
|
||||
}
|
||||
|
||||
lastTimestamp = timestamp; //上次生成ID的时间截
|
||||
|
||||
//移位并通过或运算拼到一起组成64位的ID
|
||||
var id = ((timestamp - twepoch) << timestampLeftShift)
|
||||
| (datacenterId << datacenterIdShift)
|
||||
| (workerId << workerIdShift)
|
||||
| sequence;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime AnalyzeIdToDateTime(long Id)
|
||||
{
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
return time.ToLocalTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string AnalyzeId(long Id)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
sb.Append(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss:fff"));
|
||||
|
||||
var datacenterId = (Id ^ (timestamp << timestampLeftShift)) >> datacenterIdShift;
|
||||
sb.Append("_" + datacenterId);
|
||||
|
||||
var workerId = (Id ^ ((timestamp << timestampLeftShift) | (datacenterId << datacenterIdShift))) >> workerIdShift;
|
||||
sb.Append("_" + workerId);
|
||||
|
||||
var sequence = Id & sequenceMask;
|
||||
sb.Append("_" + sequence);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 阻塞到下一个毫秒,直到获得新的时间戳
|
||||
/// </summary>
|
||||
/// <param name="lastTimestamp">上次生成ID的时间截</param>
|
||||
/// <returns>当前时间戳</returns>
|
||||
private static long GetNextTimestamp(long lastTimestamp)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp();
|
||||
while (timestamp <= lastTimestamp)
|
||||
{
|
||||
timestamp = GetCurrentTimestamp();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static long GetCurrentTimestamp()
|
||||
{
|
||||
return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
|
||||
}
|
||||
|
||||
private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Sample.SqlServerShardingTable.Common
|
||||
{/// <summary>
|
||||
/// 雪花ID
|
||||
/// Twitter_Snowflake
|
||||
/// SnowFlake的结构如下(每部分用-分开)
|
||||
/// 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
|
||||
/// 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
|
||||
/// 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)得到的值),
|
||||
/// 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
|
||||
/// 这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。
|
||||
/// 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
|
||||
/// 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
|
||||
/// 总共加起来刚好64位,为一个Long型。
|
||||
/// SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),
|
||||
/// 并且效率较高,经测试,SnowFlake单机每秒都能够产生出极限4,096,000个ID来
|
||||
/// </summary>
|
||||
public class SnowflakeIdMock
|
||||
{
|
||||
|
||||
// 开始时间截 (new DateTime(2020, 1, 1).ToUniversalTime() - Jan1st1970).TotalMilliseconds
|
||||
private const long twepoch = 1577808000000L;
|
||||
|
||||
// 机器id所占的位数
|
||||
private const int workerIdBits = 5;
|
||||
|
||||
// 数据标识id所占的位数
|
||||
private const int datacenterIdBits = 5;
|
||||
|
||||
// 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
|
||||
private const long maxWorkerId = -1L ^ (-1L << workerIdBits);
|
||||
|
||||
// 支持的最大数据标识id,结果是31
|
||||
private const long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
|
||||
|
||||
// 序列在id中占的位数
|
||||
private const int sequenceBits = 12;
|
||||
|
||||
// 数据标识id向左移17位(12+5)
|
||||
private const int datacenterIdShift = sequenceBits + workerIdBits;
|
||||
|
||||
// 机器ID向左移12位
|
||||
private const int workerIdShift = sequenceBits;
|
||||
|
||||
|
||||
// 时间截向左移22位(5+5+12)
|
||||
private const int timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
||||
|
||||
// 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
|
||||
private const long sequenceMask = -1L ^ (-1L << sequenceBits);
|
||||
|
||||
// 数据中心ID(0~31)
|
||||
public long datacenterId { get; private set; }
|
||||
|
||||
// 工作机器ID(0~31)
|
||||
public long workerId { get; private set; }
|
||||
|
||||
// 毫秒内序列(0~4095)
|
||||
public long sequence { get; private set; }
|
||||
|
||||
// 上次生成ID的时间截
|
||||
public long lastTimestamp { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 雪花ID
|
||||
/// </summary>
|
||||
/// <param name="datacenterId">数据中心ID</param>
|
||||
/// <param name="workerId">工作机器ID</param>
|
||||
public SnowflakeIdMock(long datacenterId, long workerId)
|
||||
{
|
||||
if (datacenterId > maxDatacenterId || datacenterId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("datacenter Id can't be greater than {0} or less than 0", maxDatacenterId));
|
||||
}
|
||||
if (workerId > maxWorkerId || workerId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0", maxWorkerId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
this.datacenterId = datacenterId;
|
||||
this.sequence = 0L;
|
||||
this.lastTimestamp = -1L;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得下一个ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public long NextId(DateTime utc)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp(utc);
|
||||
if (timestamp > lastTimestamp) //时间戳改变,毫秒内序列重置
|
||||
{
|
||||
sequence = 0L;
|
||||
}
|
||||
else if (timestamp == lastTimestamp) //如果是同一时间生成的,则进行毫秒内序列
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence == 0) //毫秒内序列溢出
|
||||
{
|
||||
timestamp = GetNextTimestamp(lastTimestamp, utc); //阻塞到下一个毫秒,获得新的时间戳
|
||||
}
|
||||
}
|
||||
else //当前时间小于上一次ID生成的时间戳,证明系统时钟被回拨,此时需要做回拨处理
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence > 0)
|
||||
{
|
||||
timestamp = lastTimestamp; //停留在最后一次时间戳上,等待系统时间追上后即完全度过了时钟回拨问题。
|
||||
}
|
||||
else //毫秒内序列溢出
|
||||
{
|
||||
timestamp = lastTimestamp + 1; //直接进位到下一个毫秒
|
||||
}
|
||||
//throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", lastTimestamp - timestamp));
|
||||
}
|
||||
|
||||
lastTimestamp = timestamp; //上次生成ID的时间截
|
||||
|
||||
//移位并通过或运算拼到一起组成64位的ID
|
||||
var id = ((timestamp - twepoch) << timestampLeftShift)
|
||||
| (datacenterId << datacenterIdShift)
|
||||
| (workerId << workerIdShift)
|
||||
| sequence;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime AnalyzeIdToDateTime(long Id)
|
||||
{
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
return time.ToLocalTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string AnalyzeId(long Id)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
sb.Append(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss:fff"));
|
||||
|
||||
var datacenterId = (Id ^ (timestamp << timestampLeftShift)) >> datacenterIdShift;
|
||||
sb.Append("_" + datacenterId);
|
||||
|
||||
var workerId = (Id ^ ((timestamp << timestampLeftShift) | (datacenterId << datacenterIdShift))) >> workerIdShift;
|
||||
sb.Append("_" + workerId);
|
||||
|
||||
var sequence = Id & sequenceMask;
|
||||
sb.Append("_" + sequence);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 阻塞到下一个毫秒,直到获得新的时间戳
|
||||
/// </summary>
|
||||
/// <param name="lastTimestamp">上次生成ID的时间截</param>
|
||||
/// <returns>当前时间戳</returns>
|
||||
private static long GetNextTimestamp(long lastTimestamp, DateTime utc)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp(utc);
|
||||
while (timestamp <= lastTimestamp)
|
||||
{
|
||||
timestamp = GetCurrentTimestamp(utc);
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static long GetCurrentTimestamp(DateTime utc)
|
||||
{
|
||||
return (long)(utc - Jan1st1970).TotalMilliseconds;
|
||||
}
|
||||
|
||||
private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
|
@ -34,6 +34,21 @@ namespace Sample.SqlServerShardingTable.Controllers
|
|||
sysUsers
|
||||
});
|
||||
}
|
||||
public async Task<IActionResult> Query2()
|
||||
{
|
||||
var multiOrder =await _myDbContext.Set<MultiShardingOrder>().Where(o=>o.Id== 232398109278351360).FirstOrDefaultAsync();
|
||||
var longs = new []{ 232398109278351360 , 255197859283087360 };
|
||||
var multiOrders = await _myDbContext.Set<MultiShardingOrder>().Where(o => longs.Contains(o.Id)).ToListAsync();
|
||||
var dateTime = new DateTime(2021, 11, 1);
|
||||
var multiOrder404 = await _myDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 250345338962063360&&o.CreateTime< dateTime).FirstOrDefaultAsync();
|
||||
return Ok(new
|
||||
{
|
||||
multiOrder,
|
||||
multiOrders,
|
||||
multiOrder404
|
||||
});
|
||||
|
||||
}
|
||||
public async Task<IActionResult> QueryJoin1()
|
||||
{
|
||||
var sql= from user in _myDbContext.Set<SysUser>().Where(o => o.Id == "1" || o.Id == "6")
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Sample.SqlServerShardingTable.Entities
|
||||
{
|
||||
public class MultiShardingOrder
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
}
|
|
@ -40,6 +40,13 @@ namespace Sample.SqlServerShardingTable
|
|||
entity.Property(o=>o.Name).IsRequired().IsUnicode(false).HasMaxLength(50);
|
||||
entity.ToTable(nameof(Setting));
|
||||
});
|
||||
modelBuilder.Entity<MultiShardingOrder>(entity =>
|
||||
{
|
||||
entity.HasKey(o => o.Id);
|
||||
entity.Property(o => o.Id).ValueGeneratedNever();
|
||||
entity.Property(o=>o.Name).IsRequired().IsUnicode(false).HasMaxLength(50);
|
||||
entity.ToTable(nameof(MultiShardingOrder));
|
||||
});
|
||||
}
|
||||
/// <summary>
|
||||
/// empty impl
|
||||
|
|
|
@ -38,11 +38,12 @@ namespace Sample.SqlServerShardingTable
|
|||
builder.UseSqlServer(conStr).UseLoggerFactory(efLogger);
|
||||
}).Begin(op =>
|
||||
{
|
||||
op.AutoTrackEntity = true;
|
||||
//如果您使用code-first建议选择false
|
||||
op.CreateShardingTableOnStart = true;
|
||||
//如果您使用code-first建议修改为fsle
|
||||
op.EnsureCreatedWithOutShardingTable = true;
|
||||
//当无法获取路由时会返回默认值而不是报错
|
||||
op.ThrowIfQueryRouteNotMatch = false;
|
||||
}).AddShardingTransaction((connection, builder) =>
|
||||
{
|
||||
builder.UseSqlServer(connection).UseLoggerFactory(efLogger);
|
||||
|
@ -52,6 +53,7 @@ namespace Sample.SqlServerShardingTable
|
|||
{
|
||||
op.AddShardingTableRoute<SysUserVirtualTableRoute>();
|
||||
op.AddShardingTableRoute<OrderVirtualTableRoute>();
|
||||
op.AddShardingTableRoute<MultiShardingOrderVirtualTableRoute>();
|
||||
}).End();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Sample.SqlServerShardingTable.Common;
|
||||
using Sample.SqlServerShardingTable.Entities;
|
||||
using ShardingCore.Bootstrapers;
|
||||
|
||||
|
@ -66,9 +67,88 @@ namespace Sample.SqlServerShardingTable
|
|||
};
|
||||
orders.Add(order);
|
||||
}
|
||||
|
||||
var multiShardingOrders = new List<MultiShardingOrder>(9);
|
||||
#region 添加多字段分表
|
||||
|
||||
{
|
||||
var now = new DateTime(2021, 10, 1, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 231765457240207360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 10, 2, 11, 3, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 232095129534607360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 10, 3, 7, 7, 7);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 232398109278351360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 11, 6, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 244811420401807360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 11, 21, 19, 43, 0);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 250345338962063360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 5, 5, 5, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 255197859283087360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 9, 19, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 256860816933007360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 19, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 260394098622607360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
myDbContext.AddRange(settings);
|
||||
myDbContext.AddRange(users);
|
||||
myDbContext.AddRange(orders);
|
||||
myDbContext.AddRange(multiShardingOrders);
|
||||
myDbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using Sample.SqlServerShardingTable.Common;
|
||||
using Sample.SqlServerShardingTable.Entities;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Helpers;
|
||||
using ShardingCore.VirtualRoutes.Months;
|
||||
|
||||
namespace Sample.SqlServerShardingTable.VirtualRoutes
|
||||
{
|
||||
public class MultiShardingOrderVirtualTableRoute:AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<MultiShardingOrder>
|
||||
{
|
||||
public override void Configure(EntityMetadataTableBuilder<MultiShardingOrder> builder)
|
||||
{
|
||||
builder.ShardingProperty(o => o.CreateTime);
|
||||
builder.ShardingExtraProperty(o => o.Id);
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetExtraRouteFilter(object shardingKey, ShardingOperatorEnum shardingOperator, string shardingPropertyName)
|
||||
{
|
||||
switch (shardingPropertyName)
|
||||
{
|
||||
case nameof(MultiShardingOrder.Id): return GetIdRouteFilter(shardingKey, shardingOperator);
|
||||
default: throw new NotImplementedException(shardingPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
private Expression<Func<string, bool>> GetIdRouteFilter(object shardingKey,
|
||||
ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
//解析雪花id 需要考虑异常情况,传入的可能不是雪花id那么可以随机查询一张表
|
||||
var analyzeIdToDateTime = SnowflakeId.AnalyzeIdToDateTime(Convert.ToInt64(shardingKey));
|
||||
//当前时间的tail
|
||||
var t = TimeFormatToTail(analyzeIdToDateTime);
|
||||
//因为是按月分表所以获取下个月的时间判断id是否是在灵界点创建的
|
||||
var nextMonthFirstDay = ShardingCoreHelper.GetNextMonthFirstDay(DateTime.Now);
|
||||
if (analyzeIdToDateTime.AddSeconds(10) > nextMonthFirstDay)
|
||||
{
|
||||
var nextT = TimeFormatToTail(nextMonthFirstDay);
|
||||
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t||tail== nextT;
|
||||
}
|
||||
}
|
||||
var currentMonthFirstDay = ShardingCoreHelper.GetCurrentMonthFirstDay(DateTime.Now);
|
||||
if (analyzeIdToDateTime.AddSeconds(-10) < currentMonthFirstDay)
|
||||
{
|
||||
//上个月tail
|
||||
var nextT = TimeFormatToTail(analyzeIdToDateTime.AddSeconds(-10));
|
||||
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t || tail == nextT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t;
|
||||
}
|
||||
}
|
||||
|
||||
return tail => true;
|
||||
}
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override DateTime GetBeginTime()
|
||||
{
|
||||
return new DateTime(2021, 9, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ namespace Sample.SqlServerShardingTable.VirtualRoutes
|
|||
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
//因为hash路由仅支持等于所以仅仅只需要写等于的情况
|
||||
var t = ShardingKeyToTail(shardingKey);
|
||||
|
|
|
@ -41,6 +41,18 @@ namespace ShardingCore.Core.EntityMetadatas
|
|||
_entityMetadata.SetShardingDataSourceProperty(propertyInfo);
|
||||
return this;
|
||||
}
|
||||
public EntityMetadataDataSourceBuilder<TEntity> ShardingExtraProperty<TProperty>(Expression<Func<TEntity, TProperty>> propertyExpression)
|
||||
{
|
||||
var propertyAccess = propertyExpression.GetPropertyAccess();
|
||||
_entityMetadata.AddExtraSharingDataSourceProperty(propertyAccess);
|
||||
return this;
|
||||
}
|
||||
public EntityMetadataDataSourceBuilder<TEntity> ShardingExtraProperty(string propertyName)
|
||||
{
|
||||
var propertyInfo = typeof(TEntity).GetProperty(propertyName);
|
||||
_entityMetadata.AddExtraSharingDataSourceProperty(propertyInfo);
|
||||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否启动建表
|
||||
/// </summary>
|
||||
|
|
|
@ -38,6 +38,18 @@ namespace ShardingCore.Core.EntityMetadatas
|
|||
_entityMetadata.SetShardingTableProperty(propertyInfo);
|
||||
return this;
|
||||
}
|
||||
public EntityMetadataTableBuilder<TEntity> ShardingExtraProperty<TProperty>(Expression<Func<TEntity, TProperty>> propertyExpression)
|
||||
{
|
||||
var propertyAccess = propertyExpression.GetPropertyAccess();
|
||||
_entityMetadata.AddExtraSharingTableProperty(propertyAccess);
|
||||
return this;
|
||||
}
|
||||
public EntityMetadataTableBuilder<TEntity> ShardingExtraProperty(string propertyName)
|
||||
{
|
||||
var propertyInfo = typeof(TEntity).GetProperty(propertyName);
|
||||
_entityMetadata.AddExtraSharingTableProperty(propertyInfo);
|
||||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// 分表表和后缀连接器
|
||||
/// </summary>
|
||||
|
|
|
@ -16,13 +16,8 @@ namespace ShardingCore.Core.TrackerManagers
|
|||
*/
|
||||
public class TrackerManager<TShardingDbContext>: ITrackerManager<TShardingDbContext> where TShardingDbContext : DbContext, IShardingDbContext
|
||||
{
|
||||
private readonly IShardingConfigOption<TShardingDbContext> _shardingConfigOption;
|
||||
private readonly ISet<Type> _dbContextModels = new HashSet<Type>();
|
||||
|
||||
public TrackerManager(IShardingConfigOption<TShardingDbContext> shardingConfigOption)
|
||||
{
|
||||
_shardingConfigOption = shardingConfigOption;
|
||||
}
|
||||
public bool AddDbContextModel(Type entityType)
|
||||
{
|
||||
return _dbContextModels.Add(entityType);
|
||||
|
@ -30,8 +25,6 @@ namespace ShardingCore.Core.TrackerManagers
|
|||
|
||||
public bool EntityUseTrack(Type entityType)
|
||||
{
|
||||
if (!_shardingConfigOption.AutoTrackEntity)
|
||||
return false;
|
||||
return _dbContextModels.Contains(entityType);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
|
|||
public abstract class AbstractShardingRouteParseCompileCacheVirtualDataSourceRoute<TEntity, TKey> : AbstractShardingFilterVirtualDataSourceRoute<TEntity, TKey> where TEntity : class
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Expression<Func<string, bool>>, Func<string, bool>> _routeCompileCaches = new(new ExtensionExpressionComparer.RouteParseExpressionEqualityComparer());
|
||||
|
||||
static AbstractShardingRouteParseCompileCacheVirtualDataSourceRoute()
|
||||
{
|
||||
Expression<Func<string, bool>> defaultWhere1 = x => true;
|
||||
|
@ -30,7 +29,14 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
|
|||
/// <summary>
|
||||
/// 是否启用路由解析编译缓存
|
||||
/// </summary>
|
||||
public virtual bool EnableRouteParseCompileCache => false;
|
||||
public virtual bool? EnableRouteParseCompileCache => null;
|
||||
|
||||
public virtual bool EnableCompileCache()
|
||||
{
|
||||
if (EnableRouteParseCompileCache.HasValue)
|
||||
return EnableRouteParseCompileCache.Value;
|
||||
return ShardingConfigOption.EnableDataSourceRouteCompileCache.GetValueOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对表达式进行缓存编译默认永久缓存单个参数表达式,且不包含orElse只包含单个AndAlso或者没有AndAlso的,
|
||||
|
@ -41,7 +47,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
|
|||
/// <returns></returns>
|
||||
public virtual Func<string, bool> CachingCompile(Expression<Func<string, bool>> parseWhere)
|
||||
{
|
||||
if (EnableRouteParseCompileCache)
|
||||
if (EnableCompileCache())
|
||||
{
|
||||
var doCachingCompile = DoCachingCompile(parseWhere);
|
||||
if (doCachingCompile != null)
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
|
|||
{
|
||||
public EntityMetadata EntityMetadata { get; private set; }
|
||||
private readonly DoOnlyOnce _doOnlyOnce = new DoOnlyOnce();
|
||||
public IShardingConfigOption ShardingConfigOption { get; private set; }
|
||||
|
||||
|
||||
public void Initialize(EntityMetadata entityMetadata)
|
||||
|
@ -34,6 +35,9 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
|
|||
paginationConfiguration.Configure(paginationBuilder);
|
||||
}
|
||||
|
||||
ShardingConfigOption =
|
||||
ShardingContainer.GetRequiredShardingConfigOption(entityMetadata.ShardingDbContextType);
|
||||
|
||||
}
|
||||
public virtual IPaginationConfiguration<T> CreatePaginationConfiguration()
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
|
|||
protected override List<IPhysicTable> DoRouteWithPredicate(List<IPhysicTable> allPhysicTables, IQueryable queryable)
|
||||
{
|
||||
//获取路由后缀表达式
|
||||
var routeParseExpression = ShardingUtil.GetRouteParseExpression(queryable, EntityMetadata, GetRouteToFilter,true);
|
||||
var routeParseExpression = ShardingUtil.GetRouteParseExpression(queryable, EntityMetadata, GetRouteFilter,true);
|
||||
//表达式缓存编译
|
||||
var filter =CachingCompile(routeParseExpression);
|
||||
//通过编译结果进行过滤
|
||||
|
@ -37,12 +37,12 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
|
|||
/// <param name="shardingOperator">操作</param>
|
||||
/// <param name="shardingPropertyName">分表字段</param>
|
||||
/// <returns>如果返回true表示返回该表 第一个参数 tail 第二参数是否返回该物理表</returns>
|
||||
public Expression<Func<string, bool>> GetRouteToFilter(object shardingKey,
|
||||
public Expression<Func<string, bool>> GetRouteFilter(object shardingKey,
|
||||
ShardingOperatorEnum shardingOperator, string shardingPropertyName)
|
||||
{
|
||||
if (EntityMetadata.IsMainShardingTableKey(shardingPropertyName))
|
||||
{
|
||||
return GetMainRouteFilter((TKey)shardingKey, shardingOperator);
|
||||
return GetRouteToFilter((TKey)shardingKey, shardingOperator);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
|
|||
}
|
||||
}
|
||||
|
||||
public abstract Expression<Func<string, bool>> GetMainRouteFilter(TKey shardingKey,
|
||||
public abstract Expression<Func<string, bool>> GetRouteToFilter(TKey shardingKey,
|
||||
ShardingOperatorEnum shardingOperator);
|
||||
|
||||
public virtual Expression<Func<string, bool>> GetExtraRouteFilter(object shardingKey,
|
||||
|
|
|
@ -32,7 +32,13 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
|
|||
/// <summary>
|
||||
/// 是否启用路由解析编译缓存
|
||||
/// </summary>
|
||||
public virtual bool EnableRouteParseCompileCache => false;
|
||||
public virtual bool? EnableRouteParseCompileCache => null;
|
||||
public virtual bool EnableCompileCache()
|
||||
{
|
||||
if (EnableRouteParseCompileCache.HasValue)
|
||||
return EnableRouteParseCompileCache.Value;
|
||||
return ShardingConfigOption.EnableTableRouteCompileCache.GetValueOrDefault();
|
||||
}
|
||||
/// <summary>
|
||||
/// 对表达式进行缓存编译默认永久缓存单个参数表达式,且不包含orElse只包含单个AndAlso或者没有AndAlso的,
|
||||
/// 比如:<![CDATA[o.id==x]]>或者<![CDATA[o.id>x]]>,不会缓存<![CDATA[o=>id>x && o.id<y ]]>等一共大于、等于、小于、大于等于、小于等于(不等于编译成<![CDATA[t=>true]]>)缓存会存在的数量个数上限为
|
||||
|
@ -42,7 +48,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
|
|||
/// <returns></returns>
|
||||
public virtual Func<string, bool> CachingCompile(Expression<Func<string, bool>> parseWhere)
|
||||
{
|
||||
if (EnableRouteParseCompileCache)
|
||||
if (EnableCompileCache())
|
||||
{
|
||||
var doCachingCompile = DoCachingCompile(parseWhere);
|
||||
if (doCachingCompile != null)
|
||||
|
|
|
@ -22,11 +22,14 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
|
|||
{
|
||||
|
||||
private readonly DoOnlyOnce _doOnlyOnce = new DoOnlyOnce();
|
||||
public IShardingConfigOption ShardingConfigOption { get; private set; }
|
||||
public virtual void Initialize(EntityMetadata entityMetadata)
|
||||
{
|
||||
if (!_doOnlyOnce.IsUnDo())
|
||||
throw new ShardingCoreInvalidOperationException("already init");
|
||||
EntityMetadata = entityMetadata;
|
||||
ShardingConfigOption =
|
||||
ShardingContainer.GetRequiredShardingConfigOption(entityMetadata.ShardingDbContextType);
|
||||
}
|
||||
public virtual IPaginationConfiguration<T> CreatePaginationConfiguration()
|
||||
{
|
||||
|
|
|
@ -43,11 +43,15 @@ namespace ShardingCore.DIExtensions
|
|||
throw new ArgumentException(
|
||||
$"{nameof(shardingCoreBeginOptions.MaxQueryConnectionsLimit)} should greater than and equal 1");
|
||||
ShardingConfigOption.EnsureCreatedWithOutShardingTable = shardingCoreBeginOptions.EnsureCreatedWithOutShardingTable;
|
||||
ShardingConfigOption.AutoTrackEntity = shardingCoreBeginOptions.AutoTrackEntity;
|
||||
//ShardingConfigOption.AutoTrackEntity = shardingCoreBeginOptions.AutoTrackEntity;
|
||||
ShardingConfigOption.CreateShardingTableOnStart = shardingCoreBeginOptions.CreateShardingTableOnStart;
|
||||
ShardingConfigOption.IgnoreCreateTableError = shardingCoreBeginOptions.IgnoreCreateTableError;
|
||||
ShardingConfigOption.MaxQueryConnectionsLimit = shardingCoreBeginOptions.MaxQueryConnectionsLimit;
|
||||
ShardingConfigOption.ConnectionMode = shardingCoreBeginOptions.ConnectionMode;
|
||||
ShardingConfigOption.ThrowIfQueryRouteNotMatch = shardingCoreBeginOptions.ThrowIfQueryRouteNotMatch;
|
||||
ShardingConfigOption.EnableTableRouteCompileCache = shardingCoreBeginOptions.EnableTableRouteCompileCache;
|
||||
ShardingConfigOption.EnableDataSourceRouteCompileCache = shardingCoreBeginOptions.EnableDataSourceRouteCompileCache;
|
||||
|
||||
foreach (var entityType in shardingCoreBeginOptions.GetCreateTableEntities())
|
||||
{
|
||||
ShardingConfigOption.AddEntityTryCreateTable(entityType);
|
||||
|
@ -89,13 +93,17 @@ namespace ShardingCore.DIExtensions
|
|||
/// 是否需要在启动时创建分表
|
||||
/// </summary>
|
||||
public bool? CreateShardingTableOnStart { get; set; }
|
||||
///// <summary>
|
||||
///// 是否自动追踪实体
|
||||
///// 譬如本次查询涉及到a1,a2,a3这三张表,会创建3个dbcontext进行查询,如果AutoTrackEntity=false那么针对被创建的dbcontext不会有任何变化,还是以追踪的形式查询
|
||||
///// 因为会同时创建3个dbcontext所以针对跨表查询完成后dbcontext会被回收,但是查询还是按原先的行为查询,所以如果不启用建议在查询的时候使用notracking
|
||||
///// 如果AutoTrackEntity=true,那么被创建的三个dbcontext还是以原先的表现行为进行查询,在查询完成后会再次各自创建对应的dbcontext进行对象的追踪
|
||||
///// </summary>
|
||||
//public bool AutoTrackEntity { get; set; }
|
||||
/// <summary>
|
||||
/// 是否自动追踪实体
|
||||
/// 譬如本次查询涉及到a1,a2,a3这三张表,会创建3个dbcontext进行查询,如果AutoTrackEntity=false那么针对被创建的dbcontext不会有任何变化,还是以追踪的形式查询
|
||||
/// 因为会同时创建3个dbcontext所以针对跨表查询完成后dbcontext会被回收,但是查询还是按原先的行为查询,所以如果不启用建议在查询的时候使用notracking
|
||||
/// 如果AutoTrackEntity=true,那么被创建的三个dbcontext还是以原先的表现行为进行查询,在查询完成后会再次各自创建对应的dbcontext进行对象的追踪
|
||||
/// 当查询遇到没有路由被命中时是否抛出错误
|
||||
/// </summary>
|
||||
public bool AutoTrackEntity { get; set; }
|
||||
public bool ThrowIfQueryRouteNotMatch { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 忽略建表时的错误
|
||||
|
@ -103,9 +111,7 @@ namespace ShardingCore.DIExtensions
|
|||
public bool? IgnoreCreateTableError { get; set; } = true;
|
||||
public int MaxQueryConnectionsLimit { get; set; } = Environment.ProcessorCount;
|
||||
public ConnectionModeEnum ConnectionMode { get; set; } = ConnectionModeEnum.SYSTEM_AUTO;
|
||||
[Obsolete]
|
||||
public bool? EnableTableRouteCompileCache { get; set; }
|
||||
[Obsolete]
|
||||
public bool? EnableDataSourceRouteCompileCache { get; set; }
|
||||
|
||||
private readonly ISet<Type> _createTableEntities = new HashSet<Type>();
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ShardingCoreDataSourceQueryRouteNotMatchException : ShardingCoreQueryRouteNotMatchException
|
||||
{
|
||||
public ShardingCoreDataSourceQueryRouteNotMatchException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingCoreDataSourceQueryRouteNotMatchException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ShardingCoreQueryRouteNotMatchException : ShardingCoreException
|
||||
{
|
||||
public ShardingCoreQueryRouteNotMatchException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingCoreQueryRouteNotMatchException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ShardingCoreTableQueryRouteNotMatchException : ShardingCoreQueryRouteNotMatchException
|
||||
{
|
||||
public ShardingCoreTableQueryRouteNotMatchException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingCoreTableQueryRouteNotMatchException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,10 +58,10 @@ namespace ShardingCore
|
|||
/// </summary>
|
||||
public bool? IgnoreCreateTableError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自动追踪实体
|
||||
/// </summary>
|
||||
public bool AutoTrackEntity { get; set; }
|
||||
///// <summary>
|
||||
///// 自动追踪实体
|
||||
///// </summary>
|
||||
//public bool AutoTrackEntity { get; set; }
|
||||
/// <summary>
|
||||
/// 默认数据源名称
|
||||
/// </summary>
|
||||
|
@ -78,18 +78,22 @@ namespace ShardingCore
|
|||
/// 连接数限制
|
||||
/// </summary>
|
||||
public ConnectionModeEnum ConnectionMode { get; set; }
|
||||
/// <summary>
|
||||
/// 当查询遇到没有路由被命中时是否抛出错误
|
||||
/// </summary>
|
||||
public bool ThrowIfQueryRouteNotMatch { get; set; }
|
||||
|
||||
public bool AddParallelTableGroupNode(ParallelTableGroupNode parallelTableGroupNode);
|
||||
|
||||
public ISet<ParallelTableGroupNode> GetParallelTableGroupNodes();
|
||||
///// <summary>
|
||||
///// 是否启用表路由编译缓存
|
||||
///// </summary>
|
||||
//public bool? EnableTableRouteCompileCache { get; set; }
|
||||
///// <summary>
|
||||
///// 是否启用分库路由编译缓存
|
||||
///// </summary>
|
||||
//public bool? EnableDataSourceRouteCompileCache { get; set; }
|
||||
/// <summary>
|
||||
/// 是否启用表路由编译缓存
|
||||
/// </summary>
|
||||
public bool? EnableTableRouteCompileCache { get; set; }
|
||||
/// <summary>
|
||||
/// 是否启用分库路由编译缓存
|
||||
/// </summary>
|
||||
public bool? EnableDataSourceRouteCompileCache { get; set; }
|
||||
}
|
||||
|
||||
public interface IShardingConfigOption<TShardingDbContext>: IShardingConfigOption where TShardingDbContext : DbContext, IShardingDbContext
|
||||
|
|
|
@ -44,8 +44,11 @@ namespace ShardingCore.Sharding.MergeEngines.Abstractions.InMemoryMerge
|
|||
|
||||
public async Task<List<RouteQueryResult<TResult>>> ExecuteAsync<TResult>(Func<IQueryable, Task<TResult>> efQuery, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
var routeQueryResults = _mergeContext.PreperExecute(() => new List<RouteQueryResult<TResult>>(0));
|
||||
if (routeQueryResults != null)
|
||||
return routeQueryResults;
|
||||
var defaultSqlRouteUnits = GetDefaultSqlRouteUnits();
|
||||
var waitExecuteQueue = GetDataSourceGroupAndExecutorGroup<RouteQueryResult<TResult>>(true,defaultSqlRouteUnits,
|
||||
var waitExecuteQueue = GetDataSourceGroupAndExecutorGroup<RouteQueryResult<TResult>>(true, defaultSqlRouteUnits,
|
||||
async sqlExecutorUnit =>
|
||||
{
|
||||
var connectionMode = _mergeContext.RealConnectionMode(sqlExecutorUnit.ConnectionMode);
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Threading;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using ShardingCore.Sharding.Enumerators.TrackerEnumerators;
|
||||
using ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines.EnumeratorAsync;
|
||||
using ShardingCore.Sharding.ShardingQueryExecutors;
|
||||
|
||||
/*
|
||||
|
@ -29,6 +30,9 @@ namespace ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines
|
|||
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var emptyQueryEnumerator = _mergeContext.PreperExecute(() => new EmptyQueryEnumerator<T>());
|
||||
if (emptyQueryEnumerator != null)
|
||||
return emptyQueryEnumerator;
|
||||
var asyncEnumerator = EnumeratorStreamMergeEngineFactory<TShardingDbContext,T>.Create(_mergeContext).GetMergeEngine()
|
||||
.GetAsyncEnumerator(cancellationToken);
|
||||
|
||||
|
@ -44,6 +48,9 @@ namespace ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines
|
|||
#if EFCORE2
|
||||
IAsyncEnumerator<T> IAsyncEnumerable<T>.GetEnumerator()
|
||||
{
|
||||
var emptyQueryEnumerator = _mergeContext.PreperExecute(() => new EmptyQueryEnumerator<T>());
|
||||
if (emptyQueryEnumerator != null)
|
||||
return emptyQueryEnumerator;
|
||||
var asyncEnumerator = ((IAsyncEnumerable<T>)EnumeratorStreamMergeEngineFactory<TShardingDbContext,T>.Create(_mergeContext).GetMergeEngine())
|
||||
.GetEnumerator();
|
||||
if (_mergeContext.IsUseShardingTrack(typeof(T)))
|
||||
|
@ -57,6 +64,9 @@ namespace ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines
|
|||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
var emptyQueryEnumerator = _mergeContext.PreperExecute(() => new EmptyQueryEnumerator<T>());
|
||||
if (emptyQueryEnumerator != null)
|
||||
return emptyQueryEnumerator;
|
||||
var enumerator = ((IEnumerable<T>)EnumeratorStreamMergeEngineFactory<TShardingDbContext,T>.Create(_mergeContext).GetMergeEngine())
|
||||
.GetEnumerator();
|
||||
|
||||
|
|
|
@ -52,16 +52,17 @@ namespace ShardingCore.Sharding.ShardingExecutors
|
|||
|
||||
private IEnumerable<TableRouteResult> GetTableRouteResults(IEnumerable<TableRouteResult> tableRouteResults)
|
||||
{
|
||||
if (_queryCompilerContext.GetQueryEntities().Count > 1)
|
||||
var routeResults = tableRouteResults as TableRouteResult[] ?? tableRouteResults.ToArray();
|
||||
if (_queryCompilerContext.GetQueryEntities().Count > 1&& routeResults.Length>0)
|
||||
{
|
||||
var entityMetadataManager = _queryCompilerContext.GetEntityMetadataManager();
|
||||
var queryShardingTables = _queryCompilerContext.GetQueryEntities().Where(o => entityMetadataManager.IsShardingTable(o)).ToArray();
|
||||
if (queryShardingTables.Length > 1 && _parallelTableManager.IsParallelTableQuery(queryShardingTables))
|
||||
{
|
||||
return tableRouteResults.Where(o => o.ReplaceTables.Select(p => p.Tail).ToHashSet().Count == 1);
|
||||
return routeResults.Where(o => o.ReplaceTables.Select(p => p.Tail).ToHashSet().Count == 1);
|
||||
}
|
||||
}
|
||||
return tableRouteResults;
|
||||
return routeResults;
|
||||
}
|
||||
|
||||
public static MergeQueryCompilerContext Create(IQueryCompilerContext queryCompilerContext, QueryCombineResult queryCombineResult, DataSourceRouteResult dataSourceRouteResult,IEnumerable<TableRouteResult> tableRouteResults)
|
||||
|
@ -101,12 +102,19 @@ namespace ShardingCore.Sharding.ShardingExecutors
|
|||
{
|
||||
if (!hasQueryCompilerExecutor.HasValue)
|
||||
{
|
||||
hasQueryCompilerExecutor = !IsMergeQuery();
|
||||
if (hasQueryCompilerExecutor.Value)
|
||||
if (_dataSourceRouteResult.IntersectDataSources.IsEmpty() || _tableRouteResults.IsEmpty())
|
||||
{
|
||||
var routeTailFactory = ShardingContainer.GetService<IRouteTailFactory>();
|
||||
var dbContext = GetShardingDbContext().GetDbContext(_dataSourceRouteResult.IntersectDataSources.First(), CurrentQueryReadConnection(), routeTailFactory.Create(_tableRouteResults.First()));
|
||||
_queryCompilerExecutor = new QueryCompilerExecutor(dbContext, GetQueryExpression());
|
||||
hasQueryCompilerExecutor = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasQueryCompilerExecutor = !IsMergeQuery();
|
||||
if (hasQueryCompilerExecutor.Value)
|
||||
{
|
||||
var routeTailFactory = ShardingContainer.GetService<IRouteTailFactory>();
|
||||
var dbContext = GetShardingDbContext().GetDbContext(_dataSourceRouteResult.IntersectDataSources.First(), CurrentQueryReadConnection(), routeTailFactory.Create(_tableRouteResults.First()));
|
||||
_queryCompilerExecutor = new QueryCompilerExecutor(dbContext, GetQueryExpression());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,9 @@ namespace ShardingCore.Sharding.ShardingExecutors
|
|||
var queryCombineResult = queryableCombine.Combine(queryCompilerContext);
|
||||
var dataSourceRouteResult = dataSourceRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable());
|
||||
var tableRouteResults = tableRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable());
|
||||
var routeResults = tableRouteResults as TableRouteResult[] ?? tableRouteResults.ToArray();
|
||||
var mergeCombineCompilerContext = MergeQueryCompilerContext.Create(queryCompilerContext, queryCombineResult, dataSourceRouteResult,
|
||||
tableRouteResults);
|
||||
routeResults);
|
||||
return mergeCombineCompilerContext;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ using System.Collections.Concurrent;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Sharding.StreamMergeEngines;
|
||||
|
||||
|
||||
namespace ShardingCore.Sharding
|
||||
|
@ -233,7 +235,7 @@ namespace ShardingCore.Sharding
|
|||
/// <returns></returns>
|
||||
public bool IsParallelQuery()
|
||||
{
|
||||
return !_shardingConfigOption.AutoTrackEntity || MergeQueryCompilerContext.IsCrossTable() || MergeQueryCompilerContext.CurrentQueryReadConnection();
|
||||
return MergeQueryCompilerContext.IsCrossTable() || MergeQueryCompilerContext.CurrentQueryReadConnection();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -266,6 +268,49 @@ namespace ShardingCore.Sharding
|
|||
{
|
||||
return _shardingComparer;
|
||||
}
|
||||
|
||||
public TResult PreperExecute<TResult>(Func<TResult> emptyFunc)
|
||||
{
|
||||
|
||||
if (IsRouteNotMatch())
|
||||
{
|
||||
if (ThrowIfQueryRouteNotMatch())
|
||||
{
|
||||
if (IsDataSourceRouteNotMatch())
|
||||
{
|
||||
throw new ShardingCoreDataSourceQueryRouteNotMatchException(MergeQueryCompilerContext.GetQueryExpression().ShardingPrint());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ShardingCoreTableQueryRouteNotMatchException(MergeQueryCompilerContext.GetQueryExpression().ShardingPrint());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return emptyFunc();
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
/// <summary>
|
||||
/// 无路由匹配
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool IsRouteNotMatch()
|
||||
{
|
||||
return DataSourceRouteResult.IntersectDataSources.IsEmpty() || TableRouteResults.IsEmpty();
|
||||
}
|
||||
|
||||
private bool IsDataSourceRouteNotMatch()
|
||||
{
|
||||
return DataSourceRouteResult.IntersectDataSources.IsEmpty();
|
||||
}
|
||||
|
||||
private bool ThrowIfQueryRouteNotMatch()
|
||||
{
|
||||
return _shardingConfigOption.ThrowIfQueryRouteNotMatch;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var dbContext in _parallelDbContexts.Keys)
|
||||
|
|
|
@ -232,15 +232,21 @@ namespace ShardingCore
|
|||
/// 忽略建表时的错误
|
||||
/// </summary>
|
||||
public bool? IgnoreCreateTableError { get; set; } = true;
|
||||
/// <summary>
|
||||
/// 自动追踪实体
|
||||
/// </summary>
|
||||
public bool AutoTrackEntity { get; set; }
|
||||
///// <summary>
|
||||
///// 自动追踪实体
|
||||
///// </summary>
|
||||
//public bool AutoTrackEntity { get; set; }
|
||||
|
||||
public string DefaultDataSourceName { get; set; }
|
||||
public string DefaultConnectionString { get; set; }
|
||||
public int MaxQueryConnectionsLimit { get; set; } = Environment.ProcessorCount;
|
||||
public ConnectionModeEnum ConnectionMode { get; set; } = ConnectionModeEnum.SYSTEM_AUTO;
|
||||
/// <summary>
|
||||
/// 当查询遇到没有路由被命中时是否抛出错误
|
||||
/// </summary>
|
||||
public bool ThrowIfQueryRouteNotMatch { get; set; } = true;
|
||||
public bool? EnableTableRouteCompileCache { get; set; }
|
||||
public bool? EnableDataSourceRouteCompileCache { get; set; }
|
||||
|
||||
|
||||
public bool AddParallelTableGroupNode(ParallelTableGroupNode parallelTableGroupNode)
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace ShardingCore.VirtualRoutes.Abstractions
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract string[] GetCronExpressions();
|
||||
public Task ExecuteAsync()
|
||||
public virtual Task ExecuteAsync()
|
||||
{
|
||||
var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(EntityMetadata.ShardingDbContextType));
|
||||
var virtualTable = virtualTableManager.GetVirtualTable(typeof(TEntity));
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace ShardingCore.VirtualRoutes.Days
|
|||
return $"{time:yyyyMMdd}";
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace ShardingCore.VirtualRoutes.Days
|
|||
return $"{dateTime:yyyyMMdd}";
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(long shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(long shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace ShardingCore.VirtualRoutes.Mods
|
|||
return Enumerable.Range(0, Mod).Select(o => o.ToString().PadLeft(TailLength, PaddingChar)).ToList();
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(int shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(int shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
|
||||
var t = ShardingKeyToTail(shardingKey);
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace ShardingCore.VirtualRoutes.Mods
|
|||
/// <param name="shardingKey"></param>
|
||||
/// <param name="shardingOperator"></param>
|
||||
/// <returns></returns>
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = ShardingKeyToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace ShardingCore.VirtualRoutes.Months
|
|||
return $"{time:yyyyMM}";
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace ShardingCore.VirtualRoutes.Months
|
|||
var datetime = ShardingCoreHelper.ConvertLongToDateTime(time);
|
||||
return $"{datetime:yyyyMM}";
|
||||
}
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(long shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(long shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace ShardingCore.VirtualRoutes.Weeks
|
|||
return $"{currentMonday:yyyyMM}{currentMonday:dd}_{currentSunday:dd}";
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace ShardingCore.VirtualRoutes.Weeks
|
|||
return $"{currentMonday:yyyyMM}{currentMonday:dd}_{currentSunday:dd}";
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(long shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(long shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace ShardingCore.VirtualRoutes.Years
|
|||
{
|
||||
return $"{time:yyyy}";
|
||||
}
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace ShardingCore.VirtualRoutes.Years
|
|||
/// <param name="shardingKey"></param>
|
||||
/// <param name="shardingOperator"></param>
|
||||
/// <returns>当传入表后缀你告诉框架这个后缀是否需要被返回,分片字段如何筛选出后缀</returns>
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(long shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(long shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Test.Common
|
||||
{/// <summary>
|
||||
/// 雪花ID
|
||||
/// Twitter_Snowflake
|
||||
/// SnowFlake的结构如下(每部分用-分开)
|
||||
/// 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
|
||||
/// 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
|
||||
/// 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)得到的值),
|
||||
/// 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
|
||||
/// 这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。
|
||||
/// 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
|
||||
/// 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
|
||||
/// 总共加起来刚好64位,为一个Long型。
|
||||
/// SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),
|
||||
/// 并且效率较高,经测试,SnowFlake单机每秒都能够产生出极限4,096,000个ID来
|
||||
/// </summary>
|
||||
public class SnowflakeId
|
||||
{
|
||||
|
||||
// 开始时间截 (new DateTime(2020, 1, 1).ToUniversalTime() - Jan1st1970).TotalMilliseconds
|
||||
private const long twepoch = 1577808000000L;
|
||||
|
||||
// 机器id所占的位数
|
||||
private const int workerIdBits = 5;
|
||||
|
||||
// 数据标识id所占的位数
|
||||
private const int datacenterIdBits = 5;
|
||||
|
||||
// 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
|
||||
private const long maxWorkerId = -1L ^ (-1L << workerIdBits);
|
||||
|
||||
// 支持的最大数据标识id,结果是31
|
||||
private const long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
|
||||
|
||||
// 序列在id中占的位数
|
||||
private const int sequenceBits = 12;
|
||||
|
||||
// 数据标识id向左移17位(12+5)
|
||||
private const int datacenterIdShift = sequenceBits + workerIdBits;
|
||||
|
||||
// 机器ID向左移12位
|
||||
private const int workerIdShift = sequenceBits;
|
||||
|
||||
|
||||
// 时间截向左移22位(5+5+12)
|
||||
private const int timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
||||
|
||||
// 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
|
||||
private const long sequenceMask = -1L ^ (-1L << sequenceBits);
|
||||
|
||||
// 数据中心ID(0~31)
|
||||
public long datacenterId { get; private set; }
|
||||
|
||||
// 工作机器ID(0~31)
|
||||
public long workerId { get; private set; }
|
||||
|
||||
// 毫秒内序列(0~4095)
|
||||
public long sequence { get; private set; }
|
||||
|
||||
// 上次生成ID的时间截
|
||||
public long lastTimestamp { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 雪花ID
|
||||
/// </summary>
|
||||
/// <param name="datacenterId">数据中心ID</param>
|
||||
/// <param name="workerId">工作机器ID</param>
|
||||
public SnowflakeId(long datacenterId, long workerId)
|
||||
{
|
||||
if (datacenterId > maxDatacenterId || datacenterId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("datacenter Id can't be greater than {0} or less than 0", maxDatacenterId));
|
||||
}
|
||||
if (workerId > maxWorkerId || workerId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0", maxWorkerId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
this.datacenterId = datacenterId;
|
||||
this.sequence = 0L;
|
||||
this.lastTimestamp = -1L;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得下一个ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public long NextId()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp();
|
||||
if (timestamp > lastTimestamp) //时间戳改变,毫秒内序列重置
|
||||
{
|
||||
sequence = 0L;
|
||||
}
|
||||
else if (timestamp == lastTimestamp) //如果是同一时间生成的,则进行毫秒内序列
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence == 0) //毫秒内序列溢出
|
||||
{
|
||||
timestamp = GetNextTimestamp(lastTimestamp); //阻塞到下一个毫秒,获得新的时间戳
|
||||
}
|
||||
}
|
||||
else //当前时间小于上一次ID生成的时间戳,证明系统时钟被回拨,此时需要做回拨处理
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence > 0)
|
||||
{
|
||||
timestamp = lastTimestamp; //停留在最后一次时间戳上,等待系统时间追上后即完全度过了时钟回拨问题。
|
||||
}
|
||||
else //毫秒内序列溢出
|
||||
{
|
||||
timestamp = lastTimestamp + 1; //直接进位到下一个毫秒
|
||||
}
|
||||
//throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", lastTimestamp - timestamp));
|
||||
}
|
||||
|
||||
lastTimestamp = timestamp; //上次生成ID的时间截
|
||||
|
||||
//移位并通过或运算拼到一起组成64位的ID
|
||||
var id = ((timestamp - twepoch) << timestampLeftShift)
|
||||
| (datacenterId << datacenterIdShift)
|
||||
| (workerId << workerIdShift)
|
||||
| sequence;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime AnalyzeIdToDateTime(long Id)
|
||||
{
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
return time.ToLocalTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string AnalyzeId(long Id)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
sb.Append(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss:fff"));
|
||||
|
||||
var datacenterId = (Id ^ (timestamp << timestampLeftShift)) >> datacenterIdShift;
|
||||
sb.Append("_" + datacenterId);
|
||||
|
||||
var workerId = (Id ^ ((timestamp << timestampLeftShift) | (datacenterId << datacenterIdShift))) >> workerIdShift;
|
||||
sb.Append("_" + workerId);
|
||||
|
||||
var sequence = Id & sequenceMask;
|
||||
sb.Append("_" + sequence);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 阻塞到下一个毫秒,直到获得新的时间戳
|
||||
/// </summary>
|
||||
/// <param name="lastTimestamp">上次生成ID的时间截</param>
|
||||
/// <returns>当前时间戳</returns>
|
||||
private static long GetNextTimestamp(long lastTimestamp)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp();
|
||||
while (timestamp <= lastTimestamp)
|
||||
{
|
||||
timestamp = GetCurrentTimestamp();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static long GetCurrentTimestamp()
|
||||
{
|
||||
return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
|
||||
}
|
||||
|
||||
private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.Test.Domain.Entities
|
||||
{
|
||||
public class MultiShardingOrder
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using ShardingCore.Test.Domain.Entities;
|
||||
|
||||
namespace ShardingCore.Test.Domain.Maps
|
||||
{
|
||||
public class MultiShardingOrderMap:IEntityTypeConfiguration<MultiShardingOrder>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<MultiShardingOrder> builder)
|
||||
{
|
||||
builder.HasKey(o => o.Id);
|
||||
builder.Property(o => o.Id).ValueGeneratedNever();
|
||||
builder.Property(o => o.Name).IsRequired().IsUnicode(false).HasMaxLength(50);
|
||||
builder.ToTable(nameof(MultiShardingOrder));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ namespace ShardingCore.Test
|
|||
modelBuilder.ApplyConfiguration(new LogYearLongMap());
|
||||
modelBuilder.ApplyConfiguration(new SysUserModIntMap());
|
||||
modelBuilder.ApplyConfiguration(new LogDayLongMap());
|
||||
modelBuilder.ApplyConfiguration(new MultiShardingOrderMap());
|
||||
}
|
||||
|
||||
public IRouteTail RouteTail { get; set; }
|
||||
|
|
|
@ -86,29 +86,29 @@ namespace ShardingCore.Test
|
|||
var xxxx = "202102";
|
||||
var queryable1 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202102);
|
||||
var routeParseExpression1 = ShardingUtil.GetRouteParseExpression(queryable1, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable2 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= 202102);
|
||||
var routeParseExpression2 = ShardingUtil.GetRouteParseExpression(queryable2, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var xxxx1 = 202102;
|
||||
var queryable3 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= xxxx1);
|
||||
var routeParseExpression3 = ShardingUtil.GetRouteParseExpression(queryable3, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable4 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202101);
|
||||
var routeParseExpression4 = ShardingUtil.GetRouteParseExpression(queryable4, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable5 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth > 202101);
|
||||
var routeParseExpression5 = ShardingUtil.GetRouteParseExpression(queryable5, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable6 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth == 202101);
|
||||
var routeParseExpression6 = ShardingUtil.GetRouteParseExpression(queryable6, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable7 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 <= o.DateOfMonth);
|
||||
var routeParseExpression7 = ShardingUtil.GetRouteParseExpression(queryable7, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable8 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 == o.DateOfMonth);
|
||||
var routeParseExpression8 = ShardingUtil.GetRouteParseExpression(queryable8, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression2));
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression3));
|
||||
Assert.NotEqual(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression4));
|
||||
|
@ -235,6 +235,20 @@ namespace ShardingCore.Test
|
|||
public string Id { get; set; }
|
||||
public string T { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestMultiShardingProperty()
|
||||
{
|
||||
|
||||
var multiOrder = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 232398109278351360).FirstOrDefaultAsync();
|
||||
Assert.NotNull(multiOrder);
|
||||
var longs = new[] { 232398109278351360, 255197859283087360 };
|
||||
var multiOrders = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => longs.Contains(o.Id)).ToListAsync();
|
||||
Assert.Equal(2, multiOrders.Count);
|
||||
var dateTime = new DateTime(2021, 11, 1);
|
||||
var multiOrder404 = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 250345338962063360 && o.CreateTime < dateTime).FirstOrDefaultAsync();
|
||||
Assert.Null(multiOrder404);
|
||||
}
|
||||
[Fact]
|
||||
public void TestEntityMetadataManager()
|
||||
{
|
||||
|
|
|
@ -65,29 +65,29 @@ namespace ShardingCore.Test
|
|||
|
||||
var queryable1 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202102);
|
||||
var routeParseExpression1 = ShardingUtil.GetRouteParseExpression(queryable1, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable2 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= 202102);
|
||||
var routeParseExpression2 = ShardingUtil.GetRouteParseExpression(queryable2, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var xxxx1 = 202102;
|
||||
var queryable3 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= xxxx1);
|
||||
var routeParseExpression3 = ShardingUtil.GetRouteParseExpression(queryable3, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable4 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202101);
|
||||
var routeParseExpression4 = ShardingUtil.GetRouteParseExpression(queryable4, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable5 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth > 202101);
|
||||
var routeParseExpression5 = ShardingUtil.GetRouteParseExpression(queryable5, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable6 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth == 202101);
|
||||
var routeParseExpression6 = ShardingUtil.GetRouteParseExpression(queryable6, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable7 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 <= o.DateOfMonth);
|
||||
var routeParseExpression7 = ShardingUtil.GetRouteParseExpression(queryable7, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable8 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 == o.DateOfMonth);
|
||||
var routeParseExpression8 = ShardingUtil.GetRouteParseExpression(queryable8, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression2));
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression3));
|
||||
Assert.NotEqual(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression4));
|
||||
|
@ -190,6 +190,20 @@ namespace ShardingCore.Test
|
|||
public string Id { get; set; }
|
||||
public string T { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestMultiShardingProperty()
|
||||
{
|
||||
|
||||
var multiOrder = _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 232398109278351360).FirstOrDefault();
|
||||
Assert.NotNull(multiOrder);
|
||||
var longs = new[] { 232398109278351360, 255197859283087360 };
|
||||
var multiOrders = _virtualDbContext.Set<MultiShardingOrder>().Where(o => longs.Contains(o.Id)).ToList();
|
||||
Assert.Equal(2, multiOrders.Count);
|
||||
var dateTime = new DateTime(2021, 11, 1);
|
||||
var multiOrder404 = _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 250345338962063360 && o.CreateTime < dateTime).FirstOrDefault();
|
||||
Assert.Null(multiOrder404);
|
||||
}
|
||||
[Fact]
|
||||
public void TestEntityMetadataManager()
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class LogDayLongVirtualRoute:AbstractSimpleShardingDayKeyLongVirtualTableRoute<LogDayLong>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
protected override bool EnableHintRoute => true;
|
||||
|
||||
public override void Configure(EntityMetadataTableBuilder<LogDayLong> builder)
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class LogDayVirtualTableRoute:AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<LogDay>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
protected override bool EnableHintRoute => true;
|
||||
|
||||
public override DateTime GetBeginTime()
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class LogMonthLongvirtualRoute:AbstractSimpleShardingMonthKeyLongVirtualTableRoute<LogMonthLong>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
protected override bool EnableHintRoute => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class LogWeekDateTimeVirtualTableRoute:AbstractSimpleShardingWeekKeyDateTimeVirtualTableRoute<LogWeekDateTime>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
protected override bool EnableHintRoute => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class LogWeekTimeLongVirtualTableRoute : AbstractSimpleShardingWeekKeyLongVirtualTableRoute<LogWeekTimeLong>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
protected override bool EnableHintRoute => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class LogYearDateTimeVirtualRoute:AbstractSimpleShardingYearKeyDateTimeVirtualTableRoute<LogYearDateTime>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
protected override bool EnableHintRoute => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Test.Domain.Entities;
|
||||
using ShardingCore.VirtualRoutes.Years;
|
||||
|
@ -12,7 +13,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class LogYearLongVirtualRoute:AbstractSimpleShardingYearKeyLongVirtualTableRoute<LogYearLong>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
protected override bool EnableHintRoute => true;
|
||||
|
||||
public override void Configure(EntityMetadataTableBuilder<LogYearLong> builder)
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Helpers;
|
||||
using ShardingCore.Test.Common;
|
||||
using ShardingCore.Test.Domain.Entities;
|
||||
using ShardingCore.VirtualRoutes.Months;
|
||||
|
||||
namespace ShardingCore.Test.Shardings
|
||||
{
|
||||
public class MultiShardingOrderVirtualTableRoute:AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<MultiShardingOrder>
|
||||
{
|
||||
public override void Configure(EntityMetadataTableBuilder<MultiShardingOrder> builder)
|
||||
{
|
||||
builder.ShardingProperty(o => o.CreateTime);
|
||||
builder.ShardingExtraProperty(o => o.Id);
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetExtraRouteFilter(object shardingKey, ShardingOperatorEnum shardingOperator, string shardingPropertyName)
|
||||
{
|
||||
switch (shardingPropertyName)
|
||||
{
|
||||
case nameof(MultiShardingOrder.Id): return GetIdRouteFilter(shardingKey, shardingOperator);
|
||||
default: throw new NotImplementedException(shardingPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
private Expression<Func<string, bool>> GetIdRouteFilter(object shardingKey,
|
||||
ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
//解析雪花id 需要考虑异常情况,传入的可能不是雪花id那么可以随机查询一张表
|
||||
var analyzeIdToDateTime = SnowflakeId.AnalyzeIdToDateTime(Convert.ToInt64(shardingKey));
|
||||
//当前时间的tail
|
||||
var t = TimeFormatToTail(analyzeIdToDateTime);
|
||||
//因为是按月分表所以获取下个月的时间判断id是否是在灵界点创建的
|
||||
var nextMonthFirstDay = ShardingCoreHelper.GetNextMonthFirstDay(DateTime.Now);
|
||||
if (analyzeIdToDateTime.AddSeconds(10) > nextMonthFirstDay)
|
||||
{
|
||||
var nextT = TimeFormatToTail(nextMonthFirstDay);
|
||||
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t||tail== nextT;
|
||||
}
|
||||
}
|
||||
var currentMonthFirstDay = ShardingCoreHelper.GetCurrentMonthFirstDay(DateTime.Now);
|
||||
if (analyzeIdToDateTime.AddSeconds(-10) < currentMonthFirstDay)
|
||||
{
|
||||
//上个月tail
|
||||
var nextT = TimeFormatToTail(analyzeIdToDateTime.AddSeconds(-10));
|
||||
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t || tail == nextT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t;
|
||||
}
|
||||
}
|
||||
|
||||
return tail => true;
|
||||
}
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override DateTime GetBeginTime()
|
||||
{
|
||||
return new DateTime(2021, 9, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class OrderAreaShardingVirtualDataSourceRoute:AbstractShardingOperatorVirtualDataSourceRoute<Order,string>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
protected override bool EnableHintRoute =>true;
|
||||
|
||||
private readonly List<string> _dataSources = new List<string>()
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace ShardingCore.Test.Shardings
|
|||
{
|
||||
public class OrderCreateTimeVirtualTableRoute:AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<Order>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
public override DateTime GetBeginTime()
|
||||
{
|
||||
return new DateTime(2021, 1, 1);
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace ShardingCore.Test.Shardings
|
|||
public class SysUserModIntVirtualRoute:AbstractSimpleShardingModKeyIntVirtualTableRoute<SysUserModInt>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public SysUserModIntVirtualRoute() : base(2, 3)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace ShardingCore.Test.Shardings
|
|||
public class SysUserModVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<SysUserMod>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public SysUserModVirtualTableRoute() : base(2,3)
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace ShardingCore.Test.Shardings
|
|||
*/
|
||||
public class SysUserSalaryVirtualTableRoute:AbstractShardingOperatorVirtualTableRoute<SysUserSalary,int>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override string ShardingKeyToTail(object shardingKey)
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ namespace ShardingCore.Test.Shardings
|
|||
return $"{dateOfMonth:yyyyMM}";
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(int shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(int shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace ShardingCore.Test
|
|||
o.CreateShardingTableOnStart = true;
|
||||
o.EnsureCreatedWithOutShardingTable = true;
|
||||
|
||||
o.AutoTrackEntity = true;
|
||||
o.ThrowIfQueryRouteNotMatch = false;
|
||||
//o.AddParallelTables(typeof(SysUserMod), typeof(SysUserSalary));
|
||||
})
|
||||
.AddShardingTransaction((connection, builder) =>
|
||||
|
@ -72,6 +72,7 @@ namespace ShardingCore.Test
|
|||
op.AddShardingTableRoute<LogYearLongVirtualRoute>();
|
||||
op.AddShardingTableRoute<SysUserModIntVirtualRoute>();
|
||||
op.AddShardingTableRoute<LogDayLongVirtualRoute>();
|
||||
op.AddShardingTableRoute<MultiShardingOrderVirtualTableRoute>();
|
||||
}).AddReadWriteSeparation(sp =>
|
||||
{
|
||||
return new Dictionary<string, IEnumerable<string>>()
|
||||
|
@ -269,6 +270,82 @@ namespace ShardingCore.Test
|
|||
});
|
||||
begin6 = begin6.AddDays(1);
|
||||
}
|
||||
var multiShardingOrders = new List<MultiShardingOrder>(9);
|
||||
#region 添加多字段分表
|
||||
|
||||
{
|
||||
var now = new DateTime(2021, 10, 1, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 231765457240207360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 10, 2, 11, 3, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 232095129534607360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 10, 3, 7, 7, 7);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 232398109278351360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 11, 6, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 244811420401807360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 11, 21, 19, 43, 0);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 250345338962063360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 5, 5, 5, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 255197859283087360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 9, 19, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 256860816933007360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 19, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 260394098622607360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
using (var tran = virtualDbContext.Database.BeginTransaction())
|
||||
{
|
||||
await virtualDbContext.AddRangeAsync(userMods);
|
||||
|
@ -282,6 +359,7 @@ namespace ShardingCore.Test
|
|||
await virtualDbContext.AddRangeAsync(logYears);
|
||||
await virtualDbContext.AddRangeAsync(logMonthLongs);
|
||||
await virtualDbContext.AddRangeAsync(logYearkLongs);
|
||||
await virtualDbContext.AddRangeAsync(multiShardingOrders);
|
||||
|
||||
await virtualDbContext.SaveChangesAsync();
|
||||
tran.Commit();
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Test2x.Common
|
||||
{/// <summary>
|
||||
/// 雪花ID
|
||||
/// Twitter_Snowflake
|
||||
/// SnowFlake的结构如下(每部分用-分开)
|
||||
/// 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
|
||||
/// 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
|
||||
/// 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)得到的值),
|
||||
/// 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
|
||||
/// 这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。
|
||||
/// 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
|
||||
/// 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
|
||||
/// 总共加起来刚好64位,为一个Long型。
|
||||
/// SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),
|
||||
/// 并且效率较高,经测试,SnowFlake单机每秒都能够产生出极限4,096,000个ID来
|
||||
/// </summary>
|
||||
public class SnowflakeId
|
||||
{
|
||||
|
||||
// 开始时间截 (new DateTime(2020, 1, 1).ToUniversalTime() - Jan1st1970).TotalMilliseconds
|
||||
private const long twepoch = 1577808000000L;
|
||||
|
||||
// 机器id所占的位数
|
||||
private const int workerIdBits = 5;
|
||||
|
||||
// 数据标识id所占的位数
|
||||
private const int datacenterIdBits = 5;
|
||||
|
||||
// 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
|
||||
private const long maxWorkerId = -1L ^ (-1L << workerIdBits);
|
||||
|
||||
// 支持的最大数据标识id,结果是31
|
||||
private const long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
|
||||
|
||||
// 序列在id中占的位数
|
||||
private const int sequenceBits = 12;
|
||||
|
||||
// 数据标识id向左移17位(12+5)
|
||||
private const int datacenterIdShift = sequenceBits + workerIdBits;
|
||||
|
||||
// 机器ID向左移12位
|
||||
private const int workerIdShift = sequenceBits;
|
||||
|
||||
|
||||
// 时间截向左移22位(5+5+12)
|
||||
private const int timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
||||
|
||||
// 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
|
||||
private const long sequenceMask = -1L ^ (-1L << sequenceBits);
|
||||
|
||||
// 数据中心ID(0~31)
|
||||
public long datacenterId { get; private set; }
|
||||
|
||||
// 工作机器ID(0~31)
|
||||
public long workerId { get; private set; }
|
||||
|
||||
// 毫秒内序列(0~4095)
|
||||
public long sequence { get; private set; }
|
||||
|
||||
// 上次生成ID的时间截
|
||||
public long lastTimestamp { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 雪花ID
|
||||
/// </summary>
|
||||
/// <param name="datacenterId">数据中心ID</param>
|
||||
/// <param name="workerId">工作机器ID</param>
|
||||
public SnowflakeId(long datacenterId, long workerId)
|
||||
{
|
||||
if (datacenterId > maxDatacenterId || datacenterId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("datacenter Id can't be greater than {0} or less than 0", maxDatacenterId));
|
||||
}
|
||||
if (workerId > maxWorkerId || workerId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0", maxWorkerId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
this.datacenterId = datacenterId;
|
||||
this.sequence = 0L;
|
||||
this.lastTimestamp = -1L;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得下一个ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public long NextId()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp();
|
||||
if (timestamp > lastTimestamp) //时间戳改变,毫秒内序列重置
|
||||
{
|
||||
sequence = 0L;
|
||||
}
|
||||
else if (timestamp == lastTimestamp) //如果是同一时间生成的,则进行毫秒内序列
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence == 0) //毫秒内序列溢出
|
||||
{
|
||||
timestamp = GetNextTimestamp(lastTimestamp); //阻塞到下一个毫秒,获得新的时间戳
|
||||
}
|
||||
}
|
||||
else //当前时间小于上一次ID生成的时间戳,证明系统时钟被回拨,此时需要做回拨处理
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence > 0)
|
||||
{
|
||||
timestamp = lastTimestamp; //停留在最后一次时间戳上,等待系统时间追上后即完全度过了时钟回拨问题。
|
||||
}
|
||||
else //毫秒内序列溢出
|
||||
{
|
||||
timestamp = lastTimestamp + 1; //直接进位到下一个毫秒
|
||||
}
|
||||
//throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", lastTimestamp - timestamp));
|
||||
}
|
||||
|
||||
lastTimestamp = timestamp; //上次生成ID的时间截
|
||||
|
||||
//移位并通过或运算拼到一起组成64位的ID
|
||||
var id = ((timestamp - twepoch) << timestampLeftShift)
|
||||
| (datacenterId << datacenterIdShift)
|
||||
| (workerId << workerIdShift)
|
||||
| sequence;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime AnalyzeIdToDateTime(long Id)
|
||||
{
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
return time.ToLocalTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string AnalyzeId(long Id)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
sb.Append(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss:fff"));
|
||||
|
||||
var datacenterId = (Id ^ (timestamp << timestampLeftShift)) >> datacenterIdShift;
|
||||
sb.Append("_" + datacenterId);
|
||||
|
||||
var workerId = (Id ^ ((timestamp << timestampLeftShift) | (datacenterId << datacenterIdShift))) >> workerIdShift;
|
||||
sb.Append("_" + workerId);
|
||||
|
||||
var sequence = Id & sequenceMask;
|
||||
sb.Append("_" + sequence);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 阻塞到下一个毫秒,直到获得新的时间戳
|
||||
/// </summary>
|
||||
/// <param name="lastTimestamp">上次生成ID的时间截</param>
|
||||
/// <returns>当前时间戳</returns>
|
||||
private static long GetNextTimestamp(long lastTimestamp)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp();
|
||||
while (timestamp <= lastTimestamp)
|
||||
{
|
||||
timestamp = GetCurrentTimestamp();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static long GetCurrentTimestamp()
|
||||
{
|
||||
return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
|
||||
}
|
||||
|
||||
private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.Test2x.Domain.Entities
|
||||
{
|
||||
public class MultiShardingOrder
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using ShardingCore.Test2x.Domain.Entities;
|
||||
|
||||
namespace ShardingCore.Test2x.Domain.Maps
|
||||
{
|
||||
public class MultiShardingOrderMap:IEntityTypeConfiguration<MultiShardingOrder>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<MultiShardingOrder> builder)
|
||||
{
|
||||
builder.HasKey(o => o.Id);
|
||||
builder.Property(o => o.Id).ValueGeneratedNever();
|
||||
builder.Property(o => o.Name).IsRequired().IsUnicode(false).HasMaxLength(50);
|
||||
builder.ToTable(nameof(MultiShardingOrder));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ namespace ShardingCore.Test2x
|
|||
modelBuilder.ApplyConfiguration(new LogYearLongMap());
|
||||
modelBuilder.ApplyConfiguration(new SysUserModIntMap());
|
||||
modelBuilder.ApplyConfiguration(new LogDayLongMap());
|
||||
modelBuilder.ApplyConfiguration(new MultiShardingOrderMap());
|
||||
}
|
||||
|
||||
public IRouteTail RouteTail { get; set; }
|
||||
|
|
|
@ -74,29 +74,29 @@ namespace ShardingCore.Test2x
|
|||
|
||||
var queryable1 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202102);
|
||||
var routeParseExpression1 = ShardingUtil.GetRouteParseExpression(queryable1, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable2 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= 202102);
|
||||
var routeParseExpression2 = ShardingUtil.GetRouteParseExpression(queryable2, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var xxxx1 = 202102;
|
||||
var queryable3 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= xxxx1);
|
||||
var routeParseExpression3 = ShardingUtil.GetRouteParseExpression(queryable3, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable4 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202101);
|
||||
var routeParseExpression4 = ShardingUtil.GetRouteParseExpression(queryable4, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable5 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth > 202101);
|
||||
var routeParseExpression5 = ShardingUtil.GetRouteParseExpression(queryable5, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable6 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth == 202101);
|
||||
var routeParseExpression6 = ShardingUtil.GetRouteParseExpression(queryable6, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable7 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 <= o.DateOfMonth);
|
||||
var routeParseExpression7 = ShardingUtil.GetRouteParseExpression(queryable7, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable8 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 == o.DateOfMonth);
|
||||
var routeParseExpression8 = ShardingUtil.GetRouteParseExpression(queryable8, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression2));
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression3));
|
||||
Assert.NotEqual(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression4));
|
||||
|
@ -218,6 +218,20 @@ namespace ShardingCore.Test2x
|
|||
public string Id { get; set; }
|
||||
public string T { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestMultiShardingProperty()
|
||||
{
|
||||
|
||||
var multiOrder = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 232398109278351360).FirstOrDefaultAsync();
|
||||
Assert.NotNull(multiOrder);
|
||||
var longs = new[] { 232398109278351360, 255197859283087360 };
|
||||
var multiOrders = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => longs.Contains(o.Id)).ToListAsync();
|
||||
Assert.Equal(2, multiOrders.Count);
|
||||
var dateTime = new DateTime(2021, 11, 1);
|
||||
var multiOrder404 = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 250345338962063360 && o.CreateTime < dateTime).FirstOrDefaultAsync();
|
||||
Assert.Null(multiOrder404);
|
||||
}
|
||||
[Fact]
|
||||
public void TestEntityMetadataManager()
|
||||
{
|
||||
|
|
|
@ -64,29 +64,29 @@ namespace ShardingCore.Test2x
|
|||
|
||||
var queryable1 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202102);
|
||||
var routeParseExpression1 = ShardingUtil.GetRouteParseExpression(queryable1, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable2 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= 202102);
|
||||
var routeParseExpression2 = ShardingUtil.GetRouteParseExpression(queryable2, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var xxxx1 = 202102;
|
||||
var queryable3 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= xxxx1);
|
||||
var routeParseExpression3 = ShardingUtil.GetRouteParseExpression(queryable3, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable4 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202101);
|
||||
var routeParseExpression4 = ShardingUtil.GetRouteParseExpression(queryable4, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable5 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth > 202101);
|
||||
var routeParseExpression5 = ShardingUtil.GetRouteParseExpression(queryable5, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable6 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth == 202101);
|
||||
var routeParseExpression6 = ShardingUtil.GetRouteParseExpression(queryable6, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable7 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 <= o.DateOfMonth);
|
||||
var routeParseExpression7 = ShardingUtil.GetRouteParseExpression(queryable7, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable8 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 == o.DateOfMonth);
|
||||
var routeParseExpression8 = ShardingUtil.GetRouteParseExpression(queryable8, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression2));
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression3));
|
||||
Assert.NotEqual(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression4));
|
||||
|
@ -189,6 +189,19 @@ namespace ShardingCore.Test2x
|
|||
public string T { get; set; }
|
||||
}
|
||||
[Fact]
|
||||
public void TestMultiShardingProperty()
|
||||
{
|
||||
|
||||
var multiOrder = _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 232398109278351360).FirstOrDefault();
|
||||
Assert.NotNull(multiOrder);
|
||||
var longs = new[] { 232398109278351360, 255197859283087360 };
|
||||
var multiOrders = _virtualDbContext.Set<MultiShardingOrder>().Where(o => longs.Contains(o.Id)).ToList();
|
||||
Assert.Equal(2, multiOrders.Count);
|
||||
var dateTime = new DateTime(2021, 11, 1);
|
||||
var multiOrder404 = _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 250345338962063360 && o.CreateTime < dateTime).FirstOrDefault();
|
||||
Assert.Null(multiOrder404);
|
||||
}
|
||||
[Fact]
|
||||
public void TestEntityMetadataManager()
|
||||
{
|
||||
var objMetadata0 = _entityMetadataManager.TryGet(typeof(object));
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class LogDayLongVirtualRoute:AbstractSimpleShardingDayKeyLongVirtualTableRoute<LogDayLong>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override void Configure(EntityMetadataTableBuilder<LogDayLong> builder)
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class LogDayVirtualTableRoute:AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<LogDay>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override DateTime GetBeginTime()
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class LogMonthLongvirtualRoute:AbstractSimpleShardingMonthKeyLongVirtualTableRoute<LogMonthLong>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class LogWeekDateTimeVirtualTableRoute:AbstractSimpleShardingWeekKeyDateTimeVirtualTableRoute<LogWeekDateTime>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class LogWeekTimeLongVirtualTableRoute : AbstractSimpleShardingWeekKeyLongVirtualTableRoute<LogWeekTimeLong>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class LogYearDateTimeVirtualRoute:AbstractSimpleShardingYearKeyDateTimeVirtualTableRoute<LogYearDateTime>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class LogYearLongVirtualRoute:AbstractSimpleShardingYearKeyLongVirtualTableRoute<LogYearLong>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override void Configure(EntityMetadataTableBuilder<LogYearLong> builder)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Helpers;
|
||||
using ShardingCore.Test2x.Common;
|
||||
using ShardingCore.Test2x.Domain.Entities;
|
||||
using ShardingCore.VirtualRoutes.Months;
|
||||
|
||||
namespace ShardingCore.Test2x.Shardings
|
||||
{
|
||||
public class MultiShardingOrderVirtualTableRoute:AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<MultiShardingOrder>
|
||||
{
|
||||
public override void Configure(EntityMetadataTableBuilder<MultiShardingOrder> builder)
|
||||
{
|
||||
builder.ShardingProperty(o => o.CreateTime);
|
||||
builder.ShardingExtraProperty(o => o.Id);
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetExtraRouteFilter(object shardingKey, ShardingOperatorEnum shardingOperator, string shardingPropertyName)
|
||||
{
|
||||
switch (shardingPropertyName)
|
||||
{
|
||||
case nameof(MultiShardingOrder.Id): return GetIdRouteFilter(shardingKey, shardingOperator);
|
||||
default: throw new NotImplementedException(shardingPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
private Expression<Func<string, bool>> GetIdRouteFilter(object shardingKey,
|
||||
ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
//解析雪花id 需要考虑异常情况,传入的可能不是雪花id那么可以随机查询一张表
|
||||
var analyzeIdToDateTime = SnowflakeId.AnalyzeIdToDateTime(Convert.ToInt64(shardingKey));
|
||||
//当前时间的tail
|
||||
var t = TimeFormatToTail(analyzeIdToDateTime);
|
||||
//因为是按月分表所以获取下个月的时间判断id是否是在灵界点创建的
|
||||
var nextMonthFirstDay = ShardingCoreHelper.GetNextMonthFirstDay(DateTime.Now);
|
||||
if (analyzeIdToDateTime.AddSeconds(10) > nextMonthFirstDay)
|
||||
{
|
||||
var nextT = TimeFormatToTail(nextMonthFirstDay);
|
||||
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t||tail== nextT;
|
||||
}
|
||||
}
|
||||
var currentMonthFirstDay = ShardingCoreHelper.GetCurrentMonthFirstDay(DateTime.Now);
|
||||
if (analyzeIdToDateTime.AddSeconds(-10) < currentMonthFirstDay)
|
||||
{
|
||||
//上个月tail
|
||||
var nextT = TimeFormatToTail(analyzeIdToDateTime.AddSeconds(-10));
|
||||
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t || tail == nextT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (shardingOperator == ShardingOperatorEnum.Equal)
|
||||
{
|
||||
return tail => tail == t;
|
||||
}
|
||||
}
|
||||
|
||||
return tail => true;
|
||||
}
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override DateTime GetBeginTime()
|
||||
{
|
||||
return new DateTime(2021, 9, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class OrderAreaShardingVirtualDataSourceRoute:AbstractShardingOperatorVirtualDataSourceRoute<Order,string>
|
||||
{
|
||||
protected override bool EnableHintRoute =>true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
private readonly List<string> _dataSources = new List<string>()
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
{
|
||||
public class OrderCreateTimeVirtualTableRoute:AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<Order>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
public override DateTime GetBeginTime()
|
||||
{
|
||||
return new DateTime(2021, 1, 1);
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class SysUserModIntVirtualRoute:AbstractSimpleShardingModKeyIntVirtualTableRoute<SysUserModInt>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public SysUserModIntVirtualRoute() : base(2, 3)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
public class SysUserModVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<SysUserMod>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public SysUserModVirtualTableRoute() : base(2,3)
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
*/
|
||||
public class SysUserSalaryVirtualTableRoute:AbstractShardingOperatorVirtualTableRoute<SysUserSalary,int>
|
||||
{
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
public override string ShardingKeyToTail(object shardingKey)
|
||||
{
|
||||
var time = Convert.ToInt32(shardingKey);
|
||||
|
@ -45,7 +45,7 @@ namespace ShardingCore.Test2x.Shardings
|
|||
return $"{dateOfMonth:yyyyMM}";
|
||||
}
|
||||
|
||||
public override Expression<Func<string, bool>> GetMainRouteFilter(int shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
public override Expression<Func<string, bool>> GetRouteToFilter(int shardingKey, ShardingOperatorEnum shardingOperator)
|
||||
{
|
||||
var t = TimeFormatToTail(shardingKey);
|
||||
switch (shardingOperator)
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace ShardingCore.Test2x
|
|||
{
|
||||
o.CreateShardingTableOnStart = true;
|
||||
o.EnsureCreatedWithOutShardingTable = true;
|
||||
o.AutoTrackEntity = true;
|
||||
o.ThrowIfQueryRouteNotMatch = false;
|
||||
})
|
||||
.AddShardingTransaction((connection, builder) =>
|
||||
builder.UseSqlServer(connection).UseLoggerFactory(efLogger))
|
||||
|
@ -70,6 +70,7 @@ namespace ShardingCore.Test2x
|
|||
op.AddShardingTableRoute<LogYearLongVirtualRoute>();
|
||||
op.AddShardingTableRoute<SysUserModIntVirtualRoute>();
|
||||
op.AddShardingTableRoute<LogDayLongVirtualRoute>();
|
||||
op.AddShardingTableRoute<MultiShardingOrderVirtualTableRoute>();
|
||||
}).AddReadWriteSeparation(sp =>
|
||||
{
|
||||
return new Dictionary<string, IEnumerable<string>>()
|
||||
|
@ -267,6 +268,82 @@ namespace ShardingCore.Test2x
|
|||
});
|
||||
begin6 = begin6.AddDays(1);
|
||||
}
|
||||
var multiShardingOrders = new List<MultiShardingOrder>(9);
|
||||
#region 添加多字段分表
|
||||
|
||||
{
|
||||
var now = new DateTime(2021, 10, 1, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 231765457240207360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 10, 2, 11, 3, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 232095129534607360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 10, 3, 7, 7, 7);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 232398109278351360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 11, 6, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 244811420401807360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 11, 21, 19, 43, 0);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 250345338962063360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 5, 5, 5, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 255197859283087360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 9, 19, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 256860816933007360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
{
|
||||
var now = new DateTime(2021, 12, 19, 13, 13, 11);
|
||||
multiShardingOrders.Add(new MultiShardingOrder()
|
||||
{
|
||||
Id = 260394098622607360,
|
||||
Name = $"{now:yyyy/MM/dd HH:mm:ss}",
|
||||
CreateTime = now
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
using (var tran = virtualDbContext.Database.BeginTransaction())
|
||||
{
|
||||
await virtualDbContext.AddRangeAsync(userMods);
|
||||
|
@ -280,6 +357,7 @@ namespace ShardingCore.Test2x
|
|||
await virtualDbContext.AddRangeAsync(logYears);
|
||||
await virtualDbContext.AddRangeAsync(logMonthLongs);
|
||||
await virtualDbContext.AddRangeAsync(logYearkLongs);
|
||||
await virtualDbContext.AddRangeAsync(multiShardingOrders);
|
||||
|
||||
await virtualDbContext.SaveChangesAsync();
|
||||
tran.Commit();
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Test3x.Common
|
||||
{/// <summary>
|
||||
/// 雪花ID
|
||||
/// Twitter_Snowflake
|
||||
/// SnowFlake的结构如下(每部分用-分开)
|
||||
/// 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
|
||||
/// 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
|
||||
/// 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)得到的值),
|
||||
/// 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
|
||||
/// 这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。
|
||||
/// 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
|
||||
/// 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
|
||||
/// 总共加起来刚好64位,为一个Long型。
|
||||
/// SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),
|
||||
/// 并且效率较高,经测试,SnowFlake单机每秒都能够产生出极限4,096,000个ID来
|
||||
/// </summary>
|
||||
public class SnowflakeId
|
||||
{
|
||||
|
||||
// 开始时间截 (new DateTime(2020, 1, 1).ToUniversalTime() - Jan1st1970).TotalMilliseconds
|
||||
private const long twepoch = 1577808000000L;
|
||||
|
||||
// 机器id所占的位数
|
||||
private const int workerIdBits = 5;
|
||||
|
||||
// 数据标识id所占的位数
|
||||
private const int datacenterIdBits = 5;
|
||||
|
||||
// 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
|
||||
private const long maxWorkerId = -1L ^ (-1L << workerIdBits);
|
||||
|
||||
// 支持的最大数据标识id,结果是31
|
||||
private const long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
|
||||
|
||||
// 序列在id中占的位数
|
||||
private const int sequenceBits = 12;
|
||||
|
||||
// 数据标识id向左移17位(12+5)
|
||||
private const int datacenterIdShift = sequenceBits + workerIdBits;
|
||||
|
||||
// 机器ID向左移12位
|
||||
private const int workerIdShift = sequenceBits;
|
||||
|
||||
|
||||
// 时间截向左移22位(5+5+12)
|
||||
private const int timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
||||
|
||||
// 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
|
||||
private const long sequenceMask = -1L ^ (-1L << sequenceBits);
|
||||
|
||||
// 数据中心ID(0~31)
|
||||
public long datacenterId { get; private set; }
|
||||
|
||||
// 工作机器ID(0~31)
|
||||
public long workerId { get; private set; }
|
||||
|
||||
// 毫秒内序列(0~4095)
|
||||
public long sequence { get; private set; }
|
||||
|
||||
// 上次生成ID的时间截
|
||||
public long lastTimestamp { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 雪花ID
|
||||
/// </summary>
|
||||
/// <param name="datacenterId">数据中心ID</param>
|
||||
/// <param name="workerId">工作机器ID</param>
|
||||
public SnowflakeId(long datacenterId, long workerId)
|
||||
{
|
||||
if (datacenterId > maxDatacenterId || datacenterId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("datacenter Id can't be greater than {0} or less than 0", maxDatacenterId));
|
||||
}
|
||||
if (workerId > maxWorkerId || workerId < 0)
|
||||
{
|
||||
throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0", maxWorkerId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
this.datacenterId = datacenterId;
|
||||
this.sequence = 0L;
|
||||
this.lastTimestamp = -1L;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得下一个ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public long NextId()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp();
|
||||
if (timestamp > lastTimestamp) //时间戳改变,毫秒内序列重置
|
||||
{
|
||||
sequence = 0L;
|
||||
}
|
||||
else if (timestamp == lastTimestamp) //如果是同一时间生成的,则进行毫秒内序列
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence == 0) //毫秒内序列溢出
|
||||
{
|
||||
timestamp = GetNextTimestamp(lastTimestamp); //阻塞到下一个毫秒,获得新的时间戳
|
||||
}
|
||||
}
|
||||
else //当前时间小于上一次ID生成的时间戳,证明系统时钟被回拨,此时需要做回拨处理
|
||||
{
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence > 0)
|
||||
{
|
||||
timestamp = lastTimestamp; //停留在最后一次时间戳上,等待系统时间追上后即完全度过了时钟回拨问题。
|
||||
}
|
||||
else //毫秒内序列溢出
|
||||
{
|
||||
timestamp = lastTimestamp + 1; //直接进位到下一个毫秒
|
||||
}
|
||||
//throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", lastTimestamp - timestamp));
|
||||
}
|
||||
|
||||
lastTimestamp = timestamp; //上次生成ID的时间截
|
||||
|
||||
//移位并通过或运算拼到一起组成64位的ID
|
||||
var id = ((timestamp - twepoch) << timestampLeftShift)
|
||||
| (datacenterId << datacenterIdShift)
|
||||
| (workerId << workerIdShift)
|
||||
| sequence;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime AnalyzeIdToDateTime(long Id)
|
||||
{
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
return time.ToLocalTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析雪花ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string AnalyzeId(long Id)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
var timestamp = (Id >> timestampLeftShift);
|
||||
var time = Jan1st1970.AddMilliseconds(timestamp + twepoch);
|
||||
sb.Append(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss:fff"));
|
||||
|
||||
var datacenterId = (Id ^ (timestamp << timestampLeftShift)) >> datacenterIdShift;
|
||||
sb.Append("_" + datacenterId);
|
||||
|
||||
var workerId = (Id ^ ((timestamp << timestampLeftShift) | (datacenterId << datacenterIdShift))) >> workerIdShift;
|
||||
sb.Append("_" + workerId);
|
||||
|
||||
var sequence = Id & sequenceMask;
|
||||
sb.Append("_" + sequence);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 阻塞到下一个毫秒,直到获得新的时间戳
|
||||
/// </summary>
|
||||
/// <param name="lastTimestamp">上次生成ID的时间截</param>
|
||||
/// <returns>当前时间戳</returns>
|
||||
private static long GetNextTimestamp(long lastTimestamp)
|
||||
{
|
||||
long timestamp = GetCurrentTimestamp();
|
||||
while (timestamp <= lastTimestamp)
|
||||
{
|
||||
timestamp = GetCurrentTimestamp();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static long GetCurrentTimestamp()
|
||||
{
|
||||
return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
|
||||
}
|
||||
|
||||
private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.Test3x.Domain.Entities
|
||||
{
|
||||
public class MultiShardingOrder
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using ShardingCore.Test3x.Domain.Entities;
|
||||
|
||||
namespace ShardingCore.Test3x.Domain.Maps
|
||||
{
|
||||
public class MultiShardingOrderMap:IEntityTypeConfiguration<MultiShardingOrder>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<MultiShardingOrder> builder)
|
||||
{
|
||||
builder.HasKey(o => o.Id);
|
||||
builder.Property(o => o.Id).ValueGeneratedNever();
|
||||
builder.Property(o => o.Name).IsRequired().IsUnicode(false).HasMaxLength(50);
|
||||
builder.ToTable(nameof(MultiShardingOrder));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ namespace ShardingCore.Test3x
|
|||
modelBuilder.ApplyConfiguration(new LogYearLongMap());
|
||||
modelBuilder.ApplyConfiguration(new SysUserModIntMap());
|
||||
modelBuilder.ApplyConfiguration(new LogDayLongMap());
|
||||
modelBuilder.ApplyConfiguration(new MultiShardingOrderMap());
|
||||
}
|
||||
|
||||
public IRouteTail RouteTail { get; set; }
|
||||
|
|
|
@ -74,29 +74,29 @@ namespace ShardingCore.Test3x
|
|||
|
||||
var queryable1 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202102);
|
||||
var routeParseExpression1 = ShardingUtil.GetRouteParseExpression(queryable1, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable2 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= 202102);
|
||||
var routeParseExpression2 = ShardingUtil.GetRouteParseExpression(queryable2, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var xxxx1 = 202102;
|
||||
var queryable3 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= xxxx1);
|
||||
var routeParseExpression3 = ShardingUtil.GetRouteParseExpression(queryable3, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable4 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202101);
|
||||
var routeParseExpression4 = ShardingUtil.GetRouteParseExpression(queryable4, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable5 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth > 202101);
|
||||
var routeParseExpression5 = ShardingUtil.GetRouteParseExpression(queryable5, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable6 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth == 202101);
|
||||
var routeParseExpression6 = ShardingUtil.GetRouteParseExpression(queryable6, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable7 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 <= o.DateOfMonth);
|
||||
var routeParseExpression7 = ShardingUtil.GetRouteParseExpression(queryable7, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable8 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 == o.DateOfMonth);
|
||||
var routeParseExpression8 = ShardingUtil.GetRouteParseExpression(queryable8, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression2));
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression3));
|
||||
Assert.NotEqual(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression4));
|
||||
|
@ -217,6 +217,20 @@ namespace ShardingCore.Test3x
|
|||
public string Id { get; set; }
|
||||
public string T { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestMultiShardingProperty()
|
||||
{
|
||||
|
||||
var multiOrder = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 232398109278351360).FirstOrDefaultAsync();
|
||||
Assert.NotNull(multiOrder);
|
||||
var longs = new[] { 232398109278351360, 255197859283087360 };
|
||||
var multiOrders = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => longs.Contains(o.Id)).ToListAsync();
|
||||
Assert.Equal(2, multiOrders.Count);
|
||||
var dateTime = new DateTime(2021, 11, 1);
|
||||
var multiOrder404 = await _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 250345338962063360 && o.CreateTime < dateTime).FirstOrDefaultAsync();
|
||||
Assert.Null(multiOrder404);
|
||||
}
|
||||
[Fact]
|
||||
public void TestEntityMetadataManager()
|
||||
{
|
||||
|
|
|
@ -65,29 +65,29 @@ namespace ShardingCore.Test3x
|
|||
|
||||
var queryable1 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202102);
|
||||
var routeParseExpression1 = ShardingUtil.GetRouteParseExpression(queryable1, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable2 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= 202102);
|
||||
var routeParseExpression2 = ShardingUtil.GetRouteParseExpression(queryable2, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var xxxx1 = 202102;
|
||||
var queryable3 = _virtualDbContext.Set<SysUserSalary>().Where(ox => ox.DateOfMonth >= xxxx1);
|
||||
var routeParseExpression3 = ShardingUtil.GetRouteParseExpression(queryable3, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable4 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth >= 202101);
|
||||
var routeParseExpression4 = ShardingUtil.GetRouteParseExpression(queryable4, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable5 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth > 202101);
|
||||
var routeParseExpression5 = ShardingUtil.GetRouteParseExpression(queryable5, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable6 = _virtualDbContext.Set<SysUserSalary>().Where(o => o.DateOfMonth == 202101);
|
||||
var routeParseExpression6 = ShardingUtil.GetRouteParseExpression(queryable6, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable7 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 <= o.DateOfMonth);
|
||||
var routeParseExpression7 = ShardingUtil.GetRouteParseExpression(queryable7, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
var queryable8 = _virtualDbContext.Set<SysUserSalary>().Where(o => 202101 == o.DateOfMonth);
|
||||
var routeParseExpression8 = ShardingUtil.GetRouteParseExpression(queryable8, virtualTableRoute.EntityMetadata,
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteToFilter(i, op,propertyName), true);
|
||||
(i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true);
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression2));
|
||||
Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression3));
|
||||
Assert.NotEqual(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression4));
|
||||
|
@ -191,6 +191,19 @@ namespace ShardingCore.Test3x
|
|||
public string T { get; set; }
|
||||
}
|
||||
[Fact]
|
||||
public void TestMultiShardingProperty()
|
||||
{
|
||||
|
||||
var multiOrder = _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 232398109278351360).FirstOrDefault();
|
||||
Assert.NotNull(multiOrder);
|
||||
var longs = new[] { 232398109278351360, 255197859283087360 };
|
||||
var multiOrders = _virtualDbContext.Set<MultiShardingOrder>().Where(o => longs.Contains(o.Id)).ToList();
|
||||
Assert.Equal(2, multiOrders.Count);
|
||||
var dateTime = new DateTime(2021, 11, 1);
|
||||
var multiOrder404 = _virtualDbContext.Set<MultiShardingOrder>().Where(o => o.Id == 250345338962063360 && o.CreateTime < dateTime).FirstOrDefault();
|
||||
Assert.Null(multiOrder404);
|
||||
}
|
||||
[Fact]
|
||||
public void TestEntityMetadataManager()
|
||||
{
|
||||
var objMetadata0 = _entityMetadataManager.TryGet(typeof(object));
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace ShardingCore.Test3x.Shardings
|
|||
public class LogDayLongVirtualRoute:AbstractSimpleShardingDayKeyLongVirtualTableRoute<LogDayLong>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override void Configure(EntityMetadataTableBuilder<LogDayLong> builder)
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace ShardingCore.Test3x.Shardings
|
|||
public class LogDayVirtualTableRoute:AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<LogDay>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override DateTime GetBeginTime()
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace ShardingCore.Test3x.Shardings
|
|||
public class LogMonthLongvirtualRoute:AbstractSimpleShardingMonthKeyLongVirtualTableRoute<LogMonthLong>
|
||||
{
|
||||
protected override bool EnableHintRoute => true;
|
||||
public override bool EnableRouteParseCompileCache => true;
|
||||
public override bool? EnableRouteParseCompileCache => true;
|
||||
|
||||
public override bool AutoCreateTableByTime()
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue