From 08b83cc42dde45b16eb74e7927ff7f4bc9902486 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?=
<76204082+iamsedatozturk@users.noreply.github.com>
Date: Tue, 16 Jun 2026 13:54:48 +0300
Subject: [PATCH] =?UTF-8?q?Devexpress=20Grid=20Raporundaki=20Selectbox=20k?=
=?UTF-8?q?=C4=B1s=C4=B1mlar=C4=B1=20d=C3=BCzeltildi.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Value görünmüyor Text bilgileri görünüyor.
---
.../Seeds/TenantData.json | 2 +-
.../DynamicListFormReport.cs | 252 +++++++++++++++++-
2 files changed, 243 insertions(+), 11 deletions(-)
diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
index fc10183..8ad2e37 100644
--- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
+++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
@@ -1390,7 +1390,7 @@
"name": "App.Definitions.AiBot",
"description": "Liste Raporları",
"categoryName": "Listeler",
- "htmlContent": "
Liste Raporları.
",
+ "htmlContent": "Liste Raporları.
http://localhost:3000/admin/reports/DynamicListFormReport/view?listFormCode=App.Languages.LanguageText&filter=[%22CultureName%22,%22=%22,%22en%22]
",
"status": "active"
}
],
diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicListFormReport.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicListFormReport.cs
index aa79ce9..bbf7f62 100644
--- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicListFormReport.cs
+++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicListFormReport.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
+using System.Text.Json;
using System.Text.RegularExpressions;
using DevExpress.DataAccess.ConnectionParameters;
using DevExpress.DataAccess.Sql;
@@ -11,7 +12,6 @@ using DevExpress.XtraPrinting;
using DevExpress.XtraReports.UI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
-using Microsoft.Extensions.Primitives;
using Sozsoft.Platform.DynamicData;
using Sozsoft.Platform.Entities;
using Sozsoft.Platform.Enums;
@@ -65,6 +65,7 @@ public class DynamicListFormReport : XtraReport
var customizationManager = scope.ServiceProvider.GetRequiredService();
var dynamicDataManager = scope.ServiceProvider.GetRequiredService();
var selectQueryManager = scope.ServiceProvider.GetRequiredService();
+ var defaultValueHelper = scope.ServiceProvider.GetRequiredService();
var localizer = scope.ServiceProvider.GetRequiredService>();
if (!authManager.CanAccess(listFormCode).GetAwaiter().GetResult())
@@ -81,7 +82,6 @@ public class DynamicListFormReport : XtraReport
var customizations = customizationManager.GetUsersServerCustomizations(listFormCode).GetAwaiter().GetResult();
var (_, connectionString, dataSourceType) = dynamicDataManager.GetAsync(listForm.IsTenant, listForm.DataSourceCode).GetAwaiter().GetResult();
- var queryParameters = ToStringValues(parameters);
var queryParams = new QueryParameters
{
ListFormCode = listFormCode,
@@ -116,14 +116,20 @@ public class DynamicListFormReport : XtraReport
.Select(field =>
{
var selectField = selectQueryManager.SelectFields.First(s => s.FieldName == field.FieldName);
- return new ReportColumn(field, GetReportFieldName(selectField));
+ return CreateReportColumn(field, selectField, defaultValueHelper);
})
.Where(x => !string.IsNullOrWhiteSpace(x.BindingName) && x.BindingName != "undefined")
.ToList();
+ var selectQuery = ApplyLookupQueryColumns(
+ selectQueryManager.SelectQuery,
+ listForm,
+ reportColumns,
+ defaultValueHelper);
+
ConfigurePage(reportColumns);
ConfigureDataSource(
- ApplyQueryParameters(selectQueryManager.SelectQuery, selectQueryManager.SelectQueryParameters),
+ ApplyQueryParameters(selectQuery, selectQueryManager.SelectQueryParameters),
connectionString,
dataSourceType);
BuildLayout(listForm, reportColumns, localizer);
@@ -347,6 +353,18 @@ public class DynamicListFormReport : XtraReport
CanGrow = false
};
cell.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Text", $"[{column.BindingName}]"));
+ if (column.StaticLookupValues?.Count > 0)
+ {
+ cell.BeforePrint += (_, _) =>
+ {
+ var value = Convert.ToString(cell.Text, CultureInfo.InvariantCulture);
+ if (value != null && column.StaticLookupValues.TryGetValue(value, out var displayText))
+ {
+ cell.Text = displayText;
+ }
+ };
+ }
+
return cell;
}
@@ -417,7 +435,226 @@ public class DynamicListFormReport : XtraReport
return selectField?.FieldName;
}
- private sealed record ReportColumn(ListFormField Field, string BindingName);
+ private static ReportColumn CreateReportColumn(
+ ListFormField field,
+ SelectField selectField,
+ DefaultValueHelper defaultValueHelper)
+ {
+ var bindingName = GetReportFieldName(selectField);
+ var lookup = GetLookup(field);
+
+ if (lookup == null || selectField?.JoinOptions != null)
+ {
+ return new ReportColumn(field, bindingName, null, null);
+ }
+
+ if (IsReportQueryableLookup(lookup))
+ {
+ return new ReportColumn(field, GetLookupBindingName(field), lookup, null);
+ }
+
+ if (lookup.DataSourceType == UiLookupDataSourceTypeEnum.StaticData)
+ {
+ return new ReportColumn(
+ field,
+ bindingName,
+ lookup,
+ GetStaticLookupValues(lookup, defaultValueHelper));
+ }
+
+ return new ReportColumn(field, bindingName, null, null);
+ }
+
+ private static bool IsReportQueryableLookup(LookupDto lookup)
+ {
+ return lookup.DataSourceType == UiLookupDataSourceTypeEnum.Query &&
+ string.IsNullOrWhiteSpace(lookup.CascadeParentFields) &&
+ !string.IsNullOrWhiteSpace(lookup.LookupQuery) &&
+ !Regex.IsMatch(lookup.LookupQuery, @"@\s*param\d+", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
+ }
+
+ private static LookupDto GetLookup(ListFormField field)
+ {
+ if (string.IsNullOrWhiteSpace(field.LookupJson))
+ {
+ return null;
+ }
+
+ try
+ {
+ return JsonSerializer.Deserialize(field.LookupJson);
+ }
+ catch (JsonException)
+ {
+ return null;
+ }
+ }
+
+ private static Dictionary GetStaticLookupValues(
+ LookupDto lookup,
+ DefaultValueHelper defaultValueHelper)
+ {
+ if (string.IsNullOrWhiteSpace(lookup.LookupQuery))
+ {
+ return null;
+ }
+
+ try
+ {
+ var lookupJson = defaultValueHelper.GetDefaultValue(lookup.LookupQuery);
+ using var document = JsonDocument.Parse(lookupJson);
+ if (document.RootElement.ValueKind != JsonValueKind.Array)
+ {
+ return null;
+ }
+
+ var valueExpr = lookup.ValueExpr ?? "Key";
+ var displayExpr = lookup.DisplayExpr ?? "Name";
+ var values = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (var item in document.RootElement.EnumerateArray())
+ {
+ if (!TryGetProperty(item, valueExpr, out var valueElement) ||
+ !TryGetProperty(item, displayExpr, out var displayElement))
+ {
+ continue;
+ }
+
+ var value = GetJsonScalar(valueElement);
+ if (value == null)
+ {
+ continue;
+ }
+
+ values[value] = GetJsonScalar(displayElement) ?? value;
+ }
+
+ return values.Count == 0 ? null : values;
+ }
+ catch (JsonException)
+ {
+ return null;
+ }
+ }
+
+ private static bool TryGetProperty(JsonElement element, string propertyName, out JsonElement value)
+ {
+ foreach (var property in element.EnumerateObject())
+ {
+ if (string.Equals(property.Name, propertyName, StringComparison.OrdinalIgnoreCase))
+ {
+ value = property.Value;
+ return true;
+ }
+ }
+
+ value = default;
+ return false;
+ }
+
+ private static string GetJsonScalar(JsonElement element)
+ {
+ return element.ValueKind switch
+ {
+ JsonValueKind.String => element.GetString(),
+ JsonValueKind.Number => element.GetRawText(),
+ JsonValueKind.True => bool.TrueString,
+ JsonValueKind.False => bool.FalseString,
+ JsonValueKind.Null => null,
+ _ => element.ToString()
+ };
+ }
+
+ private static string ApplyLookupQueryColumns(
+ string selectQuery,
+ ListForm listForm,
+ IReadOnlyList reportColumns,
+ DefaultValueHelper defaultValueHelper)
+ {
+ var lookupColumns = reportColumns
+ .Where(x => x.Lookup != null && IsReportQueryableLookup(x.Lookup))
+ .ToList();
+
+ if (lookupColumns.Count == 0 || string.IsNullOrWhiteSpace(selectQuery))
+ {
+ return selectQuery;
+ }
+
+ var tableAlias = string.IsNullOrWhiteSpace(listForm.TableName)
+ ? listForm.SelectCommand
+ : listForm.TableName;
+
+ var selectParts = new List();
+ var joinParts = new List();
+ foreach (var column in lookupColumns)
+ {
+ var lookup = column.Lookup;
+ var alias = GetLookupAlias(column.Field);
+ var valueExpr = QuoteSqlIdentifier(lookup.ValueExpr ?? "Key");
+ var displayExpr = QuoteSqlIdentifier(lookup.DisplayExpr ?? "Name");
+ var lookupQuery = NormalizeLookupQuery(defaultValueHelper.GetDefaultValue(lookup.LookupQuery));
+
+ selectParts.Add($"{alias}.{displayExpr} AS {QuoteSqlIdentifier(column.BindingName)}");
+ joinParts.Add(
+ $"LEFT JOIN ({lookupQuery}) AS {alias} " +
+ $"ON {alias}.{valueExpr} = {QuoteSqlIdentifier(tableAlias)}.{QuoteSqlIdentifier(column.Field.FieldName)}");
+ }
+
+ var fromIndex = selectQuery.IndexOf(" FROM ", StringComparison.OrdinalIgnoreCase);
+ if (fromIndex < 0)
+ {
+ return selectQuery;
+ }
+
+ selectQuery = selectQuery.Insert(fromIndex, "," + string.Join(',', selectParts));
+
+ var joinInsertIndex = FindClauseIndex(selectQuery, " WHERE ");
+ if (joinInsertIndex < 0)
+ {
+ joinInsertIndex = FindClauseIndex(selectQuery, " ORDER BY ");
+ }
+ if (joinInsertIndex < 0)
+ {
+ return selectQuery + " " + string.Join(' ', joinParts);
+ }
+
+ return selectQuery.Insert(joinInsertIndex, " " + string.Join(' ', joinParts));
+ }
+
+ private static int FindClauseIndex(string sql, string clause)
+ {
+ return sql.IndexOf(clause, StringComparison.OrdinalIgnoreCase);
+ }
+
+ private static string NormalizeLookupQuery(string lookupQuery)
+ {
+ var query = lookupQuery.Trim().TrimEnd(';');
+ return Regex.Replace(
+ query,
+ @"\s+ORDER\s+BY\s+[\s\S]*$",
+ string.Empty,
+ RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
+ }
+
+ private static string GetLookupBindingName(ListFormField field)
+ {
+ return $"{field.FieldName}__LookupText";
+ }
+
+ private static string GetLookupAlias(ListFormField field)
+ {
+ return QuoteSqlIdentifier($"Lookup_{Regex.Replace(field.FieldName, @"\W+", "_")}");
+ }
+
+ private static string QuoteSqlIdentifier(string identifier)
+ {
+ return $"\"{identifier.Replace("\"", "\"\"")}\"";
+ }
+
+ private sealed record ReportColumn(
+ ListFormField Field,
+ string BindingName,
+ LookupDto Lookup,
+ Dictionary StaticLookupValues);
private static SummaryFunc? GetSummaryType(string totalSummaryJson)
{
@@ -472,9 +709,4 @@ public class DynamicListFormReport : XtraReport
{
return parameters.TryGetValue(name, out var value) ? value : null;
}
-
- private static Dictionary ToStringValues(IDictionary parameters)
- {
- return parameters.ToDictionary(x => x.Key, x => new StringValues(x.Value));
- }
}