// ------------------------------------------------------------------------
// 版权信息
// 版权归百小僧及百签科技(广东)有限公司所有。
// 所有权利保留。
// 官方网站:https://baiqian.com
//
// 许可证信息
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------
using System.Collections.Concurrent;
using ThingsGateway.Templates;
namespace ThingsGateway.Schedule;
///
/// 作业信息
///
public partial class JobDetail
{
///
/// 获取作业所有额外数据
///
///
public Dictionary GetProperties()
{
return RuntimeProperties;
}
///
/// 检查作业信息额外数据键是否存在
///
/// 键
///
public bool ContainsProperty(string key)
{
// 空检查
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
return RuntimeProperties.ContainsKey(key);
}
///
/// 获取作业信息额外数据
///
/// 键
///
public object GetProperty(string key)
{
// 空检查
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
if (RuntimeProperties.TryGetValue(key, out var value))
{
return value;
}
return default;
}
///
/// 获取作业信息额外数据
///
/// 结果泛型类型
/// 键
/// T 类型
public T GetProperty(string key)
{
var value = GetProperty(key);
if (value == null) return default;
return (T)value;
}
///
/// 添加作业信息额外数据
///
/// 键
/// 值
///
public JobDetail AddProperty(string key, object value)
{
// 空检查
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
RuntimeProperties.TryAdd(key, value);
Properties = Penetrates.Serialize(RuntimeProperties);
return this;
}
///
/// 添加或更新作业信息额外数据
///
/// 值类型
/// 键
/// 新值
/// 更新委托,如果传递了该参数,那么键存在使则使用该参数的返回值
///
public JobDetail AddOrUpdateProperty(string key, T newValue, Func updateAction = default)
{
// 空检查
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
if (RuntimeProperties.TryGetValue(key, out var existingValue))
{
RuntimeProperties[key] = updateAction == null
? newValue
: updateAction((T)existingValue);
}
else RuntimeProperties.TryAdd(key, newValue);
Properties = Penetrates.Serialize(RuntimeProperties);
return this;
}
///
/// 删除作业信息额外数据
///
/// 键
///
public JobDetail RemoveProperty(string key)
{
// 空检查
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
if (RuntimeProperties.Remove(key))
{
Properties = Penetrates.Serialize(RuntimeProperties);
}
return this;
}
///
/// 清空作业信息额外数据
///
///
public JobDetail ClearProperties()
{
RuntimeProperties.Clear();
Properties = Penetrates.Serialize(RuntimeProperties);
return this;
}
///
/// 获取作业信息构建器
///
///
public JobBuilder GetBuilder()
{
return JobBuilder.From(this);
}
///
/// 作业信息转字符串输出
///
///
public override string ToString()
{
return $"<{JobId}>{(string.IsNullOrWhiteSpace(Description) ? string.Empty : $" {Description.GetMaxLengthString()}")} [{(Concurrent ? "C" : "S")}]";
}
///
/// 带命名规则的数据库列名
///
private readonly NonBlockingDictionary _namingColumnNames = new();
///
/// 获取数据库列名
///
/// 避免多次反射
/// string[]
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(JobId), naming) // 第一个是标识,禁止移动位置
, Penetrates.GetNaming(nameof(GroupName), naming)
, Penetrates.GetNaming(nameof(JobType), naming)
, Penetrates.GetNaming(nameof(AssemblyName), naming)
, Penetrates.GetNaming(nameof(Description), naming)
, Penetrates.GetNaming(nameof(Concurrent), naming)
, Penetrates.GetNaming(nameof(IncludeAnnotations), naming)
, Penetrates.GetNaming(nameof(Properties), naming)
, Penetrates.GetNaming(nameof(UpdatedTime), naming)
};
_ = _namingColumnNames.TryAdd(naming, nameColumnNames);
return nameColumnNames;
}
///
/// 转换成 Sql 语句
///
/// 数据库表名
/// 持久化行为
/// 命名法
///
public string ConvertToSQL(string tableName, PersistenceBehavior behavior, NamingConventions naming = NamingConventions.CamelCase)
{
// 判断是否自定义了 SQL 输出程序
if (JobDetailOptions.ConvertToSQLConfigure != null)
{
return JobDetailOptions.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;
}
///
/// 转换成 Sql 新增语句
///
/// 数据库表名
/// 命名法
///
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])}
)
VALUES(
{Penetrates.GetNoNumberSqlValueOrNull(JobId)},
{Penetrates.GetNoNumberSqlValueOrNull(GroupName)},
{Penetrates.GetNoNumberSqlValueOrNull(JobType)},
{Penetrates.GetNoNumberSqlValueOrNull(AssemblyName)},
{Penetrates.GetNoNumberSqlValueOrNull(Description)},
{Penetrates.GetBooleanSqlValue(Concurrent)},
{Penetrates.GetBooleanSqlValue(IncludeAnnotations)},
{Penetrates.GetNoNumberSqlValueOrNull(Properties)},
{Penetrates.GetNoNumberSqlValueOrNull(UpdatedTime.ToFormatString())}
);";
}
///
/// 转换成 Sql 更新语句
///
/// 数据库表名
/// 命名法
///
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(JobId)},
{Penetrates.WrapDatabaseFieldName(columnNames[1])} = {Penetrates.GetNoNumberSqlValueOrNull(GroupName)},
{Penetrates.WrapDatabaseFieldName(columnNames[2])} = {Penetrates.GetNoNumberSqlValueOrNull(JobType)},
{Penetrates.WrapDatabaseFieldName(columnNames[3])} = {Penetrates.GetNoNumberSqlValueOrNull(AssemblyName)},
{Penetrates.WrapDatabaseFieldName(columnNames[4])} = {Penetrates.GetNoNumberSqlValueOrNull(Description)},
{Penetrates.WrapDatabaseFieldName(columnNames[5])} = {Penetrates.GetBooleanSqlValue(Concurrent)},
{Penetrates.WrapDatabaseFieldName(columnNames[6])} = {Penetrates.GetBooleanSqlValue(IncludeAnnotations)},
{Penetrates.WrapDatabaseFieldName(columnNames[7])} = {Penetrates.GetNoNumberSqlValueOrNull(Properties)},
{Penetrates.WrapDatabaseFieldName(columnNames[8])} = {Penetrates.GetNoNumberSqlValueOrNull(UpdatedTime.ToFormatString())}
WHERE {Penetrates.WrapDatabaseFieldName(columnNames[0])} = {Penetrates.GetNoNumberSqlValueOrNull(JobId)};";
}
///
/// 转换成 Sql 删除语句
///
/// 数据库表名
/// 命名法
///
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(JobId)};";
}
///
/// 转换成 JSON 字符串
///
/// 命名法
///
public string ConvertToJSON(NamingConventions naming = NamingConventions.CamelCase)
{
return Penetrates.Write(writer =>
{
writer.WriteStartObject();
writer.WriteString(Penetrates.GetNaming(nameof(JobId), naming), JobId);
writer.WriteString(Penetrates.GetNaming(nameof(GroupName), naming), GroupName);
writer.WriteString(Penetrates.GetNaming(nameof(JobType), naming), JobType);
writer.WriteString(Penetrates.GetNaming(nameof(AssemblyName), naming), AssemblyName);
writer.WriteString(Penetrates.GetNaming(nameof(Description), naming), Description);
writer.WriteBoolean(Penetrates.GetNaming(nameof(Concurrent), naming), Concurrent);
writer.WriteBoolean(Penetrates.GetNaming(nameof(IncludeAnnotations), naming), IncludeAnnotations);
writer.WriteString(Penetrates.GetNaming(nameof(Properties), naming), Properties);
writer.WriteString(Penetrates.GetNaming(nameof(UpdatedTime), naming), UpdatedTime.ToFormatString());
writer.WriteEndObject();
});
}
///
/// 转换成 Monitor 字符串
///
/// 命名法
///
public string ConvertToMonitor(NamingConventions naming = NamingConventions.CamelCase)
{
return TP.Wrapper(nameof(JobDetail), Description ?? JobType, new[]
{
$"##{Penetrates.GetNaming(nameof(JobId), naming)}## {JobId}"
, $"##{Penetrates.GetNaming(nameof(GroupName), naming)}## {GroupName}"
, $"##{Penetrates.GetNaming(nameof(JobType), naming)}## {JobType}"
, $"##{Penetrates.GetNaming(nameof(AssemblyName), naming)}## {AssemblyName}"
, $"##{Penetrates.GetNaming(nameof(Description), naming)}## {Description}"
, $"##{Penetrates.GetNaming(nameof(Concurrent), naming)}## {Concurrent}"
, $"##{Penetrates.GetNaming(nameof(IncludeAnnotations), naming)}## {IncludeAnnotations}"
, $"##{Penetrates.GetNaming(nameof(Properties), naming)}## {Properties}"
, $"##{Penetrates.GetNaming(nameof(UpdatedTime), naming)}## {UpdatedTime.ToFormatString()}"
});
}
}