seed/data Seeder GlobalSearch
This commit is contained in:
parent
3db82df964
commit
a1a76b1a95
6 changed files with 74 additions and 64 deletions
3
.github/instructions/lowcode.instructions.md
vendored
3
.github/instructions/lowcode.instructions.md
vendored
|
|
@ -3434,6 +3434,9 @@ Kurallar:
|
||||||
- **Anahtar dosyada durur.** Insert varsayılanları anahtarı `@NEWID` ile üretir; `ListFormSeedDataApplier`
|
- **Anahtar dosyada durur.** Insert varsayılanları anahtarı `@NEWID` ile üretir; `ListFormSeedDataApplier`
|
||||||
dosyadaki anahtarı geri yazar, böylece aynı dosya birden çok kez uygulandığında kopya kayıt oluşmaz.
|
dosyadaki anahtarı geri yazar, böylece aynı dosya birden çok kez uygulandığında kopya kayıt oluşmaz.
|
||||||
Elle dosya yazarken anahtarı deterministik üret (ör. koddan türeyen GUID).
|
Elle dosya yazarken anahtarı deterministik üret (ör. koddan türeyen GUID).
|
||||||
|
- **Identity anahtarlı tablolarda satır anahtarsız yazılır.** `Id` alanı dosyada yoksa anahtar
|
||||||
|
veritabanına bırakılır; satırın var olup olmadığı dosyadaki **tüm alan değerlerinin**
|
||||||
|
(tenant kapsamı dahil) eşleşmesine bakılarak belirlenir.
|
||||||
- **Uygulama yalnızca ekler:** anahtarı veritabanında bulunmayan satırlar `INSERT` edilir; var olan
|
- **Uygulama yalnızca ekler:** anahtarı veritabanında bulunmayan satırlar `INSERT` edilir; var olan
|
||||||
kayıt güncellenmez (her migrate'te ekrandaki güncel değerler dosyadaki eskisiyle ezilmesin diye)
|
kayıt güncellenmez (her migrate'te ekrandaki güncel değerler dosyadaki eskisiyle ezilmesin diye)
|
||||||
ve dosyada olmayan satır silinmez.
|
ve dosyada olmayan satır silinmez.
|
||||||
|
|
|
||||||
|
|
@ -1145,6 +1145,10 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.GlobalSearch)),
|
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.GlobalSearch)),
|
||||||
KeyFieldName = "Id",
|
KeyFieldName = "Id",
|
||||||
KeyFieldDbSourceType = DbType.Int32,
|
KeyFieldDbSourceType = DbType.Int32,
|
||||||
|
SeedFilePath = SeedPathResolver.GetDataFilePath(listFormName),
|
||||||
|
SeedSyncInsert = false,
|
||||||
|
SeedSyncUpdate = false,
|
||||||
|
SeedSyncDelete = false,
|
||||||
SortMode = GridOptions.SortModeSingle,
|
SortMode = GridOptions.SortModeSingle,
|
||||||
FilterRowJson = DefaultFilterRowJson(),
|
FilterRowJson = DefaultFilterRowJson(),
|
||||||
HeaderFilterJson = DefaultHeaderFilterJson(),
|
HeaderFilterJson = DefaultHeaderFilterJson(),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -138,7 +138,11 @@ public class ListFormSeedDataApplier(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Satiri ekler; kayit eklendiyse <c>true</c>, ayni anahtarli kayit zaten varsa <c>false</c> doner.</summary>
|
/// <summary>
|
||||||
|
/// Satiri ekler; kayit eklendiyse <c>true</c>, ayni kayit zaten varsa <c>false</c> doner.
|
||||||
|
/// Dosyada anahtar yoksa (identity kolonlu tablolar) satir diger alanlarinin tamami uzerinden
|
||||||
|
/// eslesir ve anahtar veritabanina biraktirilir.
|
||||||
|
/// </summary>
|
||||||
private async Task<bool> ApplyRowAsync(
|
private async Task<bool> ApplyRowAsync(
|
||||||
ListForm listForm,
|
ListForm listForm,
|
||||||
List<ListFormField> fields,
|
List<ListFormField> fields,
|
||||||
|
|
@ -154,37 +158,59 @@ public class ListFormSeedDataApplier(
|
||||||
row.GetValueOrDefault(keyFieldName));
|
row.GetValueOrDefault(keyFieldName));
|
||||||
|
|
||||||
object[] keys = [keyValue];
|
object[] keys = [keyValue];
|
||||||
|
var hasKey = keyValue != null;
|
||||||
|
|
||||||
|
var insertParameters = BuildParameters(fields, row, keyFieldName, includeKey: hasKey);
|
||||||
|
|
||||||
// Var olan kayda dokunulmaz: veritabanindaki guncel deger, dosyadaki eski degerle ezilmemeli.
|
// Var olan kayda dokunulmaz: veritabanindaki guncel deger, dosyadaki eski degerle ezilmemeli.
|
||||||
if (await ExistsAsync(listForm, keyFieldName, keyValue, repository, connectionString))
|
var match = hasKey
|
||||||
|
? new Dictionary<string, object> { [keyFieldName] = keyValue }
|
||||||
|
: new Dictionary<string, object>(insertParameters);
|
||||||
|
|
||||||
|
if (!hasKey && PlatformConsts.IsMultiTenant && listForm.IsTenant)
|
||||||
|
{
|
||||||
|
match["TenantId"] = currentTenant.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await ExistsAsync(listForm, match, repository, connectionString))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var insertParameters = BuildParameters(fields, row, keyFieldName, includeKey: true);
|
|
||||||
await MergeDefaultsAsync(listForm, fields, OperationEnum.Insert, keys, insertParameters);
|
await MergeDefaultsAsync(listForm, fields, OperationEnum.Insert, keys, insertParameters);
|
||||||
|
|
||||||
// Insert varsayilanlari anahtari @NEWID ile uretir; dosyadaki anahtar korunmazsa ayni
|
if (hasKey)
|
||||||
// dosya her uygulandiginda yeni kayit olusurdu.
|
{
|
||||||
insertParameters[keyFieldName] = keyValue;
|
// Insert varsayilanlari anahtari @NEWID ile uretir; dosyadaki anahtar korunmazsa ayni
|
||||||
|
// dosya her uygulandiginda yeni kayit olusurdu.
|
||||||
|
insertParameters[keyFieldName] = keyValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Anahtari veritabani uretir; parametre listesinde kalirsa identity kolonuna
|
||||||
|
// acik deger yazilmaya calisilir.
|
||||||
|
insertParameters.Remove(keyFieldName);
|
||||||
|
}
|
||||||
|
|
||||||
var insertSql = queryManager.GenerateQuery(listForm, fields, insertParameters, OperationEnum.Insert, dataSourceType, keys);
|
var insertSql = queryManager.GenerateQuery(listForm, fields, insertParameters, OperationEnum.Insert, dataSourceType, keys);
|
||||||
await repository.ExecuteAsync(insertSql, connectionString, insertParameters);
|
await repository.ExecuteAsync(insertSql, connectionString, insertParameters);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Ayni anahtara sahip bir kayit hedef tabloda var mi.</summary>
|
/// <summary>Verilen alan degerleriyle eslesen bir kayit hedef tabloda var mi.</summary>
|
||||||
private static async Task<bool> ExistsAsync(
|
private static async Task<bool> ExistsAsync(
|
||||||
ListForm listForm,
|
ListForm listForm,
|
||||||
string keyFieldName,
|
Dictionary<string, object> match,
|
||||||
object keyValue,
|
|
||||||
IDynamicDataRepository repository,
|
IDynamicDataRepository repository,
|
||||||
string connectionString)
|
string connectionString)
|
||||||
{
|
{
|
||||||
var sql = $"SELECT COUNT(1) FROM \"{listForm.SelectCommand}\" WHERE \"{keyFieldName}\" = @{keyFieldName}";
|
var where = string.Join(
|
||||||
var parameters = new Dictionary<string, object> { [keyFieldName] = keyValue };
|
" AND ",
|
||||||
|
match.Select(a => a.Value == null ? $"\"{a.Key}\" IS NULL" : $"\"{a.Key}\" = @{a.Key}"));
|
||||||
|
|
||||||
return await repository.ExecuteScalarAsync<int>(sql, connectionString, parameters) > 0;
|
var sql = $"SELECT COUNT(1) FROM \"{listForm.SelectCommand}\" WHERE {where}";
|
||||||
|
|
||||||
|
return await repository.ExecuteScalarAsync<int>(sql, connectionString, match) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,4 @@
|
||||||
{
|
{
|
||||||
"GlobalSearch": [
|
|
||||||
{
|
|
||||||
"system": "Platform",
|
|
||||||
"group": "Setting Definitions",
|
|
||||||
"term": "Abp.Account.Captcha.EndPoint",
|
|
||||||
"weight": "0.2",
|
|
||||||
"url": "/admin/list/App.SettingDefinitions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"system": "Platform",
|
|
||||||
"group": "Setting Definitions",
|
|
||||||
"term": "Abp.Account.IsSelfRegistrationEnabled",
|
|
||||||
"weight": "0.8",
|
|
||||||
"url": "/admin/list/App.SettingDefinitions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"system": "Platform",
|
|
||||||
"group": "Setting Definitions",
|
|
||||||
"term": "Abp.Account.IsSelfRegistrationEnabled",
|
|
||||||
"weight": "0.7",
|
|
||||||
"url": "/admin/list/App.SettingDefinitions"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ForumCategories": [
|
"ForumCategories": [
|
||||||
{
|
{
|
||||||
"Name": "Genel Tartışma",
|
"Name": "Genel Tartışma",
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ namespace Sozsoft.Platform.Data.Seeds;
|
||||||
public class TenantSeederDto
|
public class TenantSeederDto
|
||||||
{
|
{
|
||||||
//Saas
|
//Saas
|
||||||
public List<GlobalSearchSeedDto> GlobalSearch { get; set; }
|
|
||||||
public List<CustomEndpointSeedDto> CustomEndpoints { get; set; }
|
public List<CustomEndpointSeedDto> CustomEndpoints { get; set; }
|
||||||
public List<SequenceSeedDto> Sequences { get; set; }
|
public List<SequenceSeedDto> Sequences { get; set; }
|
||||||
|
|
||||||
|
|
@ -224,15 +223,6 @@ public class DepartmentSeedDto
|
||||||
public string ParentName { get; set; }
|
public string ParentName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GlobalSearchSeedDto
|
|
||||||
{
|
|
||||||
public string System { get; set; }
|
|
||||||
public string Group { get; set; }
|
|
||||||
public string Term { get; set; }
|
|
||||||
public string Weight { get; set; }
|
|
||||||
public string Url { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UomCategorySeedDto
|
public class UomCategorySeedDto
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
@ -430,7 +420,6 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
{
|
{
|
||||||
private readonly ILookupNormalizer _lookupNormalizer;
|
private readonly ILookupNormalizer _lookupNormalizer;
|
||||||
private readonly IRepository<Branch, Guid> _branchRepository;
|
private readonly IRepository<Branch, Guid> _branchRepository;
|
||||||
private readonly IRepository<GlobalSearch, int> _globalSearch;
|
|
||||||
private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository;
|
private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository;
|
||||||
private readonly IRepository<ReportCategory, Guid> _reportCategoriesRepository;
|
private readonly IRepository<ReportCategory, Guid> _reportCategoriesRepository;
|
||||||
private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository;
|
private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository;
|
||||||
|
|
@ -471,7 +460,6 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
ILookupNormalizer lookupNormalizer,
|
ILookupNormalizer lookupNormalizer,
|
||||||
IIdentityUserRepository repositoryUser,
|
IIdentityUserRepository repositoryUser,
|
||||||
IRepository<Branch, Guid> branchRepository,
|
IRepository<Branch, Guid> branchRepository,
|
||||||
IRepository<GlobalSearch, int> globalSearch,
|
|
||||||
IRepository<UomCategory, string> uomCategoryRepository,
|
IRepository<UomCategory, string> uomCategoryRepository,
|
||||||
IRepository<Uom, string> uomRepository,
|
IRepository<Uom, string> uomRepository,
|
||||||
IRepository<SkillType, string> skillTypeRepository,
|
IRepository<SkillType, string> skillTypeRepository,
|
||||||
|
|
@ -510,7 +498,6 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
_lookupNormalizer = lookupNormalizer;
|
_lookupNormalizer = lookupNormalizer;
|
||||||
_repositoryUser = repositoryUser;
|
_repositoryUser = repositoryUser;
|
||||||
_branchRepository = branchRepository;
|
_branchRepository = branchRepository;
|
||||||
_globalSearch = globalSearch;
|
|
||||||
_uomCategoryRepository = uomCategoryRepository;
|
_uomCategoryRepository = uomCategoryRepository;
|
||||||
_uomRepository = uomRepository;
|
_uomRepository = uomRepository;
|
||||||
_skillTypeRepository = skillTypeRepository;
|
_skillTypeRepository = skillTypeRepository;
|
||||||
|
|
@ -559,21 +546,6 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
|
|
||||||
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||||
|
|
||||||
foreach (var item in items.GlobalSearch)
|
|
||||||
{
|
|
||||||
if (!await _globalSearch.AnyAsync(x => x.System == item.System && x.Group == item.Group && x.Term == item.Term))
|
|
||||||
{
|
|
||||||
await _globalSearch.InsertAsync(new GlobalSearch
|
|
||||||
{
|
|
||||||
System = item.System,
|
|
||||||
Group = item.Group,
|
|
||||||
Term = item.Term,
|
|
||||||
Weight = item.Weight,
|
|
||||||
Url = item.Url
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in items.UomCategories)
|
foreach (var item in items.UomCategories)
|
||||||
{
|
{
|
||||||
var exists = await _uomCategoryRepository.AnyAsync(x => x.Name == item.Name);
|
var exists = await _uomCategoryRepository.AnyAsync(x => x.Name == item.Name);
|
||||||
|
|
|
||||||
28
configs/seeds/host/data/App.Definitions.GlobalSearch.json
Normal file
28
configs/seeds/host/data/App.Definitions.GlobalSearch.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"ListFormCode": "App.Definitions.GlobalSearch",
|
||||||
|
"KeyFieldName": "Id",
|
||||||
|
"GeneratedAt": "2026-09-04T00:00:00Z",
|
||||||
|
"Rows": [
|
||||||
|
{
|
||||||
|
"System": "Platform",
|
||||||
|
"Group": "Setting Definitions",
|
||||||
|
"Term": "Abp.Account.Captcha.EndPoint",
|
||||||
|
"Url": "/admin/list/App.SettingDefinitions",
|
||||||
|
"Weight": "0.2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"System": "Platform",
|
||||||
|
"Group": "Setting Definitions",
|
||||||
|
"Term": "Abp.Account.IsSelfRegistrationEnabled",
|
||||||
|
"Url": "/admin/list/App.SettingDefinitions",
|
||||||
|
"Weight": "0.8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"System": "Platform",
|
||||||
|
"Group": "Setting Definitions",
|
||||||
|
"Term": "Abp.Account.IsSelfRegistrationEnabled",
|
||||||
|
"Url": "/admin/list/App.SettingDefinitions",
|
||||||
|
"Weight": "0.7"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue