mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-27 21:57:10 +08:00
355 lines
14 KiB
C#
355 lines
14 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 JobDetail
|
||
{
|
||
/// <summary>
|
||
/// 获取作业所有额外数据
|
||
/// </summary>
|
||
/// <returns><see cref="Dictionary{String,Object}"/></returns>
|
||
public Dictionary<string, object> GetProperties()
|
||
{
|
||
return RuntimeProperties;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查作业信息额外数据键是否存在
|
||
/// </summary>
|
||
/// <param name="key">键</param>
|
||
/// <returns><see cref="bool"/></returns>
|
||
public bool ContainsProperty(string key)
|
||
{
|
||
// 空检查
|
||
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
|
||
|
||
return RuntimeProperties.ContainsKey(key);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取作业信息额外数据
|
||
/// </summary>
|
||
/// <param name="key">键</param>
|
||
/// <returns><see cref="object"/></returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取作业信息额外数据
|
||
/// </summary>
|
||
/// <typeparam name="T">结果泛型类型</typeparam>
|
||
/// <param name="key">键</param>
|
||
/// <returns>T 类型</returns>
|
||
public T GetProperty<T>(string key)
|
||
{
|
||
var value = GetProperty(key);
|
||
if (value == null) return default;
|
||
return (T)value;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加作业信息额外数据
|
||
/// </summary>
|
||
/// <param name="key">键</param>
|
||
/// <param name="value">值</param>
|
||
/// <returns><see cref="JobDetail"/></returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加或更新作业信息额外数据
|
||
/// </summary>
|
||
/// <typeparam name="T">值类型</typeparam>
|
||
/// <param name="key">键</param>
|
||
/// <param name="newValue">新值</param>
|
||
/// <param name="updateAction">更新委托,如果传递了该参数,那么键存在使则使用该参数的返回值</param>
|
||
/// <returns><see cref="JobDetail"/></returns>
|
||
public JobDetail AddOrUpdateProperty<T>(string key, T newValue, Func<T, object> 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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除作业信息额外数据
|
||
/// </summary>
|
||
/// <param name="key">键</param>
|
||
/// <returns><see cref="JobDetail"/></returns>
|
||
public JobDetail RemoveProperty(string key)
|
||
{
|
||
// 空检查
|
||
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
|
||
|
||
if (RuntimeProperties.Remove(key))
|
||
{
|
||
Properties = Penetrates.Serialize(RuntimeProperties);
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空作业信息额外数据
|
||
/// </summary>
|
||
/// <returns><see cref="JobDetail"/></returns>
|
||
public JobDetail ClearProperties()
|
||
{
|
||
RuntimeProperties.Clear();
|
||
Properties = Penetrates.Serialize(RuntimeProperties);
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取作业信息构建器
|
||
/// </summary>
|
||
/// <returns><see cref="JobBuilder"/></returns>
|
||
public JobBuilder GetBuilder()
|
||
{
|
||
return JobBuilder.From(this);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 作业信息转字符串输出
|
||
/// </summary>
|
||
/// <returns><see cref="string"/></returns>
|
||
public override string ToString()
|
||
{
|
||
return $"<{JobId}>{(string.IsNullOrWhiteSpace(Description) ? string.Empty : $" {Description.GetMaxLengthString()}")} [{(Concurrent ? "C" : "S")}]";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 带命名规则的数据库列名
|
||
/// </summary>
|
||
private readonly NonBlockingDictionary<NamingConventions, string[]> _namingColumnNames = new();
|
||
|
||
/// <summary>
|
||
/// 获取数据库列名
|
||
/// </summary>
|
||
/// <remarks>避免多次反射</remarks>
|
||
/// <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(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;
|
||
}
|
||
|
||
/// <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 (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;
|
||
}
|
||
|
||
/// <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])}
|
||
)
|
||
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())}
|
||
);";
|
||
}
|
||
|
||
/// <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(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)};";
|
||
}
|
||
|
||
/// <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(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(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();
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换成 Monitor 字符串
|
||
/// </summary>
|
||
/// <param name="naming">命名法</param>
|
||
/// <returns><see cref="string"/></returns>
|
||
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()}"
|
||
});
|
||
}
|
||
} |