// ============================================================================ // 【文件说明】HwPortalConfigService.cs - 门户配置服务类 // ============================================================================ // 这个服务类负责处理门户配置的业务逻辑,包括: // - 门户配置的 CRUD 操作 // - 关联查询(配置 + 配置类型) // - 空字符串规范化处理 // // 【业务背景】 // 门户配置模块用于管理网站首页的各种配置项,如轮播图、推荐内容等。 // 支持关联查询配置类型信息。 // // 【与 Java Spring Boot 的对比】 // Java Spring Boot: // @Service // public class HwPortalConfigServiceImpl implements HwPortalConfigService { ... } // // ASP.NET Core + Furion: // public class HwPortalConfigService : ITransient { ... } // ============================================================================ namespace Admin.NET.Plugin.HwPortal; /// /// 门户配置服务类。 /// /// 【服务职责】 /// 1. 管理门户配置的增删改查 /// 2. 支持关联查询配置类型信息 /// 3. 处理空字符串规范化 /// /// /// 【特殊类型处理】 /// 当 PortalConfigType 为 "2" 时,使用 JOIN 查询关联 HwPortalConfigType 表, /// 返回包含配置类型名称等附加信息的结果。 /// /// public class HwPortalConfigService : ITransient { /// /// MyBatis 映射器名称(保留用于回滚)。 /// private const string Mapper = "HwPortalConfigMapper"; /// /// MyBatis 执行器(保留用于回滚)。 /// private readonly HwPortalMyBatisExecutor _executor; /// /// SqlSugar 数据访问对象。 /// private readonly ISqlSugarClient _db; /// /// 构造函数(依赖注入)。 /// /// MyBatis 执行器 /// SqlSugar 数据访问对象 public HwPortalConfigService(HwPortalMyBatisExecutor executor, ISqlSugarClient db) { _executor = executor; _db = db; } /// /// 根据配置ID查询门户配置。 /// /// 配置ID /// 门户配置实体 public async Task SelectHwPortalConfigByPortalConfigId(long portalConfigId) { // 回滚到 XML 方案时可直接恢复: // return await _executor.QuerySingleAsync(Mapper, "selectHwPortalConfigByPortalConfigId", new { portalConfigId }); return await _db.Queryable() .Where(item => item.PortalConfigId == portalConfigId) .FirstAsync(); } /// /// 查询门户配置列表。 /// /// 【特殊类型处理】 /// 当 PortalConfigType 为 "2"(HwPortalConstants.PortalConfigTypeTwo)时, /// 使用 BuildPortalConfigJoinQuery 方法进行 JOIN 查询, /// 返回包含配置类型名称等附加信息的结果。 /// /// /// 【动态查询条件】 /// 支持按配置类型、类型ID、标题、排序号、描述、按钮名、路由地址、图片等条件筛选。 /// /// /// 查询条件 /// 门户配置列表 public async Task> SelectHwPortalConfigList(HwPortalConfig input) { HwPortalConfig query = input ?? new HwPortalConfig(); // 【特殊类型处理】 // 当配置类型为 "2" 时,使用 JOIN 查询关联配置类型表 if (string.Equals(HwPortalConstants.PortalConfigTypeTwo, query.PortalConfigType, StringComparison.Ordinal)) { // 回滚到 XML 方案时可直接恢复: // return await _executor.QueryListAsync(Mapper, "selectHwPortalConfigList2", query); return await BuildPortalConfigJoinQuery(query).ToListAsync(); } // 【普通查询】 // 回滚到 XML 方案时可直接恢复: // return await _executor.QueryListAsync(Mapper, "selectHwPortalConfigList", query); return await _db.Queryable() .WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigType), item => item.PortalConfigType == query.PortalConfigType) .WhereIF(query.PortalConfigTypeId.HasValue, item => item.PortalConfigTypeId == query.PortalConfigTypeId) .WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigTitle), item => item.PortalConfigTitle.Contains(query.PortalConfigTitle)) .WhereIF(query.PortalConfigOrder.HasValue, item => item.PortalConfigOrder == query.PortalConfigOrder) .WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigDesc), item => item.PortalConfigDesc == query.PortalConfigDesc) .WhereIF(!string.IsNullOrWhiteSpace(query.ButtonName), item => item.ButtonName.Contains(query.ButtonName)) .WhereIF(!string.IsNullOrWhiteSpace(query.RouterAddress), item => item.RouterAddress == query.RouterAddress) .WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigPic), item => item.PortalConfigPic == query.PortalConfigPic) .ToListAsync(); } /// /// 新增门户配置。 /// /// 【空字符串规范化】 /// Why:这里只把原 XML 会忽略的空串字段转成 null, /// 其它字段继续保留调用方原值,避免语义漂移。 /// /// /// 门户配置数据 /// 影响行数 public async Task InsertHwPortalConfig(HwPortalConfig input) { // 【数据规范化】 // 将空字符串转为 null,与 XML 方案保持一致 input.PortalConfigType = NormalizeEmptyToNull(input.PortalConfigType); input.PortalConfigTitle = NormalizeEmptyToNull(input.PortalConfigTitle); input.PortalConfigPic = NormalizeEmptyToNull(input.PortalConfigPic); // 【审计字段】 input.CreateTime = HwPortalContextHelper.Now(); // 回滚到 XML 方案时可直接恢复: // long identity = await _executor.InsertReturnIdentityAsync(Mapper, "insertHwPortalConfig", input); HwPortalConfig entity = await _db.Insertable(input).ExecuteReturnEntityAsync(); input.PortalConfigId = entity.PortalConfigId; return input.PortalConfigId > 0 ? 1 : 0; } /// /// 更新门户配置。 /// /// 【字段级更新策略】 /// 只更新输入对象中不为 null 或不为空的字段。 /// /// /// 更新的数据 /// 影响行数 public async Task UpdateHwPortalConfig(HwPortalConfig input) { // 【审计字段】 input.UpdateTime = HwPortalContextHelper.Now(); // 回滚到 XML 方案时可直接恢复: // return await _executor.ExecuteAsync(Mapper, "updateHwPortalConfig", input); HwPortalConfig current = await SelectHwPortalConfigByPortalConfigId(input.PortalConfigId ?? 0); if (current == null) { return 0; } // 【配置类型】 if (!string.IsNullOrWhiteSpace(input.PortalConfigType)) { current.PortalConfigType = input.PortalConfigType; } // 【类型ID】 if (input.PortalConfigTypeId.HasValue) { current.PortalConfigTypeId = input.PortalConfigTypeId; } // 【标题】 if (!string.IsNullOrWhiteSpace(input.PortalConfigTitle)) { current.PortalConfigTitle = input.PortalConfigTitle; } // 【排序号】 if (input.PortalConfigOrder.HasValue) { current.PortalConfigOrder = input.PortalConfigOrder; } // 【描述】 if (input.PortalConfigDesc != null) { current.PortalConfigDesc = input.PortalConfigDesc; } // 【按钮名】 if (input.ButtonName != null) { current.ButtonName = input.ButtonName; } // 【路由地址】 if (input.RouterAddress != null) { current.RouterAddress = input.RouterAddress; } // 【图片】 if (!string.IsNullOrWhiteSpace(input.PortalConfigPic)) { current.PortalConfigPic = input.PortalConfigPic; } // 【审计字段】 if (input.CreateTime.HasValue) { current.CreateTime = input.CreateTime; } if (input.CreateBy != null) { current.CreateBy = input.CreateBy; } current.UpdateTime = input.UpdateTime; if (input.UpdateBy != null) { current.UpdateBy = input.UpdateBy; } return await _db.Updateable(current).ExecuteCommandAsync(); } /// /// 批量删除门户配置。 /// /// 配置ID数组 /// 影响行数 public async Task DeleteHwPortalConfigByPortalConfigIds(long[] portalConfigIds) { // 回滚到 XML 方案时可直接恢复: // return await _executor.ExecuteAsync(Mapper, "deleteHwPortalConfigByPortalConfigIds", new { array = portalConfigIds }); return await _db.Deleteable() .In(portalConfigIds) .ExecuteCommandAsync(); } /// /// 查询门户配置关联列表(JOIN查询)。 /// /// 【关联查询】 /// 使用 BuildPortalConfigJoinQuery 方法进行 JOIN 查询, /// 返回包含配置类型信息的完整结果。 /// /// /// 查询条件 /// 门户配置列表(含类型信息) public async Task> SelectHwPortalConfigJoinList(HwPortalConfig input) { HwPortalConfig query = input ?? new HwPortalConfig(); // 回滚到 XML 方案时可直接恢复: // return await _executor.QueryListAsync(Mapper, "selectHwPortalConfigJoinList", query); return await BuildPortalConfigJoinQuery(query).ToListAsync(); } /// /// 构建门户配置 JOIN 查询。 /// /// 【SqlSugar JOIN 查询】 /// 使用 SqlSugar 的 Queryable 进行左连接(Left Join)查询, /// 关联 HwPortalConfigType 表获取配置类型信息。 /// /// /// 【字段投影】 /// Why:这里统一把关联侧字段一起投影出来,避免 provider 对条件投影翻译不稳定。 /// 对不需要这些字段的调用方来说,多出冗余属性不会改变行为,但能明显降低切换风险。 /// /// /// 查询条件 /// JOIN 查询对象 private ISugarQueryable BuildPortalConfigJoinQuery(HwPortalConfig query) { return _db.Queryable((config, configType) => new JoinQueryInfos(JoinType.Left, config.PortalConfigTypeId == configType.ConfigTypeId)) .WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigType), (config, _) => config.PortalConfigType == query.PortalConfigType) .WhereIF(query.PortalConfigTypeId.HasValue, (config, _) => config.PortalConfigTypeId == query.PortalConfigTypeId) .WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigTitle), (config, _) => config.PortalConfigTitle.Contains(query.PortalConfigTitle)) .WhereIF(query.PortalConfigOrder.HasValue, (config, _) => config.PortalConfigOrder == query.PortalConfigOrder) .WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigDesc), (config, _) => config.PortalConfigDesc == query.PortalConfigDesc) .WhereIF(!string.IsNullOrWhiteSpace(query.ButtonName), (config, _) => config.ButtonName.Contains(query.ButtonName)) .WhereIF(!string.IsNullOrWhiteSpace(query.RouterAddress), (config, _) => config.RouterAddress == query.RouterAddress) .WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigPic), (config, _) => config.PortalConfigPic == query.PortalConfigPic) .Select((config, configType) => new HwPortalConfig { // 【主表字段】 PortalConfigId = config.PortalConfigId, PortalConfigType = config.PortalConfigType, PortalConfigTypeId = config.PortalConfigTypeId, PortalConfigTitle = config.PortalConfigTitle, PortalConfigOrder = config.PortalConfigOrder, PortalConfigDesc = config.PortalConfigDesc, ButtonName = config.ButtonName, RouterAddress = config.RouterAddress, PortalConfigPic = config.PortalConfigPic, CreateTime = config.CreateTime, CreateBy = config.CreateBy, UpdateTime = config.UpdateTime, UpdateBy = config.UpdateBy, // 【关联表字段】 ConfigTypeName = configType.ConfigTypeName, // 【冗余字段】 // Why:这里统一把关联侧字段一起投影出来,避免 provider 对条件投影翻译不稳定。 // 对不需要这些字段的调用方来说,多出冗余属性不会改变行为,但能明显降低切换风险。 HomeConfigTypePic = configType.HomeConfigTypePic, HomeConfigTypeIcon = configType.ConfigTypeIcon, HomeConfigTypeName = configType.HomeConfigTypeName, HomeConfigTypeClassfication = configType.ConfigTypeClassfication, ParentId = configType.ParentId, Ancestors = configType.Ancestors }); } /// /// 将空字符串规范化转为 null。 /// /// 【辅助方法】 /// 用于保持与 XML 方案的数据一致性。 /// 原 XML 中 <if> 标签会跳过空字符串, /// 这里主动将空字符串转为 null,达到同样效果。 /// /// /// 输入字符串 /// null 或原值 private static string NormalizeEmptyToNull(string value) { return string.IsNullOrWhiteSpace(value) ? null : value; } }