From a029543b7224234b24e683626504712394e61386 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Fri, 24 Jul 2026 02:49:46 +0330 Subject: [PATCH] fix referencing issues ... fix seeding issues ... fix SubCategory Refresh and Add Support for handle Category Referesh and Referencing ... --- .../XCategoryServiceConfiguration.cs | 20 ++ Constants/ConfigurationNodeNames.cs | 7 + DI/XDIHelperExtension.cs | 173 ++++++++++++++++++ Providers/XBaseCategoryProvider.cs | 6 +- Providers/XCategoryServiceSeeder.cs | 12 ++ Providers/XSubCategoryProvider.cs | 68 ++++++- 6 files changed, 275 insertions(+), 11 deletions(-) create mode 100644 Configurations/XCategoryServiceConfiguration.cs create mode 100644 Constants/ConfigurationNodeNames.cs create mode 100644 Providers/XCategoryServiceSeeder.cs diff --git a/Configurations/XCategoryServiceConfiguration.cs b/Configurations/XCategoryServiceConfiguration.cs new file mode 100644 index 0000000..6557e18 --- /dev/null +++ b/Configurations/XCategoryServiceConfiguration.cs @@ -0,0 +1,20 @@ +using xCategoryService.Models.Dtos; + +namespace xCategoryService.Configurations +{ + /// + /// a Configuration Class for Providing Data to Configure XCategoryService ... + /// + public class XCategoryServiceConfiguration + { + /// + /// a List of Categories for Seeding ... + /// + public XCategoryResourceDto[] Categories { get; set; } = []; + + /// + /// a List of SubCategories for Seeding ... + /// + public XSubCategoryResourceDto[] SubCategories { get; set; } = []; + } +} \ No newline at end of file diff --git a/Constants/ConfigurationNodeNames.cs b/Constants/ConfigurationNodeNames.cs new file mode 100644 index 0000000..601ef36 --- /dev/null +++ b/Constants/ConfigurationNodeNames.cs @@ -0,0 +1,7 @@ +namespace xCategoryService.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string CATEGORY_SERVICE_NODE = "CategoryServiceConfiguration"; + } +} \ No newline at end of file diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index 7c8e40d..647de31 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -1,6 +1,11 @@ using System; +using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using SQLitePCL; +using xCategoryService.Configurations; using xCategoryService.Helpers; using xCategoryService.Interfaces; using xCategoryService.Interfaces.Dtos; @@ -22,6 +27,71 @@ namespace xCategoryService.DI { public static class XDIHelperExtension { + /// + /// Extract Service Configurations ... + /// + /// + /// + public static XCategoryServiceConfiguration GetXCategoryServiceConfigurations( + this IConfiguration source + ) + { + // + XCategoryServiceConfiguration result = null; + + // + var section = source.GetSection(Constants.ConfigurationNodeNames.CATEGORY_SERVICE_NODE); + var sectionJson = source.GetSectionAsJson(Constants.ConfigurationNodeNames.CATEGORY_SERVICE_NODE); + if (!section.IsNull()) + { + result = sectionJson.FromJSON(); + } + + // + return result; + } + + /// + /// Register Service Configuration ... + /// + /// + /// + public static void AddXCategoryServiceConfiguration( + this IServiceCollection source, + IConfiguration configuration + ) + { + // + // Extract Configuration Class ... + var config = configuration.GetXCategoryServiceConfigurations(); + + // + // Register Class as Service ... + source.AddXCategoryServiceConfiguration(config); + } + + /// + /// Register Service Configuration ... + /// + /// + /// + public static void AddXCategoryServiceConfiguration( + this IServiceCollection source, + XCategoryServiceConfiguration configuration + ) + { + // + // Normalize Configuration Class ... + if (configuration.IsNull()) + { + configuration = new XCategoryServiceConfiguration(); + } + + // + // Register ... + source.AddSingleton(configuration); + } + /// /// Register Service ... /// @@ -114,6 +184,109 @@ namespace xCategoryService.DI isDevelopmentEnvironment: isDevelopmentEnvironment ); } + + // + // Create an Scope for Services Acces ... + // Handle Seeding Category/SubCategory Resources ... + using (var scope = app.ApplicationServices.CreateScope()) + { + // + // Retrieve Configuratuions ... + var categoryProvider = scope.ServiceProvider.GetService(); + var subCategoryProvider = scope.ServiceProvider.GetService(); + var configuration = scope.ServiceProvider.GetService(); + if (!configuration.IsNullOrDefault() && + !categoryProvider.IsNullOrDefault() && + !subCategoryDescriptor.IsNullOrDefault() + ) + { + // + // Logging ... + Log("Start Seeding ..."); + + // + // Count Data in Category ... + var hasCategory = (categoryProvider.Count().GetAwaiter().GetResult()) > 0; + var hasSubCategory = (subCategoryProvider.Count().GetAwaiter().GetResult()) > 0; + + // + // Seed Category Resources ... + var canSeed = + !hasCategory && + configuration.Categories.HasChild(); + if (canSeed) + { + // + // Loop through Provided items ... + foreach (var cat in configuration.Categories) + { + // + try + { + // + Log($"Start Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} ..."); + + // + categoryProvider.Refresh( + resource: cat, + userInfo: null, + connectionId: null, + cancellationToken: default + ) + .GetAwaiter() + .GetResult(); + + // + Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + } + catch (Exception ex) + { + Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + } + } + } + + // + // Seed SubCategory Resources ... + canSeed = + !hasSubCategory && + configuration.SubCategories.HasChild(); + if (canSeed) + { + // + // Loop through Provided items ... + foreach (var subcat in configuration.SubCategories) + { + // + try + { + // + Log($"Start Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} ..."); + + // + subCategoryProvider.Refresh( + userInfo: null, + resource: subcat, + connectionId: null, + cancellationToken: default + ) + .GetAwaiter() + .GetResult(); + + // + Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + } + catch (Exception ex) + { + Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + } + } + } + + // + Log("Finish Seeding ..."); + } + } } // diff --git a/Providers/XBaseCategoryProvider.cs b/Providers/XBaseCategoryProvider.cs index d75b648..c94a75f 100644 --- a/Providers/XBaseCategoryProvider.cs +++ b/Providers/XBaseCategoryProvider.cs @@ -73,11 +73,11 @@ namespace xCategoryService.Providers // // Retrieve Last Index ... - var maxIndex = (await GetReferencingIndexes( + var indexes = await GetReferencingIndexes( providedForId: providedForId, cancellationToken: cancellationToken - )) - .Max(); + ); + var maxIndex = indexes.HasChild() ? indexes.Max() : -1; if (forIndex > maxIndex) { XException.NotFound.Throw(); diff --git a/Providers/XCategoryServiceSeeder.cs b/Providers/XCategoryServiceSeeder.cs new file mode 100644 index 0000000..5762886 --- /dev/null +++ b/Providers/XCategoryServiceSeeder.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace xCategoryService.Providers +{ + public class XCategoryServiceSeeder + { + + } +} \ No newline at end of file diff --git a/Providers/XSubCategoryProvider.cs b/Providers/XSubCategoryProvider.cs index f952b49..2f9039c 100644 --- a/Providers/XSubCategoryProvider.cs +++ b/Providers/XSubCategoryProvider.cs @@ -143,17 +143,21 @@ namespace xCategoryService.Providers // // Reading Category Resource ... XCategoryResourceDto categoryResourceDto = null; - var categoryDto = await categoryProvider.GetReference( - providedForId: id, - cancellationToken: cancellationToken - ); - if (!categoryDto.IsNullOrDefault()) + try { - categoryResourceDto = await categoryProvider.GetResource( - id: categoryDto.Id, + var categoryDto = await categoryProvider.GetReference( + providedForId: id, cancellationToken: cancellationToken ); + if (!categoryDto.IsNullOrDefault()) + { + categoryResourceDto = await categoryProvider.GetResource( + id: categoryDto.Id, + cancellationToken: cancellationToken + ); + } } + catch { } // var result = new XSubCategoryResourceDto @@ -439,7 +443,7 @@ namespace xCategoryService.Providers // // Update Category Dto if not ... - if (item.Item.Title.IsNullOrEmpty() || + if (item.Item.Title.IsNullOrEmpty() || !item.Item.Title .Equals( titleResource.Resource, @@ -671,6 +675,17 @@ namespace xCategoryService.Providers isValid = true; } + // + // Remove all Referencings ... + if (isValid) + { + await categoryProvider.RemoveReferences( + providedForId: id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + // if (isValid) { @@ -1123,6 +1138,42 @@ namespace xCategoryService.Providers } } + // + // Handle Category ... + if ( + !isDelete && + (isNew || isExists) && + !resource.Category.IsNullOrDefault()) + { + // + // Refresh Category ... + var category = await categoryProvider.Refresh( + userInfo: userInfo, + resource: resource.Category, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + // Handle SubCategory Referencings ... + var references = await categoryProvider.GetAllReferences( + providedForId: id, + cancellationToken: cancellationToken + ); + var hasReference = + references.HasChild() && + references.Any(r => r.Id == category.Item.Id); + if (!hasReference) + { + await categoryProvider.AddReference( + providedForId: id, + model: category.Item, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + } + // // Validate Action ... isValid = id.IsValidIntId(); @@ -1162,6 +1213,7 @@ namespace xCategoryService.Providers // return result; } + /// /// Get All Resources as Async Enumerable ... ///