Files
ThingsGateway/src/Admin/ThingsGateway.Furion/Schedule/Details/JobDetail.Methods.cs
2025-10-15 17:40:33 +08:00

355 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ------------------------------------------------------------------------
// 版权信息
// 版权归百小僧及百签科技(广东)有限公司所有。
// 所有权利保留。
// 官方网站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()}"
});
}
}