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