SaveDbTableColumns

This commit is contained in:
Sedat Öztürk 2026-06-24 19:59:51 +03:00
parent 741710fc72
commit c842bd6843
12 changed files with 907 additions and 88 deletions

View file

@ -1142,6 +1142,14 @@
"dataSourceCode": "Default",
"beforeSp": "Adm_T_DatabaseBackupAll",
"afterSp": "Adm_T_DatabaseBackupFilesDeleteAll"
},
{
"name": "AI Save DbTableColumns",
"cron": "0 3 * * *",
"workerType": "BackupWorker",
"isActive": true,
"dataSourceCode": "Default",
"beforeSp": "Sas_H_ListFormFieldsDictionaryJson_SaveDbTableColumns"
}
],
"ContactTitles": [

View file

@ -0,0 +1,362 @@
USE [Sozsoft]
GO
-- v12: Fully dynamic lookup dictionary. No hard-coded field-specific lookup rules.
CREATE OR ALTER PROCEDURE [dbo].[Sas_H_ListFormFieldsDictionaryJson]
@DefinitionCultureName NVARCHAR(10) = N'en', -- ListForm/ListFormField kayıt kültürü. Genelde en.
@UiCultureName NVARCHAR(10) = N'tr', -- Kullanıcıya görünen dil. Genelde tr.
@ListFormCode NVARCHAR(64) = NULL, -- Tek form istenirse.
@OnlyBaseDefinitions BIT = 1, -- 1 = UserId/RoleId özel kayıtları hariç.
@ResourceName NVARCHAR(64) = NULL -- Dil kaynağı filtrelenmek istenirse.
AS
BEGIN
SET NOCOUNT ON;
;WITH ListFormSource AS
(
SELECT
L.Id,
L.ListFormCode,
L.CultureName,
L.Name,
NameValue = LT_NAME.[Value],
L.Title,
TitleValue = LT_TITLE.[Value],
L.Description,
DescriptionValue = LT_DESC.[Value],
L.TableName,
SelectCommandText = NULLIF(LTRIM(RTRIM(CAST(L.SelectCommand AS NVARCHAR(MAX)))), N''),
L.SelectCommandType,
L.KeyFieldName,
L.KeyFieldDbSourceType,
L.ListFormType,
L.PageSize,
L.SortMode,
L.IsTenant,
L.IsBranch,
L.IsOrganizationUnit,
L.IsSubForm,
L.UserId,
L.RoleId
FROM dbo.Sas_H_ListForm L
OUTER APPLY
(
SELECT TOP (1) LT.[Value]
FROM dbo.Sas_H_LanguageText LT
WHERE LT.CultureName = @UiCultureName
AND LT.[Key] = L.Name
AND (@ResourceName IS NULL OR LT.ResourceName = @ResourceName)
ORDER BY LT.ResourceName
) LT_NAME
OUTER APPLY
(
SELECT TOP (1) LT.[Value]
FROM dbo.Sas_H_LanguageText LT
WHERE LT.CultureName = @UiCultureName
AND LT.[Key] = L.Title
AND (@ResourceName IS NULL OR LT.ResourceName = @ResourceName)
ORDER BY LT.ResourceName
) LT_TITLE
OUTER APPLY
(
SELECT TOP (1) LT.[Value]
FROM dbo.Sas_H_LanguageText LT
WHERE LT.CultureName = @UiCultureName
AND LT.[Key] = L.Description
AND (@ResourceName IS NULL OR LT.ResourceName = @ResourceName)
ORDER BY LT.ResourceName
) LT_DESC
WHERE
(@DefinitionCultureName IS NULL OR L.CultureName = @DefinitionCultureName)
AND (@ListFormCode IS NULL OR L.ListFormCode = @ListFormCode)
AND
(
@OnlyBaseDefinitions = 0
OR (L.UserId IS NULL AND L.RoleId IS NULL)
)
)
SELECT
(
SELECT
L.ListFormCode AS [formCode],
L.ListFormCode AS [listFormCode],
L.CultureName AS [definitionCulture],
@UiCultureName AS [uiCulture],
ISNULL(CAST(L.NameValue AS NVARCHAR(MAX)), ISNULL(L.Name, N'')) AS [displayName],
ISNULL(CAST(L.NameValue AS NVARCHAR(MAX)), ISNULL(L.Name, N'')) AS [nameValue],
ISNULL(CAST(L.TitleValue AS NVARCHAR(MAX)), ISNULL(L.Title, N'')) AS [title],
ISNULL(CAST(L.TitleValue AS NVARCHAR(MAX)), ISNULL(L.Title, N'')) AS [titleValue],
ISNULL(CAST(L.DescriptionValue AS NVARCHAR(MAX)), ISNULL(L.Description, N'')) AS [description],
ISNULL(CAST(L.DescriptionValue AS NVARCHAR(MAX)), ISNULL(L.Description, N'')) AS [descriptionValue],
ISNULL(L.TableName, N'') AS [sqlTableName],
ISNULL(L.TableName, N'') AS [tableName],
ISNULL(L.SelectCommandText, N'') AS [selectCommand],
ISNULL(COALESCE(NULLIF(L.TableName, N''), L.SelectCommandText), N'') AS [sqlSourceName],
CASE
WHEN COALESCE(NULLIF(L.TableName, N''), L.SelectCommandText) IS NULL THEN N'unknown'
WHEN UPPER(LTRIM(COALESCE(NULLIF(L.TableName, N''), L.SelectCommandText))) LIKE N'SELECT%' THEN N'selectSql'
ELSE N'table'
END AS [sourceKind],
L.SelectCommandType AS [selectCommandType],
ISNULL(L.KeyFieldName, N'') AS [primaryKeyColumn],
ISNULL(L.KeyFieldName, N'') AS [keyFieldName],
L.KeyFieldDbSourceType AS [keyFieldDbSourceType],
L.ListFormType AS [listFormType],
L.PageSize AS [pageSize],
L.SortMode AS [sortMode],
CONVERT(bit, L.IsTenant) AS [isTenant],
CONVERT(bit, L.IsBranch) AS [isBranch],
CONVERT(bit, L.IsOrganizationUnit) AS [isOrganizationUnit],
CONVERT(bit, L.IsSubForm) AS [isSubForm],
CONCAT_WS(N' ',
L.ListFormCode,
L.TableName,
L.SelectCommandText,
ISNULL(CAST(L.NameValue AS NVARCHAR(MAX)), L.Name),
ISNULL(CAST(L.TitleValue AS NVARCHAR(MAX)), L.Title),
ISNULL(CAST(L.DescriptionValue AS NVARCHAR(MAX)), L.Description)
) AS [searchText],
JSON_QUERY
(
(
SELECT
F.FieldName AS [sqlColumnName],
F.FieldName AS [field],
ISNULL(CAST(LT_CAP.[Value] AS NVARCHAR(MAX)), ISNULL(F.CaptionName, N'')) AS [displayName],
ISNULL(CAST(LT_CAP.[Value] AS NVARCHAR(MAX)), ISNULL(F.CaptionName, N'')) AS [captionValue],
ISNULL(F.CaptionName, N'') AS [captionKey],
F.SourceDbType AS [sourceDbType],
SC.SqlDataType AS [sqlDataType],
SC.SqlMaxLength AS [sqlMaxLength],
CONVERT(bit, CASE
WHEN SC.SqlDataType = N'bit' THEN 1
WHEN F.FieldName LIKE N'Is%' THEN 1
WHEN F.FieldName LIKE N'Has%' THEN 1
WHEN F.FieldName IN (N'Monday', N'Tuesday', N'Wednesday', N'Thursday', N'Friday', N'Saturday', N'Sunday') THEN 1
WHEN F.FieldName IN (N'EmailConfirmed', N'TwoFactorEnabled', N'IsVerified', N'IsDefault', N'IsPublic', N'IsEnabled', N'IsPublished', N'IsPinned', N'IsAnonymous', N'IsFixed', N'IsCustomized', N'IsEncrypted', N'IsInherited', N'ZipRequired', N'StateRequired') THEN 1
ELSE 0
END) AS [isBooleanColumn],
F.ListOrderNo AS [listOrderNo],
F.Width AS [width],
F.Alignment AS [alignment],
F.Format AS [format],
CONVERT(bit, ISNULL(F.Visible, 1)) AS [isVisible],
CONVERT(bit, ISNULL(F.IsActive, 1)) AS [isActive],
CONVERT(bit, ISNULL(F.AllowSearch, 0)) AS [allowSearch],
CONVERT(bit, ISNULL(F.AllowEditing, 1)) AS [allowEditing],
CONVERT(bit, ISNULL(F.AllowAdding, 1)) AS [allowAdding],
CONVERT(bit, CASE WHEN LJ.LookupJsonText IS NOT NULL THEN 1 ELSE 0 END) AS [hasLookup],
CONVERT(bit, CASE WHEN LJ.LookupJsonText IS NOT NULL THEN 1 ELSE 0 END) AS [isLookupColumn],
LJ.LookupJsonText AS [lookupJsonText],
JSON_QUERY(CASE WHEN ISJSON(LJ.LookupJsonText) = 1 THEN LJ.LookupJsonText ELSE NULL END) AS [lookupJson],
LJ.JoinTableJsonText AS [joinTableJsonText],
JSON_QUERY(CASE WHEN ISJSON(LJ.JoinTableJsonText) = 1 THEN LJ.JoinTableJsonText ELSE NULL END) AS [joinTableJson],
LKE.ParsedLookupTableName AS [parsedLookupTableName],
LK.ParsedLookupValueColumn AS [parsedLookupValueColumn],
LK.ParsedLookupDisplayColumn AS [parsedLookupDisplayColumn],
CASE WHEN ISJSON(LJ.LookupJsonText) = 1 THEN COALESCE(
JSON_VALUE(LJ.LookupJsonText, '$.listFormCode'),
JSON_VALUE(LJ.LookupJsonText, '$.formCode'),
JSON_VALUE(LJ.LookupJsonText, '$.lookupListFormCode'),
JSON_VALUE(LJ.LookupJsonText, '$.dataSource.listFormCode'),
JSON_VALUE(LJ.LookupJsonText, '$.dataSource.formCode')
) END AS [lookupListFormCode],
COALESCE(
CASE WHEN ISJSON(LJ.LookupJsonText) = 1 THEN COALESCE(
JSON_VALUE(LJ.LookupJsonText, '$.tableName'),
JSON_VALUE(LJ.LookupJsonText, '$.sqlTableName'),
JSON_VALUE(LJ.LookupJsonText, '$.lookupTableName'),
JSON_VALUE(LJ.LookupJsonText, '$.dataSource.tableName'),
JSON_VALUE(LJ.LookupJsonText, '$.dataSource.sqlTableName')
) END,
LKE.ParsedLookupTableName
) AS [lookupTableName],
COALESCE(
CASE WHEN ISJSON(LJ.LookupJsonText) = 1 THEN COALESCE(
JSON_VALUE(LJ.LookupJsonText, '$.valueExpr'),
JSON_VALUE(LJ.LookupJsonText, '$.valueField'),
JSON_VALUE(LJ.LookupJsonText, '$.valueColumn'),
JSON_VALUE(LJ.LookupJsonText, '$.keyField'),
JSON_VALUE(LJ.LookupJsonText, '$.keyFieldName')
) END,
LK.ParsedLookupValueColumn
) AS [lookupValueColumn],
COALESCE(
CASE WHEN ISJSON(LJ.LookupJsonText) = 1 THEN COALESCE(
JSON_VALUE(LJ.LookupJsonText, '$.displayExpr'),
JSON_VALUE(LJ.LookupJsonText, '$.displayField'),
JSON_VALUE(LJ.LookupJsonText, '$.displayColumn'),
JSON_VALUE(LJ.LookupJsonText, '$.textField'),
JSON_VALUE(LJ.LookupJsonText, '$.textColumn'),
JSON_VALUE(LJ.LookupJsonText, '$.nameField'),
JSON_VALUE(LJ.LookupJsonText, '$.nameColumn')
) END,
LK.ParsedLookupDisplayColumn
) AS [lookupDisplayColumn],
CASE
WHEN LJ.LookupJsonText IS NOT NULL AND F.FieldName NOT LIKE N'%Id' AND COALESCE(LK.ParsedLookupValueColumn, N'') IN (N'Name', N'Code', N'Key', N'Value') THEN N'direct-string'
WHEN LJ.LookupJsonText IS NOT NULL OR F.FieldName LIKE N'%Id' THEN N'convert-nvarchar-safe'
END AS [lookupJoinMode],
CASE
WHEN LJ.LookupJsonText IS NOT NULL AND F.FieldName NOT LIKE N'%Id' AND COALESCE(LK.ParsedLookupValueColumn, N'') IN (N'Name', N'Code', N'Key', N'Value') THEN N'ON base.lookupColumn = lookup.valueColumn'
WHEN LJ.LookupJsonText IS NOT NULL OR F.FieldName LIKE N'%Id' THEN N'ON CONVERT(NVARCHAR(100), base.lookupColumn) = CONVERT(NVARCHAR(100), lookup.valueColumn)'
END AS [lookupJoinRule],
CONVERT(bit, CASE
WHEN LJ.LookupJsonText IS NOT NULL
AND F.FieldName NOT LIKE N'%Id'
THEN 1 ELSE 0 END) AS [lookupFallbackToSourceColumn],
CASE WHEN LJ.LookupJsonText IS NOT NULL THEN CONCAT_WS(N' ', F.FieldName, F.CaptionName, CAST(LT_CAP.[Value] AS NVARCHAR(MAX)), LJ.LookupJsonText, LJ.JoinTableJsonText) END AS [lookupSearchText],
CONVERT(bit, CASE WHEN F.FieldName IN (N'IsActive', N'IsEnabled', N'IsPublished') THEN 1 ELSE 0 END) AS [isActiveStatusColumn],
CONVERT(bit, CASE WHEN F.FieldName IN (N'IsDeleted', N'Deleted', N'IsRemoved') THEN 1 ELSE 0 END) AS [isDeletedStatusColumn],
CONVERT(bit, CASE
WHEN F.FieldName LIKE N'%Password%'
OR F.FieldName LIKE N'%ConnectionString%'
OR F.FieldName LIKE N'%Token%'
OR F.FieldName LIKE N'%Secret%'
OR F.FieldName LIKE N'%ApiKey%'
OR F.FieldName LIKE N'%PrivateKey%'
THEN 1 ELSE 0 END) AS [isSensitive],
CONVERT(bit, CASE
WHEN ISNULL(F.Visible, 1) = 1
AND ISNULL(F.IsActive, 1) = 1
AND F.FieldName NOT LIKE N'%Password%'
AND F.FieldName NOT LIKE N'%ConnectionString%'
AND F.FieldName NOT LIKE N'%Token%'
AND F.FieldName NOT LIKE N'%Secret%'
AND F.FieldName NOT LIKE N'%ApiKey%'
AND F.FieldName NOT LIKE N'%PrivateKey%'
AND F.FieldName NOT IN (N'Avatar', N'ExtraProperties')
THEN 1 ELSE 0 END) AS [isDefaultSelectColumn]
FROM dbo.Sas_H_ListFormField F
OUTER APPLY
(
SELECT
LookupJsonText = NULLIF(LTRIM(RTRIM(CAST(F.LookupJson AS NVARCHAR(MAX)))), N''),
JoinTableJsonText = NULLIF(LTRIM(RTRIM(CAST(F.JoinTableJson AS NVARCHAR(MAX)))), N'')
) LJ
OUTER APPLY
(
SELECT TOP (1)
SqlDataType = TYPE_NAME(C.user_type_id),
SqlMaxLength = C.max_length,
SqlPrecision = C.precision,
SqlScale = C.scale
FROM sys.schemas S
INNER JOIN sys.tables TBL ON TBL.schema_id = S.schema_id
INNER JOIN sys.columns C ON C.object_id = TBL.object_id
WHERE S.name = N'dbo'
AND TBL.name = L.TableName
AND C.name = F.FieldName
) SC
OUTER APPLY
(
SELECT
CleanLookupSql = NULLIF(
LTRIM(RTRIM(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(CAST(F.LookupJson AS NVARCHAR(MAX)), N'\\u0022', N''),
N'\u0022', N''),
N'"', N''),
N'"', N''),
N'[', N''),
N']', N''),
N'`', N''),
N'\', N''),
CHAR(13) + CHAR(10), N' ')
)),
N'')
) LKC
OUTER APPLY
(
SELECT
UpperLookupSql = UPPER(LKC.CleanLookupSql),
FromPos = CHARINDEX(N' FROM ', UPPER(LKC.CleanLookupSql)),
OrderPos = CHARINDEX(N' ORDER BY ', UPPER(LKC.CleanLookupSql)),
WherePos = CHARINDEX(N' WHERE ', UPPER(LKC.CleanLookupSql)),
GroupPos = CHARINDEX(N' GROUP BY ', UPPER(LKC.CleanLookupSql))
) LKP
OUTER APPLY
(
SELECT
StopPos = CASE
WHEN LKP.FromPos <= 0 THEN 0
WHEN LKP.WherePos > LKP.FromPos THEN LKP.WherePos
WHEN LKP.GroupPos > LKP.FromPos THEN LKP.GroupPos
WHEN LKP.OrderPos > LKP.FromPos THEN LKP.OrderPos
ELSE LEN(LKC.CleanLookupSql) + 1
END,
SelectPart = CASE WHEN LKP.FromPos > 0 THEN LTRIM(RTRIM(SUBSTRING(LKC.CleanLookupSql, 7, LKP.FromPos - 7))) END
) LKS
OUTER APPLY
(
SELECT
TablePart = CASE WHEN LKP.FromPos > 0 AND LKS.StopPos > LKP.FromPos
THEN LTRIM(RTRIM(SUBSTRING(LKC.CleanLookupSql, LKP.FromPos + 6, LKS.StopPos - (LKP.FromPos + 6))))
END,
KeyAsPos = CHARINDEX(N' AS KEY', UPPER(ISNULL(LKS.SelectPart, N''))),
NameAsPos = CHARINDEX(N' AS NAME', UPPER(ISNULL(LKS.SelectPart, N'')))
) LKT
OUTER APPLY
(
SELECT
ParsedLookupTableName = NULLIF(REPLACE(REPLACE(LEFT(LKT.TablePart, CHARINDEX(N' ', LKT.TablePart + N' ') - 1), N'dbo.', N''), N'DBO.', N''), N''),
KeyExprChunk = CASE WHEN LKT.KeyAsPos > 0 THEN LTRIM(RTRIM(SUBSTRING(LKS.SelectPart, 1, LKT.KeyAsPos - 1))) END,
NameExprChunk = CASE WHEN LKT.NameAsPos > 0 THEN LTRIM(RTRIM(SUBSTRING(LKS.SelectPart, 1, LKT.NameAsPos - 1))) END
) LKE
OUTER APPLY
(
SELECT
ParsedLookupValueColumn = NULLIF(LTRIM(RTRIM(REPLACE(REPLACE(
CASE WHEN LKE.KeyExprChunk IS NOT NULL THEN
RIGHT(LKE.KeyExprChunk, CHARINDEX(N',', REVERSE(LKE.KeyExprChunk) + N',') - 1)
END, N'SELECT', N''), N'select', N''))), N''),
ParsedLookupDisplayColumn = NULLIF(LTRIM(RTRIM(REPLACE(REPLACE(
CASE WHEN LKE.NameExprChunk IS NOT NULL THEN
RIGHT(LKE.NameExprChunk, CHARINDEX(N',', REVERSE(LKE.NameExprChunk) + N',') - 1)
END, N'SELECT', N''), N'select', N''))), N'')
) LK
OUTER APPLY
(
SELECT TOP (1) LT.[Value]
FROM dbo.Sas_H_LanguageText LT
WHERE LT.CultureName = @UiCultureName
AND LT.[Key] = F.CaptionName
AND (@ResourceName IS NULL OR LT.ResourceName = @ResourceName)
ORDER BY LT.ResourceName
) LT_CAP
WHERE
F.ListFormCode = L.ListFormCode
AND F.CultureName = L.CultureName
AND (@DefinitionCultureName IS NULL OR F.CultureName = @DefinitionCultureName)
AND
(
@OnlyBaseDefinitions = 0
OR (F.UserId IS NULL AND F.RoleId IS NULL)
)
ORDER BY
ISNULL(F.ListOrderNo, 999999),
F.FieldName
FOR JSON PATH
)
) AS [fields]
FROM ListFormSource L
ORDER BY L.ListFormCode
FOR JSON PATH, ROOT('listForms')
) AS ListFormDataDictionaryJson;
END
GO

View file

@ -0,0 +1,153 @@
USE [Sozsoft]
GO
CREATE OR ALTER PROCEDURE [dbo].[Sas_H_ListFormFieldsDictionaryJson_SaveDbTableColumns]
@TenantName NVARCHAR(128) = N'Sozsoft',
@DefinitionCultureName NVARCHAR(10) = N'en',
@UiCultureName NVARCHAR(10) = N'tr',
@ListFormCode NVARCHAR(64) = NULL,
@OnlyBaseDefinitions BIT = 1,
@ResourceName NVARCHAR(64) = NULL,
@MaxForms INT = 500,
@DeactivatePrevious BIT = 1,
@Note NVARCHAR(4000) = NULL
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF OBJECT_ID(N'dbo.Sas_H_ListFormFieldsDictionaryJson', N'P') IS NULL
BEGIN
THROW 51000, 'dbo.Sas_H_ListFormFieldsDictionaryJson bulunamadı. Önce mevcut JSON üreten SP kurulmalıdır.', 1;
END;
DECLARE @Result TABLE
(
ListFormDataDictionaryJson NVARCHAR(MAX) NULL
);
INSERT INTO @Result (ListFormDataDictionaryJson)
EXEC dbo.Sas_H_ListFormFieldsDictionaryJson
@DefinitionCultureName = @DefinitionCultureName,
@UiCultureName = @UiCultureName,
@ListFormCode = @ListFormCode,
@OnlyBaseDefinitions = @OnlyBaseDefinitions,
@ResourceName = @ResourceName;
DECLARE @JsonData NVARCHAR(MAX);
SELECT TOP (1)
@JsonData = ListFormDataDictionaryJson
FROM @Result
WHERE NULLIF(LTRIM(RTRIM(ListFormDataDictionaryJson)), N'') IS NOT NULL;
IF @JsonData IS NULL
BEGIN
THROW 51001, 'JSON veri sözlüğü boş döndü. dbo.Sas_H_ListFormFieldsDictionaryJson çıktısını kontrol edin.', 1;
END;
IF ISJSON(@JsonData) <> 1
BEGIN
THROW 51002, 'Üretilen JsonData geçerli JSON değil.', 1;
END;
DECLARE @CacheKey NVARCHAR(512) = CONCAT(
N'ListFormJson|',
ISNULL(@TenantName, N''), N'|',
ISNULL(@DefinitionCultureName, N''), N'|',
ISNULL(@UiCultureName, N''), N'|',
ISNULL(@ListFormCode, N''), N'|',
CONVERT(NVARCHAR(1), ISNULL(@OnlyBaseDefinitions, 1)), N'|',
ISNULL(@ResourceName, N''), N'|',
CONVERT(NVARCHAR(20), ISNULL(@MaxForms, 500))
);
DECLARE @FormCount INT = 0;
DECLARE @FieldCount INT = 0;
DECLARE @JsonLength INT = LEN(@JsonData);
SELECT @FormCount = COUNT(1)
FROM OPENJSON(@JsonData, '$.listForms');
SELECT @FieldCount = COUNT(1)
FROM OPENJSON(@JsonData, '$.listForms') AS LF
CROSS APPLY OPENJSON(JSON_QUERY(LF.[value], '$.fields')) AS FF;
BEGIN TRAN;
IF @DeactivatePrevious = 1
BEGIN
UPDATE dbo.Sas_H_DbTableColumn
SET IsActive = 0
WHERE DictionaryType = N'ListFormJson'
AND CacheKey = @CacheKey
AND ISNULL(IsActive, 0) = 1;
END;
INSERT INTO dbo.Sas_H_DbTableColumn
(
TenantName,
DictionaryType,
DefinitionCultureName,
UiCultureName,
ListFormCode,
OnlyBaseDefinitions,
ResourceName,
MaxForms,
CacheKey,
JsonData,
FormCount,
FieldCount,
JsonLength,
IsActive,
RefreshedAt,
SourceProcedure,
Note
)
VALUES
(
ISNULL(@TenantName, N'Sozsoft'),
N'ListFormJson',
ISNULL(@DefinitionCultureName, N'en'),
ISNULL(@UiCultureName, N'tr'),
@ListFormCode,
ISNULL(@OnlyBaseDefinitions, 1),
@ResourceName,
ISNULL(@MaxForms, 500),
@CacheKey,
@JsonData,
@FormCount,
@FieldCount,
@JsonLength,
1,
SYSDATETIME(),
N'dbo.Sas_H_ListFormFieldsDictionaryJson',
@Note
);
COMMIT;
SELECT TOP (1)
TenantName,
DictionaryType,
DefinitionCultureName,
UiCultureName,
ListFormCode,
OnlyBaseDefinitions,
ResourceName,
MaxForms,
CacheKey,
FormCount,
FieldCount,
JsonLength,
IsActive,
RefreshedAt,
SourceProcedure,
Note
FROM dbo.Sas_H_DbTableColumn
WHERE DictionaryType = N'ListFormJson'
AND CacheKey = @CacheKey
AND IsActive = 1
ORDER BY RefreshedAt DESC;
END
GO

View file

@ -94,4 +94,5 @@ public enum TableNameEnum
VideoroomAttandance,
VideoroomChat,
Sequence,
DbTableColumn
}

View file

@ -12,6 +12,7 @@ public static class TableNameResolver
_map = new(StringComparer.OrdinalIgnoreCase)
{
// 🔹 SAAS TABLOLARI
{ nameof(TableNameEnum.DbTableColumn), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.LogEntry), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.AiBot), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.GlobalSearch), (TablePrefix.TenantByName, MenuPrefix.Saas) },

View file

@ -0,0 +1,25 @@
using System;
using Volo.Abp.Domain.Entities;
namespace Sozsoft.Platform.Entities;
public class DbTableColumn : Entity<Guid>
{
public string TenantName { get; set; }
public string DictionaryType { get; set; }
public string DefinitionCultureName { get; set; }
public string UiCultureName { get; set; }
public string? ListFormCode { get; set; }
public bool OnlyBaseDefinitions { get; set; }
public string? ResourceName { get; set; }
public int MaxForms { get; set; }
public string CacheKey { get; set; }
public string JsonData { get; set; }
public int FormCount { get; set; }
public int FieldCount { get; set; }
public int JsonLength { get; set; }
public bool IsActive { get; set; }
public DateTime RefreshedAt { get; set; }
public string? SourceProcedure { get; set; }
public string? Note { get; set; }
}

View file

@ -41,6 +41,7 @@ public class PlatformDbContext :
private readonly bool _isPostgreSql;
#region Saas
public DbSet<DbTableColumn> DbTableColumns { get; set; }
public DbSet<LogEntry> LogEntries { get; set; }
public DbSet<Tenant> Tenants { get; set; }
public DbSet<TenantConnectionString> TenantConnectionStrings { get; set; }
@ -1526,6 +1527,31 @@ public class PlatformDbContext :
b.HasIndex(x => new { x.TenantId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
});
builder.Entity<DbTableColumn>(b =>
{
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.DbTableColumn)), Prefix.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.Id).HasDefaultValueSql("NEWID()");
b.Property(x => x.TenantName).HasMaxLength(128).IsRequired().HasDefaultValue("Sozsoft");
b.Property(x => x.DictionaryType).HasMaxLength(50).IsRequired().HasDefaultValue("ListFormJson");
b.Property(x => x.DefinitionCultureName).HasMaxLength(10).IsRequired().HasDefaultValue("en");
b.Property(x => x.UiCultureName).HasMaxLength(10).IsRequired().HasDefaultValue("tr");
b.Property(x => x.ListFormCode).HasMaxLength(64);
b.Property(x => x.OnlyBaseDefinitions).HasDefaultValue(true);
b.Property(x => x.ResourceName).HasMaxLength(64);
b.Property(x => x.MaxForms).HasDefaultValue(500);
b.Property(x => x.CacheKey).HasMaxLength(512).IsRequired();
b.Property(x => x.JsonData).IsRequired();
b.Property(x => x.FormCount).HasDefaultValue(0);
b.Property(x => x.FieldCount).HasDefaultValue(0);
b.Property(x => x.JsonLength).HasDefaultValue(0);
b.Property(x => x.IsActive).HasDefaultValue(true);
b.Property(x => x.RefreshedAt).HasDefaultValueSql("SYSDATETIME()");
b.Property(x => x.SourceProcedure).HasMaxLength(128);
b.Property(x => x.Note).HasMaxLength(4000);
});
ConfigureProviderSpecificModel(builder);
}

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Sozsoft.Platform.Migrations
{
[DbContext(typeof(PlatformDbContext))]
[Migration("20260623164647_Initial")]
[Migration("20260624135753_Initial")]
partial class Initial
{
/// <inheritdoc />
@ -1963,6 +1963,105 @@ namespace Sozsoft.Platform.Migrations
b.ToTable("Sas_H_DataSource", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.DbTableColumn", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier")
.HasDefaultValueSql("NEWID()");
b.Property<string>("CacheKey")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("DefinitionCultureName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(10)
.HasColumnType("nvarchar(10)")
.HasDefaultValue("en");
b.Property<string>("DictionaryType")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)")
.HasDefaultValue("ListFormJson");
b.Property<int>("FieldCount")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<int>("FormCount")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<bool>("IsActive")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(true);
b.Property<string>("JsonData")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("JsonLength")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<string>("ListFormCode")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<int>("MaxForms")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(500);
b.Property<string>("Note")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<bool>("OnlyBaseDefinitions")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(true);
b.Property<DateTime>("RefreshedAt")
.ValueGeneratedOnAdd()
.HasColumnType("datetime2")
.HasDefaultValueSql("SYSDATETIME()");
b.Property<string>("ResourceName")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("SourceProcedure")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("TenantName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("Sozsoft");
b.Property<string>("UiCultureName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(10)
.HasColumnType("nvarchar(10)")
.HasDefaultValue("tr");
b.HasKey("Id");
b.ToTable("Sas_H_DbTableColumn", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.Demo", b =>
{
b.Property<Guid>("Id")

View file

@ -1195,6 +1195,34 @@ namespace Sozsoft.Platform.Migrations
table.PrimaryKey("PK_Sas_H_DataSource", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Sas_H_DbTableColumn",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
TenantName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false, defaultValue: "Sozsoft"),
DictionaryType = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false, defaultValue: "ListFormJson"),
DefinitionCultureName = table.Column<string>(type: "nvarchar(10)", maxLength: 10, nullable: false, defaultValue: "en"),
UiCultureName = table.Column<string>(type: "nvarchar(10)", maxLength: 10, nullable: false, defaultValue: "tr"),
ListFormCode = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
OnlyBaseDefinitions = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
ResourceName = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
MaxForms = table.Column<int>(type: "int", nullable: false, defaultValue: 500),
CacheKey = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: false),
JsonData = table.Column<string>(type: "nvarchar(max)", nullable: false),
FormCount = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
FieldCount = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
JsonLength = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
RefreshedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "SYSDATETIME()"),
SourceProcedure = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Note = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Sas_H_DbTableColumn", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Sas_H_Demo",
columns: table => new
@ -4389,6 +4417,9 @@ namespace Sozsoft.Platform.Migrations
migrationBuilder.DropTable(
name: "Sas_H_DataSource");
migrationBuilder.DropTable(
name: "Sas_H_DbTableColumn");
migrationBuilder.DropTable(
name: "Sas_H_Demo");

View file

@ -1960,6 +1960,105 @@ namespace Sozsoft.Platform.Migrations
b.ToTable("Sas_H_DataSource", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.DbTableColumn", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier")
.HasDefaultValueSql("NEWID()");
b.Property<string>("CacheKey")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("DefinitionCultureName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(10)
.HasColumnType("nvarchar(10)")
.HasDefaultValue("en");
b.Property<string>("DictionaryType")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)")
.HasDefaultValue("ListFormJson");
b.Property<int>("FieldCount")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<int>("FormCount")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<bool>("IsActive")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(true);
b.Property<string>("JsonData")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("JsonLength")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<string>("ListFormCode")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<int>("MaxForms")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(500);
b.Property<string>("Note")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<bool>("OnlyBaseDefinitions")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(true);
b.Property<DateTime>("RefreshedAt")
.ValueGeneratedOnAdd()
.HasColumnType("datetime2")
.HasDefaultValueSql("SYSDATETIME()");
b.Property<string>("ResourceName")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("SourceProcedure")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("TenantName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("Sozsoft");
b.Property<string>("UiCultureName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(10)
.HasColumnType("nvarchar(10)")
.HasDefaultValue("tr");
b.HasKey("Id");
b.ToTable("Sas_H_DbTableColumn", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.Demo", b =>
{
b.Property<Guid>("Id")

File diff suppressed because one or more lines are too long

View file

@ -12,7 +12,7 @@ import {
MessageContent,
SqlResultRow,
} from '@/proxy/ai/models'
import { Container } from '@/components/shared'
import { Container, Loading } from '@/components/shared'
import { Helmet } from 'react-helmet'
import { APP_NAME } from '@/constants/app.constant'
import dayjs from 'dayjs'
@ -421,7 +421,9 @@ const Assistant = () => {
{sql && (
<details className="group border-b border-gray-100 px-4 py-2.5 dark:border-gray-700">
<summary className="flex cursor-pointer list-none items-center justify-between gap-3 text-xs font-medium text-gray-500 marker:content-none hover:text-emerald-700 dark:text-gray-400 dark:hover:text-emerald-300">
<span>Oluşturulan SQL sorgusunu göster ({rowCount ?? resultRows.length} kayıt)</span>
<span>
Oluşturulan SQL sorgusunu göster ({rowCount ?? resultRows.length} kayıt)
</span>
<span className="text-base leading-none transition-transform group-open:rotate-45">
+
</span>
@ -439,7 +441,7 @@ const Assistant = () => {
) : (
<div className="max-h-[400px] overflow-auto">
<table className="w-full min-w-max text-sm">
<thead className="sticky top-0 z-10 bg-gray-800 text-xs uppercase tracking-wide text-gray-100 shadow-sm dark:bg-gray-950">
<thead className="sticky top-0 z-10 bg-gray-800 text-xs tracking-wide text-gray-100 shadow-sm dark:bg-gray-950">
<tr>
{resultColumns.map((column) => (
<th
@ -744,12 +746,7 @@ const Assistant = () => {
</div>
))}
{loading && (
<div className="flex items-center justify-center gap-2 text-gray-500 dark:text-gray-400">
<div className="animate-spin rounded-full h-4 w-4 border-2 border-gray-500 dark:border-gray-400 border-t-transparent" />
{translate('::AI.WaitAnswer')}
</div>
)}
<Loading type="default" loading={loading}></Loading>
<div ref={bottomRef}></div>
</div>