using System; using System.IO; using System.Linq; using System.Text.Json; using System.Threading.Tasks; using Sozsoft.Platform.Entities; using Sozsoft.Platform.Enums; using Sozsoft.Settings.Entities; using Microsoft.Extensions.Configuration; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Microsoft.EntityFrameworkCore; using EFCore.BulkExtensions; using System.Collections.Generic; using Sozsoft.Platform.Public; using static Sozsoft.Settings.SettingsConsts; namespace Sozsoft.Platform.Data.Seeds; #region SeedDtos public class AiBotSeedDto { public string Name { get; set; } public string Description { get; set; } public string ApiUrl { get; set; } public bool IsActive { get; set; } } public class LanguageTextsSeedDto { public string ResourceName { get; set; } public string Key { get; set; } public string En { get; set; } public string Tr { get; set; } } public class BackgroundWorkerSeedDto { public string Name { get; set; } public string Cron { get; set; } public string WorkerType { get; set; } public bool IsActive { get; set; } public string DataSourceCode { get; set; } public string BeforeSp { get; set; } public string AfterSp { get; set; } } public class NotificationRuleSeedDto { public string NotificationType { get; set; } public string RecipientType { get; set; } public string RecipientId { get; set; } public string Channel { get; set; } public bool IsActive { get; set; } public bool IsFixed { get; set; } public bool IsCustomized { get; set; } } public class PermissionGroupDefinitionRecordSeedDto { public string Name { get; set; } public string DisplayName { get; set; } } public class PermissionDefinitionRecordSeedDto { public string GroupName { get; set; } public string Name { get; set; } public string ParentName { get; set; } public string DisplayName { get; set; } public bool IsEnabled { get; set; } public int MultiTenancySide { get; set; } public string MenuGroup { get; set; } } public class CurrencySeedDto { public string Id { get; set; } public string Symbol { get; set; } public string Name { get; set; } public bool IsActive { get; set; } } public class ContactTitleSeedDto { public string Title { get; set; } public string Abbreviation { get; set; } } public class HostSeederDto { public List AiBots { get; set; } public List DataSources { get; set; } public List Settings { get; set; } public List BackgroundWorkers { get; set; } public List NotificationRules { get; set; } public List Currencies { get; set; } public List ContactTitles { get; set; } } #endregion public class HostDataSeeder : IDataSeedContributor, ITransientDependency { private readonly IRepository _aiBotRepository; private readonly IRepository _dataSources; private readonly IRepository _settings; private readonly IRepository _backgroundWorkerRepository; private readonly IRepository _currencyRepository; private readonly IRepository _countryGroupRepository; private readonly IRepository _countryRepository; private readonly IRepository _cityRepository; private readonly IRepository _districtRepository; private readonly IRepository _contactTitleRepository; public HostDataSeeder( IRepository aiBotRepository, IRepository dataSource, IRepository settings, IRepository backgroundWorkerRepository, IRepository currencyRepository, IRepository countryGroupRepository, IRepository countryRepository, IRepository cityRepository, IRepository districtRepository, IRepository contactTitleRepository, IRepository routeRepository ) { _aiBotRepository = aiBotRepository; _dataSources = dataSource; _settings = settings; _backgroundWorkerRepository = backgroundWorkerRepository; _currencyRepository = currencyRepository; _countryGroupRepository = countryGroupRepository; _countryRepository = countryRepository; _cityRepository = cityRepository; _districtRepository = districtRepository; _contactTitleRepository = contactTitleRepository; } private static IConfigurationRoot BuildConfiguration() { var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? ""}.json", true); return builder.Build(); } public async Task SeedCountyGroupsAsync() { var dbCtx = await _countryRepository.GetDbContextAsync(); // DB’de mevcut kodları set olarak al var existingCodes = (await dbCtx.Set() .Select(c => c.Name) .ToListAsync()) .ToHashSet(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; using var fs = File.OpenRead(Path.Combine("Seeds", "CountryGroups.json")); var buffer = new List(capacity: 1000); var seenCodes = new HashSet(); // JSON içindeki duplicate’leri yakalamak için await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable(fs, options)) { if (item == null) continue; if (string.IsNullOrWhiteSpace(item.Name)) continue; // boş kodları atla // hem DB’de hem JSON içinde duplicate engelle if (!seenCodes.Add(item.Name) || existingCodes.Contains(item.Name)) continue; buffer.Add(new CountryGroup( item.Name, item.Name )); if (buffer.Count >= 1000) { await BulkCountryGroupInsertAsync(buffer); buffer.Clear(); } } if (buffer.Count > 0) { await BulkCountryGroupInsertAsync(buffer); } } private async Task BulkCountryGroupInsertAsync(List entities) { var dbCtx = await _countryGroupRepository.GetDbContextAsync(); await dbCtx.BulkInsertAsync(entities, new BulkConfig { BatchSize = 1000 }); } public async Task SeedCountriesAsync() { var dbCtx = await _countryRepository.GetDbContextAsync(); // DB’de mevcut kodları set olarak al var existingCodes = (await dbCtx.Set() .Select(c => c.Name) .ToListAsync()) .ToHashSet(); var countryGroupNames = (await dbCtx.Set() .Select(c => c.Name) .ToListAsync()) .ToHashSet(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; using var fs = File.OpenRead(Path.Combine("Seeds", "Countries.json")); var buffer = new List(capacity: 1000); var seenCodes = new HashSet(); // JSON içindeki duplicate’leri yakalamak için await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable(fs, options)) { if (item == null) continue; if (string.IsNullOrWhiteSpace(item.Name)) continue; // boş kodları atla // hem DB’de hem JSON içinde duplicate engelle if (!seenCodes.Add(item.Name) || existingCodes.Contains(item.Name)) continue; var groupName = string.IsNullOrWhiteSpace(item.GroupName) ? null : item.GroupName.Trim(); if (!string.IsNullOrWhiteSpace(groupName) && !countryGroupNames.Contains(groupName)) { groupName = null; } buffer.Add(new Country( item.Name, item.Name, groupName, item.Currency, item.PhoneCode, item.TaxLabel )); if (buffer.Count >= 1000) { await BulkCountryInsertAsync(buffer); buffer.Clear(); } } if (buffer.Count > 0) { await BulkCountryInsertAsync(buffer); } } private async Task BulkCountryInsertAsync(List entities) { var dbCtx = await _countryRepository.GetDbContextAsync(); await dbCtx.BulkInsertAsync(entities, new BulkConfig { BatchSize = 1000 }); } public async Task SeedCitiesAsync() { var dbCtx = await _cityRepository.GetDbContextAsync(); // 1. Mevcut kayıtları çek (tek sorguda) var existingCities = await dbCtx.Set() .Select(d => new { d.Country, d.Name }) .ToListAsync(); var existingSet = existingCities .Select(d => $"{d.Country}.{d.Name}") .ToHashSet(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; // 2. JSON’u stream et using FileStream fs = File.OpenRead(Path.Combine("Seeds", "Cities.json")); var buffer = new List(capacity: 5000); await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable(fs, options)) { if (item == null) continue; var key = $"{item.Country}.{item.Name}"; if (existingSet.Contains(key)) continue; // duplicate kontrolü buffer.Add(new City( Guid.NewGuid(), item.Country, item.Name, item.PlateCode )); if (buffer.Count >= 1000) // 3. Batch { await BulkCityInsertAsync(buffer); buffer.Clear(); } } if (buffer.Count > 0) { await BulkCityInsertAsync(buffer); } } private async Task BulkCityInsertAsync(List entities) { var dbCtx = await _cityRepository.GetDbContextAsync(); await dbCtx.BulkInsertAsync(entities, new BulkConfig { PreserveInsertOrder = true, SetOutputIdentity = true, BatchSize = 1000 }); } public async Task SeedDistrictsAsync() { var dbCtx = await _districtRepository.GetDbContextAsync(); // 1. Mevcut kayıtları çek (tek sorguda) var existingDistricts = await dbCtx.Set() .Select(d => new { d.Country, d.City, d.Name, d.Township }) .ToListAsync(); var existingSet = existingDistricts .Select(d => $"{d.Country}:{d.City}:{d.Name}:{d.Township}") .ToHashSet(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; // 2. JSON’u stream et using FileStream fs = File.OpenRead(Path.Combine("Seeds", "Districts.json")); var buffer = new List(capacity: 5000); await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable(fs, options)) { if (item == null) continue; var key = $"{item.Country}:{item.City}:{item.Name}:{item.Township}"; if (existingSet.Contains(key)) continue; buffer.Add(new District( Guid.NewGuid(), item.Country, item.City, item.Name, item.Township )); if (buffer.Count >= 5000) // 3. Batch { await BulkDistrictInsertAsync(buffer); buffer.Clear(); } } if (buffer.Count > 0) { await BulkDistrictInsertAsync(buffer); } } private async Task BulkDistrictInsertAsync(List entities) { var dbCtx = await _districtRepository.GetDbContextAsync(); await dbCtx.BulkInsertAsync(entities, new BulkConfig { PreserveInsertOrder = true, SetOutputIdentity = true, BatchSize = 5000 }); } public async Task SeedAsync(DataSeedContext context) { var settings = await _settings.GetListAsync(); var dataSources = await _dataSources.GetListAsync(); var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile(Path.Combine("Seeds", "HostData.json")) .AddJsonFile(Path.Combine("Seeds", $"HostData.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? ""}.json"), true) .Build(); var items = configuration.Get(); foreach (var item in items.Settings) { if (!settings.Any(a => a.Code == item.Code)) { await _settings.InsertAsync(new() { Code = item.Code, NameKey = item.NameKey, DescriptionKey = item.DescriptionKey, DefaultValue = item.DefaultValue.Replace("\r\n", Environment.NewLine), IsVisibleToClients = item.IsVisibleToClients, IsInherited = item.IsInherited, IsEncrypted = item.IsEncrypted, MainGroupKey = item.MainGroupKey, SubGroupKey = item.SubGroupKey, RequiredPermissionName = item.RequiredPermissionName, DataType = item.DataType, Providers = item.Providers, SelectOptions = item.SelectOptions, Order = item.Order }); } } if (!dataSources.Any(a => a.Code == SeedConsts.DataSources.DefaultCode)) { var config = BuildConfiguration(); await _dataSources.InsertAsync(new() { Code = SeedConsts.DataSources.DefaultCode, DataSourceType = DefaultDatabaseProvider == DatabaseProvider.SqlServer ? DataSourceTypeEnum.Mssql : DataSourceTypeEnum.Postgresql, ConnectionString = config.GetConnectionString(DefaultDatabaseProvider) }); } foreach (var item in items.BackgroundWorkers) { if (!await _backgroundWorkerRepository.AnyAsync(x => x.Name == item.Name)) { await _backgroundWorkerRepository.InsertAsync(new BackgroundWorker { Name = item.Name, Cron = item.Cron, WorkerType = Enum.Parse(item.WorkerType), IsActive = item.IsActive, DataSourceCode = item.DataSourceCode, BeforeSp = item.BeforeSp, AfterSp = item.AfterSp }); } } foreach (var item in items.Currencies) { var exists = await _currencyRepository.AnyAsync(x => x.Id == item.Id); if (!exists) { await _currencyRepository.InsertAsync(new Currency(item.Id) { Symbol = item.Symbol, Name = item.Name, IsActive = item.IsActive }, autoSave: true); } } foreach (var item in items.ContactTitles) { var exists = await _contactTitleRepository.AnyAsync(x => x.Title == item.Title); if (!exists) { await _contactTitleRepository.InsertAsync(new ContactTitle { Title = item.Title, Abbreviation = item.Abbreviation, }); } } foreach (var item in items.AiBots) { var exists = await _aiBotRepository.AnyAsync(x => x.Name == item.Name); if (!exists) { await _aiBotRepository.InsertAsync(new AiBot { Name = item.Name, Description = item.Description, ApiUrl = item.ApiUrl, IsActive = item.IsActive }); } } await SeedCountyGroupsAsync(); await SeedCountriesAsync(); await SeedCitiesAsync(); await SeedDistrictsAsync(); } }