594 lines
20 KiB
C#
594 lines
20 KiB
C#
using System;
|
||
using System.Globalization;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text.Json;
|
||
using System.Threading.Tasks;
|
||
using Kurs.Languages.Entities;
|
||
using Kurs.Platform.Entities;
|
||
using Kurs.Platform.Enums;
|
||
using Kurs.Platform.Seeds;
|
||
using Kurs.Settings.Entities;
|
||
using Microsoft.Extensions.Configuration;
|
||
using Volo.Abp.Data;
|
||
using Volo.Abp.DependencyInjection;
|
||
using Volo.Abp.Domain.Repositories;
|
||
using Volo.Abp.MultiTenancy;
|
||
using Volo.Abp.PermissionManagement;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using EFCore.BulkExtensions;
|
||
using System.Collections.Generic;
|
||
using Kurs.Platform.Public;
|
||
using static Kurs.Settings.SettingsConsts;
|
||
using Kurs.Platform.Extensions;
|
||
|
||
namespace Kurs.Platform.Data.Seeds;
|
||
|
||
public class HostDataSeeder : IDataSeedContributor, ITransientDependency
|
||
{
|
||
private readonly IRepository<AiBot, Guid> _aiBotRepository;
|
||
private readonly IRepository<Language, Guid> _languages;
|
||
private readonly IRepository<LanguageKey, Guid> _languageKey;
|
||
private readonly IRepository<LanguageText, Guid> _languagesText;
|
||
private readonly IRepository<DataSource, Guid> _dataSources;
|
||
private readonly IRepository<SettingDefinition, Guid> _settings;
|
||
private readonly IRepository<BackgroundWorker, Guid> _backgroundWorkerRepository;
|
||
private readonly IRepository<Menu, Guid> _menuRepository;
|
||
private readonly IRepository<PermissionGroupDefinitionRecord, Guid> _permissionGroupRepository;
|
||
private readonly IRepository<PermissionDefinitionRecord, Guid> _permissionRepository;
|
||
private readonly IRepository<Currency, Guid> _currencyRepository;
|
||
private readonly IRepository<CountryGroup, Guid> _countryGroupRepository;
|
||
private readonly IRepository<Country, Guid> _countryRepository;
|
||
private readonly IRepository<City, Guid> _cityRepository;
|
||
private readonly IRepository<District, Guid> _districtRepository;
|
||
private readonly IRepository<ContactTag, Guid> _contactTagRepository;
|
||
private readonly IRepository<ContactTitle, Guid> _contactTitleRepository;
|
||
private readonly IRepository<Route, Guid> _routeRepository;
|
||
|
||
public HostDataSeeder(
|
||
IRepository<AiBot, Guid> aiBotRepository,
|
||
IRepository<Language, Guid> languages,
|
||
IRepository<LanguageKey, Guid> languageKey,
|
||
IRepository<LanguageText, Guid> languagesText,
|
||
IRepository<DataSource, Guid> dataSource,
|
||
IRepository<SettingDefinition, Guid> settings,
|
||
IRepository<BackgroundWorker, Guid> backgroundWorkerRepository,
|
||
IRepository<Menu, Guid> menuRepository,
|
||
IRepository<PermissionGroupDefinitionRecord, Guid> permissionGroupRepository,
|
||
IRepository<PermissionDefinitionRecord, Guid> permissionRepository,
|
||
IRepository<Currency, Guid> currencyRepository,
|
||
IRepository<CountryGroup, Guid> countryGroupRepository,
|
||
IRepository<Country, Guid> countryRepository,
|
||
IRepository<City, Guid> cityRepository,
|
||
IRepository<District, Guid> districtRepository,
|
||
IRepository<ContactTag, Guid> contactTagRepository,
|
||
IRepository<ContactTitle, Guid> contactTitleRepository,
|
||
IRepository<Route, Guid> routeRepository
|
||
)
|
||
{
|
||
_languages = languages;
|
||
_languageKey = languageKey;
|
||
_languagesText = languagesText;
|
||
_dataSources = dataSource;
|
||
_settings = settings;
|
||
_backgroundWorkerRepository = backgroundWorkerRepository;
|
||
_menuRepository = menuRepository;
|
||
_permissionGroupRepository = permissionGroupRepository;
|
||
_permissionRepository = permissionRepository;
|
||
_currencyRepository = currencyRepository;
|
||
_countryGroupRepository = countryGroupRepository;
|
||
_countryRepository = countryRepository;
|
||
_cityRepository = cityRepository;
|
||
_districtRepository = districtRepository;
|
||
_contactTagRepository = contactTagRepository;
|
||
_contactTitleRepository = contactTitleRepository;
|
||
_aiBotRepository = aiBotRepository;
|
||
_routeRepository = routeRepository;
|
||
}
|
||
|
||
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<CountryGroup>()
|
||
.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<CountryGroup>(capacity: 1000);
|
||
var seenCodes = new HashSet<string>(); // JSON içindeki duplicate’leri yakalamak için
|
||
|
||
await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable<CountryGroupDto>(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(
|
||
Guid.NewGuid(),
|
||
item.Name
|
||
));
|
||
|
||
if (buffer.Count >= 1000)
|
||
{
|
||
await BulkCountryGroupInsertAsync(buffer);
|
||
buffer.Clear();
|
||
}
|
||
}
|
||
|
||
if (buffer.Count > 0)
|
||
{
|
||
await BulkCountryGroupInsertAsync(buffer);
|
||
}
|
||
}
|
||
|
||
private async Task BulkCountryGroupInsertAsync(List<CountryGroup> 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<Country>()
|
||
.Select(c => c.Code)
|
||
.ToListAsync())
|
||
.ToHashSet();
|
||
|
||
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||
|
||
using var fs = File.OpenRead(Path.Combine("Seeds", "Countries.json"));
|
||
|
||
var buffer = new List<Country>(capacity: 1000);
|
||
var seenCodes = new HashSet<string>(); // JSON içindeki duplicate’leri yakalamak için
|
||
|
||
await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable<CountryDto>(fs, options))
|
||
{
|
||
if (item == null) continue;
|
||
if (string.IsNullOrWhiteSpace(item.Code)) continue; // boş kodları atla
|
||
|
||
// hem DB’de hem JSON içinde duplicate engelle
|
||
if (!seenCodes.Add(item.Code) || existingCodes.Contains(item.Code))
|
||
continue;
|
||
|
||
buffer.Add(new Country(
|
||
Guid.NewGuid(),
|
||
item.Code,
|
||
item.Name,
|
||
item.GroupName,
|
||
item.CurrencyCode,
|
||
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<Country> 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<City>()
|
||
.Select(d => new { d.Code })
|
||
.ToListAsync();
|
||
|
||
var existingSet = existingCities
|
||
.Select(d => d.Code)
|
||
.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<City>(capacity: 5000);
|
||
await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable<CityDto>(fs, options))
|
||
{
|
||
if (item == null) continue;
|
||
|
||
var key = $"{item.Country}.{item.Code}";
|
||
if (existingSet.Contains(key)) continue; // duplicate kontrolü
|
||
|
||
buffer.Add(new City(
|
||
Guid.NewGuid(),
|
||
item.Country,
|
||
item.Name,
|
||
key,
|
||
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<City> 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<District>()
|
||
.Select(d => new { d.Country, d.City, d.Name, d.Township, d.Street, d.ZipCode })
|
||
.ToListAsync();
|
||
|
||
var existingSet = existingDistricts
|
||
.Select(d => $"{d.Country}:{d.City}:{d.Name}:{d.Township}:{d.Street}:{d.ZipCode}")
|
||
.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<District>(capacity: 5000);
|
||
await foreach (var item in JsonSerializer.DeserializeAsyncEnumerable<DistrictDto>(fs, options))
|
||
{
|
||
if (item == null) continue;
|
||
|
||
var key = $"{item.Country}:{item.Country}.{item.City}:{item.Name}:{item.Township}:{item.Street}:{item.ZipCode}";
|
||
var city = $"{item.Country}.{item.City}";
|
||
if (existingSet.Contains(key)) continue;
|
||
|
||
buffer.Add(new District(
|
||
Guid.NewGuid(),
|
||
item.Country,
|
||
city,
|
||
item.Name,
|
||
item.Township,
|
||
item.Street,
|
||
item.ZipCode
|
||
));
|
||
|
||
if (buffer.Count >= 5000) // 3. Batch
|
||
{
|
||
await BulkDistrictInsertAsync(buffer);
|
||
buffer.Clear();
|
||
}
|
||
}
|
||
|
||
if (buffer.Count > 0)
|
||
{
|
||
await BulkDistrictInsertAsync(buffer);
|
||
}
|
||
}
|
||
|
||
private async Task BulkDistrictInsertAsync(List<District> 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 languages = await _languages.GetListAsync();
|
||
var keys = await _languageKey.GetListAsync();
|
||
var texts = await _languagesText.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<HostSeederDto>();
|
||
|
||
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||
|
||
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.Languages)
|
||
{
|
||
if (!languages.Any(a => a.CultureName == item.CultureName))
|
||
{
|
||
await _languages.InsertAsync(new()
|
||
{
|
||
CultureName = item.CultureName,
|
||
UiCultureName = item.UiCultureName,
|
||
DisplayName = item.DisplayName,
|
||
IsEnabled = item.IsEnabled,
|
||
TwoLetterISOLanguageName = new CultureInfo(item.CultureName).TwoLetterISOLanguageName,
|
||
});
|
||
}
|
||
}
|
||
|
||
foreach (var item in items.LanguageTexts)
|
||
{
|
||
try
|
||
{
|
||
if (!keys.Any(a => a.Key == item.Key))
|
||
{
|
||
await _languageKey.InsertAsync(new()
|
||
{
|
||
Key = item.Key,
|
||
ResourceName = item.ResourceName,
|
||
});
|
||
}
|
||
if (!texts.Any(a => a.CultureName == "en" && a.Key == item.Key))
|
||
{
|
||
await _languagesText.InsertAsync(new()
|
||
{
|
||
CultureName = "en",
|
||
Key = item.Key,
|
||
Value = item.En,
|
||
ResourceName = item.ResourceName,
|
||
});
|
||
}
|
||
if (!texts.Any(a => a.CultureName == "tr" && a.Key == item.Key))
|
||
{
|
||
|
||
await _languagesText.InsertAsync(new()
|
||
{
|
||
CultureName = "tr",
|
||
Key = item.Key,
|
||
Value = item.Tr,
|
||
ResourceName = item.ResourceName,
|
||
});
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw new Exception($"Hata veren Kod:' ResourceName='{item.ResourceName}', Key='{item.Key}' Message='{ex.Message}'");
|
||
}
|
||
}
|
||
|
||
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<WorkerTypeEnum>(item.WorkerType),
|
||
IsActive = item.IsActive,
|
||
DataSourceCode = item.DataSourceCode
|
||
});
|
||
}
|
||
}
|
||
|
||
foreach (var item in items.Menus)
|
||
{
|
||
var exists = await _menuRepository.AnyAsync(x => x.Code == item.Code);
|
||
|
||
if (!exists)
|
||
{
|
||
await _menuRepository.InsertAsync(new Menu
|
||
{
|
||
ParentCode = string.IsNullOrWhiteSpace(item.ParentCode) ? null : item.ParentCode,
|
||
Code = item.Code,
|
||
DisplayName = item.DisplayName,
|
||
Order = item.Order,
|
||
Url = item.Url,
|
||
Icon = item.Icon,
|
||
RequiredPermissionName = item.RequiredPermissionName,
|
||
IsDisabled = item.IsDisabled,
|
||
});
|
||
}
|
||
}
|
||
|
||
foreach (var item in items.PermissionGroupDefinitionRecords)
|
||
{
|
||
var exists = await _permissionGroupRepository.AnyAsync(x => x.Name == item.Name);
|
||
|
||
if (!exists)
|
||
{
|
||
await _permissionGroupRepository.InsertAsync(new PermissionGroupDefinitionRecord
|
||
{
|
||
Name = item.Name,
|
||
DisplayName = item.DisplayName
|
||
});
|
||
}
|
||
}
|
||
|
||
foreach (var item in items.PermissionDefinitionRecords)
|
||
{
|
||
var exists = await _permissionRepository.AnyAsync(x => x.Name == item.Name);
|
||
|
||
if (!exists)
|
||
{
|
||
var perm = new PermissionDefinitionRecord
|
||
{
|
||
GroupName = item.GroupName,
|
||
Name = item.Name,
|
||
ParentName = string.IsNullOrWhiteSpace(item.ParentName) ? null : item.ParentName,
|
||
DisplayName = item.DisplayName,
|
||
IsEnabled = item.IsEnabled,
|
||
MultiTenancySide = (MultiTenancySides)item.MultiTenancySide,
|
||
};
|
||
|
||
perm.SetMenuGroup(item.MenuGroup);
|
||
|
||
await _permissionRepository.InsertAsync(perm);
|
||
}
|
||
}
|
||
|
||
foreach (var item in items.Currencies)
|
||
{
|
||
var exists = await _currencyRepository.AnyAsync(x => x.Code == item.Code);
|
||
|
||
if (!exists)
|
||
{
|
||
await _currencyRepository.InsertAsync(new Currency
|
||
{
|
||
Code = item.Code,
|
||
Symbol = item.Symbol,
|
||
Name = item.Name,
|
||
IsActive = item.IsActive
|
||
});
|
||
}
|
||
}
|
||
|
||
foreach (var item in items.ContactTags)
|
||
{
|
||
var exists = await _contactTagRepository.AnyAsync(x => x.Name == item.Name);
|
||
|
||
if (!exists)
|
||
{
|
||
await _contactTagRepository.InsertAsync(new ContactTag
|
||
{
|
||
Name = item.Name,
|
||
Category = item.Category,
|
||
});
|
||
}
|
||
}
|
||
|
||
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.BotName == item.BotName);
|
||
|
||
if (!exists)
|
||
{
|
||
await _aiBotRepository.InsertAsync(new AiBot
|
||
{
|
||
BotName = item.BotName,
|
||
});
|
||
}
|
||
}
|
||
|
||
foreach (var item in items.Routes)
|
||
{
|
||
var exists = await _routeRepository.AnyAsync(x => x.Key == item.Key);
|
||
|
||
if (!exists)
|
||
{
|
||
await _routeRepository.InsertAsync(new Route(
|
||
item.Key,
|
||
item.Path,
|
||
item.ComponentPath,
|
||
item.RouteType,
|
||
item.Authority ?? []
|
||
));
|
||
}
|
||
}
|
||
|
||
await SeedCountyGroupsAsync();
|
||
|
||
await SeedCountriesAsync();
|
||
|
||
await SeedCitiesAsync();
|
||
|
||
await SeedDistrictsAsync();
|
||
}
|
||
}
|