mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-20 10:50:48 +08:00
667 lines
27 KiB
C#
667 lines
27 KiB
C#
// ------------------------------------------------------------------------
|
||
// 版权信息
|
||
// 版权归百小僧及百签科技(广东)有限公司所有。
|
||
// 所有权利保留。
|
||
// 官方网站:https://baiqian.com
|
||
//
|
||
// 许可证信息
|
||
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
|
||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
|
||
// ------------------------------------------------------------------------
|
||
|
||
using System.Collections.Concurrent;
|
||
|
||
using ThingsGateway.Templates;
|
||
|
||
namespace ThingsGateway.Schedule;
|
||
|
||
/// <summary>
|
||
/// 作业触发器基类
|
||
/// </summary>
|
||
public partial class Trigger
|
||
{
|
||
/// <summary>
|
||
/// 计算下一个触发时间
|
||
/// </summary>
|
||
/// <param name="startAt">起始时间</param>
|
||
/// <returns><see cref="DateTime"/></returns>
|
||
public virtual DateTime GetNextOccurrence(DateTime startAt) => throw new NotImplementedException();
|
||
|
||
/// <summary>
|
||
/// 执行条件检查
|
||
/// </summary>
|
||
/// <param name="jobDetail">作业信息</param>
|
||
/// <param name="startAt">起始时间</param>
|
||
/// <returns><see cref="bool"/></returns>
|
||
public virtual bool ShouldRun(JobDetail jobDetail, DateTime startAt)
|
||
{
|
||
return NextRunTime.Value <= startAt
|
||
&& LastRunTime != NextRunTime;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取作业触发器构建器
|
||
/// </summary>
|
||
/// <returns><see cref="TriggerBuilder"/></returns>
|
||
public TriggerBuilder GetBuilder()
|
||
{
|
||
return TriggerBuilder.From(this);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取作业触发器最近运行时间
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public IEnumerable<TriggerTimeline> GetTimelines()
|
||
{
|
||
return Timelines.OrderByDescending(u => u.CreatedTime).ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 作业触发器转字符串输出
|
||
/// </summary>
|
||
/// <returns><see cref="string"/></returns>
|
||
public override string ToString()
|
||
{
|
||
return $"<{JobId} {TriggerId}>{(string.IsNullOrWhiteSpace(Description) ? string.Empty : $" {Description.GetMaxLengthString()}")} {NumberOfRuns}ts";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置启动时最大触发次数等于一次的作业触发器
|
||
/// </summary>
|
||
/// <param name="startAt">起始时间</param>
|
||
internal void ResetMaxNumberOfRunsEqualOnceOnStart(DateTime startAt)
|
||
{
|
||
if (StartNow
|
||
&& ResetOnlyOnce
|
||
&& MaxNumberOfRuns == 1
|
||
&& NumberOfRuns == 1)
|
||
{
|
||
NumberOfRuns = 0;
|
||
SetStatus(TriggerStatus.Ready);
|
||
NextRunTime = CheckRunOnStartAndReturnNextRunTime(startAt);
|
||
|
||
if (MaxNumberOfErrors > 0 && NumberOfErrors >= MaxNumberOfErrors)
|
||
{
|
||
NumberOfErrors = MaxNumberOfErrors - 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录运行信息和计算下一个触发时间
|
||
/// </summary>
|
||
/// <param name="jobDetail">作业信息</param>
|
||
/// <param name="startAt">起始时间</param>
|
||
internal void Increment(JobDetail jobDetail, DateTime startAt)
|
||
{
|
||
// 阻塞状态并没有实际执行,此时忽略次数递增和最近运行时间赋值
|
||
if (Status != TriggerStatus.Blocked)
|
||
{
|
||
NumberOfRuns++;
|
||
// 处理立即执行的情况
|
||
LastRunTime = NextRunTime == null
|
||
? startAt
|
||
: (startAt < NextRunTime.Value
|
||
? startAt
|
||
: NextRunTime);
|
||
}
|
||
|
||
NextRunTime = GetNextRunTime(startAt);
|
||
|
||
// 检查下一次执行信息
|
||
CheckAndFixNextOccurrence(jobDetail, startAt);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录错误信息,包含错误次数和运行状态
|
||
/// </summary>
|
||
/// <param name="jobDetail">作业信息</param>
|
||
/// <param name="startAt">起始时间</param>
|
||
internal void IncrementErrors(JobDetail jobDetail, DateTime startAt)
|
||
{
|
||
NumberOfErrors++;
|
||
|
||
// 检查下一次执行信息
|
||
if (CheckAndFixNextOccurrence(jobDetail, startAt)) SetStatus(TriggerStatus.ErrorToReady);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算下一次运行时间
|
||
/// </summary>
|
||
/// <param name="startAt">起始时间</param>
|
||
/// <returns><see cref="DateTime"/></returns>
|
||
internal DateTime? GetNextRunTime(DateTime startAt)
|
||
{
|
||
// 如果未启动或不是正常的触发器状态,则返回 null
|
||
if (StartNow == false || (Status != TriggerStatus.Backlog
|
||
&& Status != TriggerStatus.Ready
|
||
&& Status != TriggerStatus.ErrorToReady
|
||
&& Status != TriggerStatus.Running
|
||
&& Status != TriggerStatus.Blocked)) return null;
|
||
|
||
// 如果已经设置了 NextRunTime 且其值大于当前时间,则返回当前 NextRunTime(可能因为其他方式修改了该值导致触发时间不是精准计算的时间)
|
||
if (NextRunTime != null && NextRunTime.Value > startAt) return NextRunTime;
|
||
|
||
var baseTime = GetStartAt(startAt);
|
||
if (baseTime == null) return null;
|
||
|
||
// 获取下一次执行时间
|
||
return GetNextOccurrence(baseTime.Value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否启动时执行一次并返回下一次执行时间
|
||
/// </summary>
|
||
/// <param name="startAt">起始时间</param>
|
||
/// <returns><see cref="DateTime"/></returns>
|
||
internal DateTime? CheckRunOnStartAndReturnNextRunTime(DateTime startAt)
|
||
{
|
||
// 检查是否启动时需要执行
|
||
if (!(StartNow && RunOnStart))
|
||
{
|
||
return GetNextRunTime(startAt);
|
||
}
|
||
else
|
||
{
|
||
// 检查是否设置了 RunOnStartProvider 配置
|
||
if (ScheduleOptionsBuilder.InternalRunOnStartProvider is null)
|
||
{
|
||
return (StartTime == null || StartTime.Value <= startAt)
|
||
? startAt.AddSeconds(-1)
|
||
: StartTime;
|
||
}
|
||
|
||
return ScheduleOptionsBuilder.InternalRunOnStartProvider(this, startAt);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置作业触发器状态
|
||
/// </summary>
|
||
/// <param name="status"><see cref="TriggerStatus"/></param>
|
||
internal void SetStatus(TriggerStatus status)
|
||
{
|
||
if (Status == status) return;
|
||
Status = status;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否是正常触发器状态
|
||
/// </summary>
|
||
/// <returns><see cref="bool"/></returns>
|
||
internal bool IsNormalStatus()
|
||
{
|
||
var isNormalStatus = Status != TriggerStatus.Pause
|
||
&& Status != TriggerStatus.Archived
|
||
&& Status != TriggerStatus.Panic
|
||
&& Status != TriggerStatus.Overrun
|
||
&& Status != TriggerStatus.Unoccupied
|
||
&& Status != TriggerStatus.NotStart
|
||
&& Status != TriggerStatus.Unknown
|
||
&& Status != TriggerStatus.Unhandled;
|
||
|
||
// 如果不是正常触发器状态,NextRunTime 强制设置为 null
|
||
if (!isNormalStatus) NextRunTime = null;
|
||
|
||
return isNormalStatus;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查下一次执行信息并修正 <see cref="NextRunTime"/> 和 <see cref="Status"/>
|
||
/// </summary>
|
||
/// <param name="jobDetail">作业信息</param>
|
||
/// <param name="startAt">起始时间</param>
|
||
/// <returns><see cref="bool"/></returns>
|
||
internal bool CheckAndFixNextOccurrence(JobDetail jobDetail, DateTime startAt)
|
||
{
|
||
// 检查作业信息运行时类型
|
||
if (jobDetail.RuntimeJobType == null)
|
||
{
|
||
SetStatus(TriggerStatus.Unhandled);
|
||
NextRunTime = null;
|
||
return false;
|
||
}
|
||
|
||
// 检查作业触发器运行时类型
|
||
if (RuntimeTriggerType == null)
|
||
{
|
||
SetStatus(TriggerStatus.Unknown);
|
||
NextRunTime = null;
|
||
return false;
|
||
}
|
||
|
||
// 检查是否立即启动
|
||
if (StartNow == false)
|
||
{
|
||
SetStatus(TriggerStatus.NotStart);
|
||
NextRunTime = null;
|
||
return false;
|
||
}
|
||
|
||
// 开始时间检查
|
||
if (StartTime != null)
|
||
{
|
||
if (StartTime.Value > startAt)
|
||
{
|
||
SetStatus(TriggerStatus.Backlog);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 结束时间检查
|
||
if (EndTime != null)
|
||
{
|
||
var compareTime = NextRunTime != null ? NextRunTime.Value : startAt;
|
||
if (EndTime.Value < compareTime)
|
||
{
|
||
SetStatus(TriggerStatus.Archived);
|
||
NextRunTime = null;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 最大次数判断
|
||
if (MaxNumberOfRuns > 0 && NumberOfRuns >= MaxNumberOfRuns)
|
||
{
|
||
SetStatus(TriggerStatus.Overrun);
|
||
NextRunTime = null;
|
||
return false;
|
||
}
|
||
|
||
// 最大错误数判断
|
||
if (MaxNumberOfErrors > 0 && NumberOfErrors >= MaxNumberOfErrors)
|
||
{
|
||
SetStatus(TriggerStatus.Panic);
|
||
NextRunTime = null;
|
||
return false;
|
||
}
|
||
|
||
// 状态检查
|
||
if (!IsNormalStatus())
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 下一次运行时间空判断
|
||
if (NextRunTime == null)
|
||
{
|
||
if (IsNormalStatus()) SetStatus(TriggerStatus.Unoccupied);
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 下一次可执行检查
|
||
/// </summary>
|
||
/// <param name="startAt">起始时间</param>
|
||
/// <returns><see cref="bool"/></returns>
|
||
internal bool NextShouldRun(DateTime startAt)
|
||
{
|
||
return IsNormalStatus()
|
||
&& NextRunTime != null
|
||
&& NextRunTime.Value >= startAt;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前可执行检查
|
||
/// </summary>
|
||
/// <param name="jobDetail">作业信息</param>
|
||
/// <param name="startAt">起始时间</param>
|
||
/// <returns><see cref="bool"/></returns>
|
||
internal bool CurrentShouldRun(JobDetail jobDetail, DateTime startAt)
|
||
{
|
||
return CheckAndFixNextOccurrence(jobDetail, startAt)
|
||
// 调用派生类 ShouldRun 方法
|
||
&& ShouldRun(jobDetail, startAt);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录作业触发器运行信息
|
||
/// </summary>
|
||
/// <param name="schedulerFactory">作业计划工厂</param>
|
||
/// <param name="jobId">作业 Id</param>
|
||
/// <param name="exception">异常信息</param>
|
||
/// <returns><see cref="Task"/></returns>
|
||
internal async Task RecordTimelineAsync(ISchedulerFactory schedulerFactory, string jobId, string exception = null)
|
||
{
|
||
Timelines ??= new();
|
||
|
||
// 只保留 5 条记录
|
||
if (Timelines.Count >= 5)
|
||
{
|
||
var _timelines = Timelines.Dequeue();
|
||
_timelines?.Dispose();
|
||
}
|
||
|
||
var timeline = new TriggerTimeline
|
||
{
|
||
JobId = jobId,
|
||
TriggerId = TriggerId,
|
||
LastRunTime = LastRunTime,
|
||
NumberOfRuns = NumberOfRuns,
|
||
NextRunTime = NextRunTime,
|
||
Status = Status,
|
||
Result = Result,
|
||
ElapsedTime = ElapsedTime,
|
||
CreatedTime = DateTime.Now,
|
||
Mode = Mode,
|
||
Exception = exception
|
||
};
|
||
|
||
Timelines.Enqueue(timeline);
|
||
|
||
// 调用事件委托(记录作业触发器运行信息)
|
||
if (schedulerFactory is SchedulerFactory schedulerFactoryInstance)
|
||
{
|
||
// 获取作业计划
|
||
var scheduler = schedulerFactoryInstance.GetJob(jobId);
|
||
if (scheduler is null)
|
||
{
|
||
Timelines.Clear();
|
||
Timelines = null;
|
||
|
||
return;
|
||
}
|
||
|
||
// 初始化作业执行记录持久上下文
|
||
var context = new PersistenceExecutionRecordContext(
|
||
scheduler.GetJobDetail()
|
||
, this
|
||
, timeline.Mode
|
||
, timeline);
|
||
|
||
await schedulerFactoryInstance.RecordTimelineAsync(context).ConfigureAwait(false);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 带命名规则的数据库列名
|
||
/// </summary>
|
||
private readonly NonBlockingDictionary<NamingConventions, string[]> _namingColumnNames = new();
|
||
|
||
/// <summary>
|
||
/// 获取数据库列名
|
||
/// </summary>
|
||
/// <param name="naming">命名法</param>
|
||
/// <returns>string[]</returns>
|
||
private string[] ColumnNames(NamingConventions naming = NamingConventions.CamelCase)
|
||
{
|
||
// 如果字典中已经存在过,则直接返回
|
||
var contains = _namingColumnNames.TryGetValue(naming, out var columnNames);
|
||
if (contains) return columnNames;
|
||
|
||
// 否则创建新的
|
||
var nameColumnNames = new[]
|
||
{
|
||
Penetrates.GetNaming(nameof(TriggerId), naming) // 第一个是标识,禁止移动位置
|
||
, Penetrates.GetNaming(nameof(JobId), naming) // 第二个是作业标识,禁止移动位置
|
||
, Penetrates.GetNaming(nameof(TriggerType), naming)
|
||
, Penetrates.GetNaming(nameof(AssemblyName), naming)
|
||
, Penetrates.GetNaming(nameof(Args), naming)
|
||
, Penetrates.GetNaming(nameof(Description), naming)
|
||
, Penetrates.GetNaming(nameof(Status), naming)
|
||
, Penetrates.GetNaming(nameof(StartTime), naming)
|
||
, Penetrates.GetNaming(nameof(EndTime), naming)
|
||
, Penetrates.GetNaming(nameof(LastRunTime), naming)
|
||
, Penetrates.GetNaming(nameof(NextRunTime), naming)
|
||
, Penetrates.GetNaming(nameof(NumberOfRuns), naming)
|
||
, Penetrates.GetNaming(nameof(MaxNumberOfRuns), naming)
|
||
, Penetrates.GetNaming(nameof(NumberOfErrors), naming)
|
||
, Penetrates.GetNaming(nameof(MaxNumberOfErrors), naming)
|
||
, Penetrates.GetNaming(nameof(NumRetries), naming)
|
||
, Penetrates.GetNaming(nameof(RetryTimeout), naming)
|
||
, Penetrates.GetNaming(nameof(StartNow), naming)
|
||
, Penetrates.GetNaming(nameof(RunOnStart), naming)
|
||
, Penetrates.GetNaming(nameof(ResetOnlyOnce), naming)
|
||
, Penetrates.GetNaming(nameof(Result), naming)
|
||
, Penetrates.GetNaming(nameof(ElapsedTime), naming)
|
||
, Penetrates.GetNaming(nameof(UpdatedTime), naming)
|
||
};
|
||
_ = _namingColumnNames.TryAdd(naming, nameColumnNames);
|
||
|
||
return nameColumnNames;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取触发器初始化时间
|
||
/// </summary>
|
||
/// <param name="startAt">起始时间</param>
|
||
/// <returns><see cref="DateTime"/> 或者 null</returns>
|
||
private DateTime? GetStartAt(DateTime startAt)
|
||
{
|
||
if (StartTime == null)
|
||
{
|
||
if (EndTime == null) return startAt;
|
||
else return EndTime.Value < startAt ? null : startAt;
|
||
}
|
||
else return StartTime.Value < startAt ? startAt : StartTime.Value;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换成 Sql 语句
|
||
/// </summary>
|
||
/// <param name="tableName">数据库表名</param>
|
||
/// <param name="behavior">持久化行为</param>
|
||
/// <param name="naming">命名法</param>
|
||
/// <returns><see cref="string"/></returns>
|
||
public string ConvertToSQL(string tableName, PersistenceBehavior behavior, NamingConventions naming = NamingConventions.CamelCase)
|
||
{
|
||
// 判断是否自定义了 SQL 输出程序
|
||
if (TriggerOptions.ConvertToSQLConfigure != null)
|
||
{
|
||
return TriggerOptions.ConvertToSQLConfigure(tableName, ColumnNames(naming), this, behavior, naming);
|
||
}
|
||
|
||
// 生成新增 SQL
|
||
if (behavior == PersistenceBehavior.Appended)
|
||
{
|
||
return ConvertToInsertSQL(tableName, naming);
|
||
}
|
||
// 生成更新 SQL
|
||
else if (behavior == PersistenceBehavior.Updated)
|
||
{
|
||
return ConvertToUpdateSQL(tableName, naming);
|
||
}
|
||
// 生成删除 SQL
|
||
else if (behavior == PersistenceBehavior.Removed)
|
||
{
|
||
return ConvertToDeleteSQL(tableName, naming);
|
||
}
|
||
|
||
return string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换成 Sql 新增语句
|
||
/// </summary>
|
||
/// <param name="tableName">数据库表名</param>
|
||
/// <param name="naming">命名法</param>
|
||
/// <returns><see cref="string"/></returns>
|
||
public string ConvertToInsertSQL(string tableName, NamingConventions naming = NamingConventions.CamelCase)
|
||
{
|
||
// 不使用反射生成,为了使顺序可控,生成 SQL 可控,性能损耗最小
|
||
var columnNames = ColumnNames(naming);
|
||
|
||
return $@"INSERT INTO {Penetrates.WrapDatabaseFieldName(tableName)}(
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[0])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[1])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[2])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[3])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[4])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[5])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[6])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[7])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[8])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[9])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[10])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[11])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[12])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[13])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[14])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[15])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[16])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[17])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[18])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[19])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[20])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[21])},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[22])}
|
||
)
|
||
VALUES(
|
||
{Penetrates.GetNoNumberSqlValueOrNull(TriggerId)},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(JobId)},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(TriggerType)},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(AssemblyName)},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(Args)},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(Description)},
|
||
{((int)Status)},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(StartTime.ToFormatString())},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(EndTime.ToFormatString())},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(LastRunTime.ToFormatString())},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(NextRunTime.ToFormatString())},
|
||
{NumberOfRuns},
|
||
{MaxNumberOfRuns},
|
||
{NumberOfErrors},
|
||
{MaxNumberOfErrors},
|
||
{NumRetries},
|
||
{RetryTimeout},
|
||
{Penetrates.GetBooleanSqlValue(StartNow)},
|
||
{Penetrates.GetBooleanSqlValue(RunOnStart)},
|
||
{Penetrates.GetBooleanSqlValue(ResetOnlyOnce)},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(Result)},
|
||
{ElapsedTime},
|
||
{Penetrates.GetNoNumberSqlValueOrNull(UpdatedTime.ToFormatString())}
|
||
);";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换成 Sql 更新语句
|
||
/// </summary>
|
||
/// <param name="tableName">数据库表名</param>
|
||
/// <param name="naming">命名法</param>
|
||
/// <returns><see cref="string"/></returns>
|
||
public string ConvertToUpdateSQL(string tableName, NamingConventions naming = NamingConventions.CamelCase)
|
||
{
|
||
// 不使用反射生成,为了使顺序可控,生成 SQL 可控,性能损耗最小
|
||
var columnNames = ColumnNames(naming);
|
||
|
||
return $@"UPDATE {Penetrates.WrapDatabaseFieldName(tableName)}
|
||
SET
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[0])} = {Penetrates.GetNoNumberSqlValueOrNull(TriggerId)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[1])} = {Penetrates.GetNoNumberSqlValueOrNull(JobId)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[2])} = {Penetrates.GetNoNumberSqlValueOrNull(TriggerType)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[3])} = {Penetrates.GetNoNumberSqlValueOrNull(AssemblyName)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[4])} = {Penetrates.GetNoNumberSqlValueOrNull(Args)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[5])} = {Penetrates.GetNoNumberSqlValueOrNull(Description)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[6])} = {((int)Status)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[7])} = {Penetrates.GetNoNumberSqlValueOrNull(StartTime.ToFormatString())},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[8])} = {Penetrates.GetNoNumberSqlValueOrNull(EndTime.ToFormatString())},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[9])} = {Penetrates.GetNoNumberSqlValueOrNull(LastRunTime.ToFormatString())},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[10])} = {Penetrates.GetNoNumberSqlValueOrNull(NextRunTime.ToFormatString())},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[11])} = {NumberOfRuns},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[12])} = {MaxNumberOfRuns},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[13])} = {NumberOfErrors},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[14])} = {MaxNumberOfErrors},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[15])} = {NumRetries},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[16])} = {RetryTimeout},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[17])} = {Penetrates.GetBooleanSqlValue(StartNow)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[18])} = {Penetrates.GetBooleanSqlValue(RunOnStart)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[19])} = {Penetrates.GetBooleanSqlValue(ResetOnlyOnce)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[20])} = {Penetrates.GetNoNumberSqlValueOrNull(Result)},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[21])} = {ElapsedTime},
|
||
{Penetrates.WrapDatabaseFieldName(columnNames[22])} = {Penetrates.GetNoNumberSqlValueOrNull(UpdatedTime.ToFormatString())}
|
||
WHERE {Penetrates.WrapDatabaseFieldName(columnNames[0])} = {Penetrates.GetNoNumberSqlValueOrNull(TriggerId)} AND {Penetrates.WrapDatabaseFieldName(columnNames[1])} = {Penetrates.GetNoNumberSqlValueOrNull(JobId)};";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换成 Sql 删除语句
|
||
/// </summary>
|
||
/// <param name="tableName">数据库表名</param>
|
||
/// <param name="naming">命名法</param>
|
||
/// <returns><see cref="string"/></returns>
|
||
public string ConvertToDeleteSQL(string tableName, NamingConventions naming = NamingConventions.CamelCase)
|
||
{
|
||
// 不使用反射生成,为了使顺序可控,生成 SQL 可控,性能损耗最小
|
||
var columnNames = ColumnNames(naming);
|
||
|
||
return $@"DELETE FROM {Penetrates.WrapDatabaseFieldName(tableName)}
|
||
WHERE {Penetrates.WrapDatabaseFieldName(columnNames[0])} = {Penetrates.GetNoNumberSqlValueOrNull(TriggerId)} AND {Penetrates.WrapDatabaseFieldName(columnNames[1])} = {Penetrates.GetNoNumberSqlValueOrNull(JobId)};";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换成 JSON 字符串
|
||
/// </summary>
|
||
/// <param name="naming">命名法</param>
|
||
/// <returns><see cref="string"/></returns>
|
||
public string ConvertToJSON(NamingConventions naming = NamingConventions.CamelCase)
|
||
{
|
||
return Penetrates.Write(writer =>
|
||
{
|
||
writer.WriteStartObject();
|
||
|
||
writer.WriteString(Penetrates.GetNaming(nameof(TriggerId), naming), TriggerId);
|
||
writer.WriteString(Penetrates.GetNaming(nameof(JobId), naming), JobId);
|
||
writer.WriteString(Penetrates.GetNaming(nameof(TriggerType), naming), TriggerType);
|
||
writer.WriteString(Penetrates.GetNaming(nameof(AssemblyName), naming), AssemblyName);
|
||
writer.WriteString(Penetrates.GetNaming(nameof(Args), naming), Args);
|
||
writer.WriteString(Penetrates.GetNaming(nameof(Description), naming), Description);
|
||
writer.WriteNumber(Penetrates.GetNaming(nameof(Status), naming), (int)Status);
|
||
writer.WriteString(Penetrates.GetNaming(nameof(StartTime), naming), StartTime.ToFormatString());
|
||
writer.WriteString(Penetrates.GetNaming(nameof(EndTime), naming), EndTime.ToFormatString());
|
||
writer.WriteString(Penetrates.GetNaming(nameof(LastRunTime), naming), LastRunTime.ToFormatString());
|
||
writer.WriteString(Penetrates.GetNaming(nameof(NextRunTime), naming), NextRunTime.ToFormatString());
|
||
writer.WriteNumber(Penetrates.GetNaming(nameof(NumberOfRuns), naming), NumberOfRuns);
|
||
writer.WriteNumber(Penetrates.GetNaming(nameof(MaxNumberOfRuns), naming), MaxNumberOfRuns);
|
||
writer.WriteNumber(Penetrates.GetNaming(nameof(NumberOfErrors), naming), NumberOfErrors);
|
||
writer.WriteNumber(Penetrates.GetNaming(nameof(MaxNumberOfErrors), naming), MaxNumberOfErrors);
|
||
writer.WriteNumber(Penetrates.GetNaming(nameof(NumRetries), naming), NumRetries);
|
||
writer.WriteNumber(Penetrates.GetNaming(nameof(RetryTimeout), naming), RetryTimeout);
|
||
writer.WriteBoolean(Penetrates.GetNaming(nameof(StartNow), naming), StartNow);
|
||
writer.WriteBoolean(Penetrates.GetNaming(nameof(RunOnStart), naming), RunOnStart);
|
||
writer.WriteBoolean(Penetrates.GetNaming(nameof(ResetOnlyOnce), naming), ResetOnlyOnce);
|
||
writer.WriteString(Penetrates.GetNaming(nameof(Result), naming), Result);
|
||
writer.WriteNumber(Penetrates.GetNaming(nameof(ElapsedTime), naming), ElapsedTime);
|
||
writer.WriteString(Penetrates.GetNaming(nameof(UpdatedTime), naming), UpdatedTime.ToFormatString());
|
||
|
||
writer.WriteEndObject();
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换成 Monitor 字符串
|
||
/// </summary>
|
||
/// <param name="naming">命名法</param>
|
||
/// <returns><see cref="string"/></returns>
|
||
public string ConvertToMonitor(NamingConventions naming = NamingConventions.CamelCase)
|
||
{
|
||
return TP.Wrapper(nameof(Trigger), Description ?? TriggerType, new[]
|
||
{
|
||
$"##{Penetrates.GetNaming(nameof(TriggerId), naming)}## {TriggerId}"
|
||
, $"##{Penetrates.GetNaming(nameof(JobId), naming)}## {JobId}"
|
||
, $"##{Penetrates.GetNaming(nameof(TriggerType), naming)}## {TriggerType}"
|
||
, $"##{Penetrates.GetNaming(nameof(AssemblyName), naming)}## {AssemblyName}"
|
||
, $"##{Penetrates.GetNaming(nameof(Args), naming)}## {Args}"
|
||
, $"##{Penetrates.GetNaming(nameof(Description), naming)}## {Description}"
|
||
, $"##{Penetrates.GetNaming(nameof(Status), naming)}## {Status}"
|
||
, $"##{Penetrates.GetNaming(nameof(StartTime), naming)}## {StartTime.ToFormatString()}"
|
||
, $"##{Penetrates.GetNaming(nameof(EndTime), naming)}## {EndTime.ToFormatString()}"
|
||
, $"##{Penetrates.GetNaming(nameof(LastRunTime), naming)}## {LastRunTime.ToFormatString()}"
|
||
, $"##{Penetrates.GetNaming(nameof(NextRunTime), naming)}## {NextRunTime.ToFormatString()}"
|
||
, $"##{Penetrates.GetNaming(nameof(NumberOfRuns), naming)}## {NumberOfRuns}"
|
||
, $"##{Penetrates.GetNaming(nameof(MaxNumberOfRuns), naming)}## {MaxNumberOfRuns}"
|
||
, $"##{Penetrates.GetNaming(nameof(NumberOfErrors), naming)}## {NumberOfErrors}"
|
||
, $"##{Penetrates.GetNaming(nameof(MaxNumberOfErrors), naming)}## {MaxNumberOfErrors}"
|
||
, $"##{Penetrates.GetNaming(nameof(NumRetries), naming)}## {NumRetries}"
|
||
, $"##{Penetrates.GetNaming(nameof(RetryTimeout), naming)}## {RetryTimeout}"
|
||
, $"##{Penetrates.GetNaming(nameof(StartNow), naming)}## {StartNow}"
|
||
, $"##{Penetrates.GetNaming(nameof(RunOnStart), naming)}## {RunOnStart}"
|
||
, $"##{Penetrates.GetNaming(nameof(ResetOnlyOnce), naming)}## {ResetOnlyOnce}"
|
||
, $"##{Penetrates.GetNaming(nameof(Result), naming)}## {Result}"
|
||
, $"##{Penetrates.GetNaming(nameof(ElapsedTime), naming)}## {ElapsedTime}"
|
||
, $"##{Penetrates.GetNaming(nameof(UpdatedTime), naming)}## {UpdatedTime.ToFormatString()}"
|
||
});
|
||
}
|
||
} |