From a1a76b1a95ba5fd420637248ef3ce39ab917c6fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?=
<76204082+iamsedatozturk@users.noreply.github.com>
Date: Fri, 4 Sep 2026 14:25:35 +0300
Subject: [PATCH] seed/data Seeder GlobalSearch
---
.github/instructions/lowcode.instructions.md | 3 ++
.../Migrations/ListFormSeeder_Saas.cs | 4 ++
.../Data/ListFormSeedDataApplier.cs | 52 ++++++++++++++-----
.../Seeds/TenantData.json | 23 --------
.../Seeds/TenantDataSeeder.cs | 28 ----------
.../data/App.Definitions.GlobalSearch.json | 28 ++++++++++
6 files changed, 74 insertions(+), 64 deletions(-)
create mode 100644 configs/seeds/host/data/App.Definitions.GlobalSearch.json
diff --git a/.github/instructions/lowcode.instructions.md b/.github/instructions/lowcode.instructions.md
index 2d9fc436..4e4ba8be 100644
--- a/.github/instructions/lowcode.instructions.md
+++ b/.github/instructions/lowcode.instructions.md
@@ -3434,6 +3434,9 @@ Kurallar:
- **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.
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
kayıt güncellenmez (her migrate'te ekrandaki güncel değerler dosyadaki eskisiyle ezilmesin diye)
ve dosyada olmayan satır silinmez.
diff --git a/api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_Saas.cs b/api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_Saas.cs
index 7bb16ed3..8c2d4c5f 100644
--- a/api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_Saas.cs
+++ b/api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_Saas.cs
@@ -1145,6 +1145,10 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.GlobalSearch)),
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.Int32,
+ SeedFilePath = SeedPathResolver.GetDataFilePath(listFormName),
+ SeedSyncInsert = false,
+ SeedSyncUpdate = false,
+ SeedSyncDelete = false,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
diff --git a/api/src/Sozsoft.Platform.Domain/Data/ListFormSeedDataApplier.cs b/api/src/Sozsoft.Platform.Domain/Data/ListFormSeedDataApplier.cs
index f03d3879..18ba6d06 100644
--- a/api/src/Sozsoft.Platform.Domain/Data/ListFormSeedDataApplier.cs
+++ b/api/src/Sozsoft.Platform.Domain/Data/ListFormSeedDataApplier.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -138,7 +138,11 @@ public class ListFormSeedDataApplier(
}
}
- /// Satiri ekler; kayit eklendiyse true, ayni anahtarli kayit zaten varsa false doner.
+ ///
+ /// Satiri ekler; kayit eklendiyse true, ayni kayit zaten varsa false doner.
+ /// Dosyada anahtar yoksa (identity kolonlu tablolar) satir diger alanlarinin tamami uzerinden
+ /// eslesir ve anahtar veritabanina biraktirilir.
+ ///
private async Task ApplyRowAsync(
ListForm listForm,
List fields,
@@ -154,37 +158,59 @@ public class ListFormSeedDataApplier(
row.GetValueOrDefault(keyFieldName));
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.
- if (await ExistsAsync(listForm, keyFieldName, keyValue, repository, connectionString))
+ var match = hasKey
+ ? new Dictionary { [keyFieldName] = keyValue }
+ : new Dictionary(insertParameters);
+
+ if (!hasKey && PlatformConsts.IsMultiTenant && listForm.IsTenant)
+ {
+ match["TenantId"] = currentTenant.Id;
+ }
+
+ if (await ExistsAsync(listForm, match, repository, connectionString))
{
return false;
}
- var insertParameters = BuildParameters(fields, row, keyFieldName, includeKey: true);
await MergeDefaultsAsync(listForm, fields, OperationEnum.Insert, keys, insertParameters);
- // Insert varsayilanlari anahtari @NEWID ile uretir; dosyadaki anahtar korunmazsa ayni
- // dosya her uygulandiginda yeni kayit olusurdu.
- insertParameters[keyFieldName] = keyValue;
+ if (hasKey)
+ {
+ // 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);
await repository.ExecuteAsync(insertSql, connectionString, insertParameters);
return true;
}
- /// Ayni anahtara sahip bir kayit hedef tabloda var mi.
+ /// Verilen alan degerleriyle eslesen bir kayit hedef tabloda var mi.
private static async Task ExistsAsync(
ListForm listForm,
- string keyFieldName,
- object keyValue,
+ Dictionary match,
IDynamicDataRepository repository,
string connectionString)
{
- var sql = $"SELECT COUNT(1) FROM \"{listForm.SelectCommand}\" WHERE \"{keyFieldName}\" = @{keyFieldName}";
- var parameters = new Dictionary { [keyFieldName] = keyValue };
+ var where = string.Join(
+ " AND ",
+ match.Select(a => a.Value == null ? $"\"{a.Key}\" IS NULL" : $"\"{a.Key}\" = @{a.Key}"));
- return await repository.ExecuteScalarAsync(sql, connectionString, parameters) > 0;
+ var sql = $"SELECT COUNT(1) FROM \"{listForm.SelectCommand}\" WHERE {where}";
+
+ return await repository.ExecuteScalarAsync(sql, connectionString, match) > 0;
}
///
diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
index bda2ec50..bccf6a89 100644
--- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
+++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
@@ -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": [
{
"Name": "Genel Tartışma",
diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantDataSeeder.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantDataSeeder.cs
index df8b99f6..c7887fdc 100644
--- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantDataSeeder.cs
+++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantDataSeeder.cs
@@ -21,7 +21,6 @@ namespace Sozsoft.Platform.Data.Seeds;
public class TenantSeederDto
{
//Saas
- public List GlobalSearch { get; set; }
public List CustomEndpoints { get; set; }
public List Sequences { get; set; }
@@ -224,15 +223,6 @@ public class DepartmentSeedDto
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 Guid Id { get; set; }
@@ -430,7 +420,6 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
{
private readonly ILookupNormalizer _lookupNormalizer;
private readonly IRepository _branchRepository;
- private readonly IRepository _globalSearch;
private readonly IRepository _customEndpointRepository;
private readonly IRepository _reportCategoriesRepository;
private readonly IRepository _reportTemplatesRepository;
@@ -471,7 +460,6 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
ILookupNormalizer lookupNormalizer,
IIdentityUserRepository repositoryUser,
IRepository branchRepository,
- IRepository globalSearch,
IRepository uomCategoryRepository,
IRepository uomRepository,
IRepository skillTypeRepository,
@@ -510,7 +498,6 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
_lookupNormalizer = lookupNormalizer;
_repositoryUser = repositoryUser;
_branchRepository = branchRepository;
- _globalSearch = globalSearch;
_uomCategoryRepository = uomCategoryRepository;
_uomRepository = uomRepository;
_skillTypeRepository = skillTypeRepository;
@@ -559,21 +546,6 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
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)
{
var exists = await _uomCategoryRepository.AnyAsync(x => x.Name == item.Name);
diff --git a/configs/seeds/host/data/App.Definitions.GlobalSearch.json b/configs/seeds/host/data/App.Definitions.GlobalSearch.json
new file mode 100644
index 00000000..4d1f31e2
--- /dev/null
+++ b/configs/seeds/host/data/App.Definitions.GlobalSearch.json
@@ -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"
+ }
+ ]
+}