147 lines
5.7 KiB
C#
147 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Logging;
|
|
using Sozsoft.Platform.Entities;
|
|
using Volo.Abp.Data;
|
|
using Volo.Abp.DependencyInjection;
|
|
using Volo.Abp.Domain.Repositories;
|
|
|
|
namespace Sozsoft.Platform.Data.Seeds;
|
|
|
|
/// <summary>
|
|
/// SqlQueryManager uzerinden uretilen CRUD endpoint'lerini
|
|
/// <c>{host|tenants/{tenantId}}/crud/*.json</c> dosyalarindan okuyarak veritabanina uygular.
|
|
/// <para>
|
|
/// <see cref="SqlDataSeeder"/> tablolari olusturduktan hemen sonra calisir; boylece endpoint'ler
|
|
/// her zaman dayandiklari tablolar hazir olduktan sonra yazilir. ABP'nin contributor sirasi
|
|
/// garanti edilmedigi icin bilincli olarak <see cref="IDataSeedContributor"/> degildir,
|
|
/// SqlDataSeeder tarafindan dogrudan cagrilir.
|
|
/// </para>
|
|
/// Her dosya bir entity'ye aittir ve o entity'nin endpoint listesinin tamamini icerir:
|
|
/// dosyadaki liste kaynak kabul edilir, veritabanindaki eski kayitlar dosyaya gore guncellenir.
|
|
/// </summary>
|
|
public class CrudDataSeeder : ITransientDependency
|
|
{
|
|
private static readonly JsonSerializerOptions JsonReadOptions = new()
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
};
|
|
|
|
private readonly IRepository<CrudEndpoint, Guid> _repository;
|
|
private readonly IConfiguration _configuration;
|
|
private readonly ILogger<CrudDataSeeder> _logger;
|
|
|
|
public CrudDataSeeder(
|
|
IRepository<CrudEndpoint, Guid> repository,
|
|
IConfiguration configuration,
|
|
ILogger<CrudDataSeeder> logger)
|
|
{
|
|
_repository = repository;
|
|
_configuration = configuration;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task SeedAsync(DataSeedContext context)
|
|
{
|
|
var scopeFolderName = SeedPathResolver.GetScopeFolderName(context.TenantId);
|
|
var crudDataPath = SeedPathResolver.GetScopePath(_configuration, context.TenantId, SeedPathResolver.CrudFolder);
|
|
|
|
if (!Directory.Exists(crudDataPath))
|
|
{
|
|
_logger.LogInformation("Seeds/{Scope}/crud directory not found, skipping CrudDataSeeder.", scopeFolderName);
|
|
return;
|
|
}
|
|
|
|
var jsonFiles = Directory.GetFiles(crudDataPath, "*.json").OrderBy(Path.GetFileName).ToArray();
|
|
if (jsonFiles.Length == 0)
|
|
{
|
|
_logger.LogInformation("No JSON files found in Seeds/{Scope}/crud directory, skipping CrudDataSeeder.", scopeFolderName);
|
|
return;
|
|
}
|
|
|
|
_logger.LogInformation("CrudDataSeeder started. {Count} file(s) to be processed.", jsonFiles.Length);
|
|
|
|
foreach (var filePath in jsonFiles)
|
|
{
|
|
var fileName = Path.GetFileName(filePath);
|
|
try
|
|
{
|
|
var json = await File.ReadAllTextAsync(filePath);
|
|
var seedFile = JsonSerializer.Deserialize<CrudEndpointSeedFileDto>(json, JsonReadOptions);
|
|
|
|
var entityName = string.IsNullOrWhiteSpace(seedFile?.EntityName)
|
|
? Path.GetFileNameWithoutExtension(filePath)
|
|
: seedFile!.EntityName.Trim();
|
|
|
|
if (seedFile?.Endpoints == null || seedFile.Endpoints.Count == 0)
|
|
{
|
|
_logger.LogWarning("[{File}] No endpoint found, skipped.", fileName);
|
|
continue;
|
|
}
|
|
|
|
await ApplyAsync(entityName, seedFile.Endpoints);
|
|
_logger.LogInformation("[{File}] '{EntityName}' applied with {Count} endpoint(s).", fileName, entityName, seedFile.Endpoints.Count);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Tek bir dosyanin hatasi diger endpoint'lerin seed edilmesini engellemez.
|
|
_logger.LogError(ex, "Failed to process CRUD seed file: {FileName}", fileName);
|
|
}
|
|
}
|
|
|
|
_logger.LogInformation("CrudDataSeeder completed. {Count} file(s) processed.", jsonFiles.Length);
|
|
}
|
|
|
|
private async Task ApplyAsync(string entityName, List<CrudEndpointSeedItemDto> endpoints)
|
|
{
|
|
var existing = await _repository.GetListAsync(x => x.EntityName == entityName);
|
|
|
|
foreach (var item in endpoints)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(item.OperationType))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var current = existing.FirstOrDefault(x =>
|
|
string.Equals(x.OperationType, item.OperationType, StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (current == null)
|
|
{
|
|
// CsharpCode seed dosyasinda tutulmaz; endpoint'in calismasi icin gerekli degildir,
|
|
// gerektiginde SqlQueryManager'daki "Yeniden Olustur" ile uretilir.
|
|
await _repository.InsertAsync(new CrudEndpoint
|
|
{
|
|
EntityName = entityName,
|
|
Method = item.Method,
|
|
Path = item.Path,
|
|
OperationType = item.OperationType,
|
|
IsActive = item.IsActive
|
|
}, autoSave: true);
|
|
continue;
|
|
}
|
|
|
|
current.Method = item.Method;
|
|
current.Path = item.Path;
|
|
current.IsActive = item.IsActive;
|
|
await _repository.UpdateAsync(current, autoSave: true);
|
|
}
|
|
|
|
// Dosyada artik yer almayan operasyonlar kaldirilir; dosya tek kaynaktir.
|
|
var seededOperations = endpoints
|
|
.Select(x => x.OperationType)
|
|
.Where(x => !string.IsNullOrWhiteSpace(x))
|
|
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
|
|
var obsolete = existing.Where(x => !seededOperations.Contains(x.OperationType)).ToList();
|
|
if (obsolete.Count > 0)
|
|
{
|
|
await _repository.DeleteManyAsync(obsolete, autoSave: true);
|
|
}
|
|
}
|
|
}
|