From 5e6e3970c516567d77f6d872d712bf8713323933 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, 2 Oct 2026 12:29:22 +0300 Subject: [PATCH] =?UTF-8?q?ListFormun=20birden=20fazla=20SubFormlar=C4=B1n?= =?UTF-8?q?=20FormReport=20raporu=20hatas=C4=B1=20giderildi.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lowcode-reference.instructions.md | 2 +- .github/instructions/lowcode.instructions.md | 2 +- .../McpDevelopAppService.cs | 15 ++++++++++++--- .../DynamicData/MsDynamicDataRepository.cs | 7 ++++++- .../DynamicData/PgDynamicDataRepository.cs | 7 ++++++- .../PredefinedReports/DynamicFormReport.cs | 2 +- .../PredefinedReports/DynamicReportColumn.cs | 2 +- .../PredefinedReports/DynamicReportImageHelper.cs | 2 +- 8 files changed, 29 insertions(+), 10 deletions(-) diff --git a/.github/instructions/lowcode-reference.instructions.md b/.github/instructions/lowcode-reference.instructions.md index 13e68c43..bb6830cd 100644 --- a/.github/instructions/lowcode-reference.instructions.md +++ b/.github/instructions/lowcode-reference.instructions.md @@ -378,7 +378,7 @@ Wizard varsayılan olarak `DefaultFieldPermissionJson(permissionName)` üretir. | `TabType` | Sekmenin görünümü — `ListFormTabTypeEnum`: `List` \| `Card` \| `Tree` \| `Gantt` \| `Scheduler` \| `Todo` \| `Form` \| `Chart` \| `Pivot`. `Form` ana kayda bağlı **tek** kaydı gösterir: kayıt yokken "Yeni" düğmesi (hedef ekranda `AllowAdding` açıksa), kayıt varken yalnızca düzenleme; ikinci kayıt açılmaz | | `TabTitle` | Dil anahtarı | | `Code` | Hedef `ListFormCode` | -| `IsRefresh` | Ana kayıt değişince yenilensin | +| `IsRefresh` | Ana kayıt değişince yenilensin. MCP `deploy_wizard` yeni alt form bağlantısını `false` yazar; var olan bağlantıda önceki değer korunur | | `Relation[]` | `ParentFieldName` → `ChildFieldName` + `DbType` (`System.Data.DbType`, **sayı**; bileşik anahtarda birden çok satır) | Alt formun kendisi de bir ListForm'dur: `IsSubForm = true` olmalı ve genellikle `CreateMenu: diff --git a/.github/instructions/lowcode.instructions.md b/.github/instructions/lowcode.instructions.md index aa3fc67f..d4185859 100644 --- a/.github/instructions/lowcode.instructions.md +++ b/.github/instructions/lowcode.instructions.md @@ -1849,7 +1849,7 @@ Wizard Manager'daki talep silmesini kullanır. "TabType": "List", // List|Card|Tree|Gantt|Scheduler|Todo|Form|Chart|Pivot "TabTitle": "App.Mrp.OrderItems", // dil anahtarı "Code": "App.Mrp.OrderItems", // hedef ListFormCode - "IsRefresh": true, // ana kayıt değişince yenilensin + "IsRefresh": false, // ana kayıt değişince yenilensin; MCP yeni bağlantıda false yazar "Relation": [ { "ParentFieldName": "Id", "ChildFieldName": "OrderId", "DbType": 11 } ] diff --git a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpDevelopAppService.cs b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpDevelopAppService.cs index 8850ac1e..fc93fd17 100644 --- a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpDevelopAppService.cs +++ b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpDevelopAppService.cs @@ -211,9 +211,18 @@ public class McpDevelopAppService( // Menu sirasi modelin karari degildir: yeni ekran kardeslerinin sonuna eklenir (deploy // bagimlilik sirasiyla yapildigi icin lookup kaynagi tuketen ekranin ustunde kalir), // guncelleme ekranin mevcut yerini korur. - wizard.MenuOrder = wizard.EditFileName is null - ? 0 - : (await wizardAppService.GetFile(wizard.EditFileName)).Wizard?.MenuOrder ?? 0; + var previous = wizard.EditFileName is null ? null : (await wizardAppService.GetFile(wizard.EditFileName)).Wizard; + wizard.MenuOrder = previous?.MenuOrder ?? 0; + + // Alt form sekmesi ana kayit her degistiginde yeniden sorgulanmaz; MCP yeni baglanti + // acarken yenilemeyi kapali yazar. Var olan baglantida kullanicinin ekrandan verdigi + // deger korunur. + var previousRefresh = (previous?.SubForms ?? []) + .Where(subForm => !string.IsNullOrWhiteSpace(subForm.Code)) + .GroupBy(subForm => subForm.Code, StringComparer.OrdinalIgnoreCase) + .ToDictionary(group => group.Key, group => group.First().IsRefresh, StringComparer.OrdinalIgnoreCase); + foreach (var subForm in wizard.SubForms ?? []) + subForm.IsRefresh = subForm.Code is not null && previousRefresh.GetValueOrDefault(subForm.Code); // Tek gruplu duzenleme formunda grup basligi popup basligini tekrarlar; baslik yalnizca // birden fazla grubu birbirinden ayirmak icin yazilir. diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/DynamicData/MsDynamicDataRepository.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/DynamicData/MsDynamicDataRepository.cs index 2badb946..1c2abffe 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/DynamicData/MsDynamicDataRepository.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/DynamicData/MsDynamicDataRepository.cs @@ -27,6 +27,11 @@ public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency private readonly HashSet _registeredConnections; private readonly object _lock = new object(); + // Bağlantı ve transaction bu örneğe aittir ve kapsamı kapanınca dispose edilir; aynı UoW içinde + // ikinci bir DI kapsamı (ör. form raporunun alt form raporları) aynı anahtarla AddTransactionApi + // çağırıp UoW'yi reddettirmesin diye anahtar örneğe özgüdür. + private readonly string _instanceId = Guid.NewGuid().ToString("N"); + public bool IsDisposed { get; private set; } public MsDynamicDataRepository( @@ -45,7 +50,7 @@ public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency private string BuildKey(string cs) { var uowId = _unitOfWorkManager.Current?.GetHashCode() ?? 0; - return $"Dapper_{uowId}_{cs}"; + return $"Dapper_{uowId}_{_instanceId}_{cs}"; } private async Task GetOrCreateConnectionAsync(string cs) diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/DynamicData/PgDynamicDataRepository.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/DynamicData/PgDynamicDataRepository.cs index 14db2a15..af788b98 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/DynamicData/PgDynamicDataRepository.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/DynamicData/PgDynamicDataRepository.cs @@ -27,6 +27,11 @@ public class PgDynamicDataRepository : IDynamicDataRepository, IScopedDependency private readonly HashSet _registeredConnections; private readonly object _lock = new object(); + // Bağlantı ve transaction bu örneğe aittir ve kapsamı kapanınca dispose edilir; aynı UoW içinde + // ikinci bir DI kapsamı (ör. form raporunun alt form raporları) aynı anahtarla AddTransactionApi + // çağırıp UoW'yi reddettirmesin diye anahtar örneğe özgüdür. + private readonly string _instanceId = Guid.NewGuid().ToString("N"); + public bool IsDisposed { get; private set; } public PgDynamicDataRepository( @@ -44,7 +49,7 @@ public class PgDynamicDataRepository : IDynamicDataRepository, IScopedDependency private string BuildKey(string cs) { var uowId = _unitOfWorkManager.Current?.GetHashCode() ?? 0; - return $"Dapper_{uowId}_{cs}"; + return $"Dapper_{uowId}_{_instanceId}_{cs}"; } private async Task GetOrCreateConnectionAsync(string cs) diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicFormReport.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicFormReport.cs index 36f8d792..5e52492a 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicFormReport.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicFormReport.cs @@ -701,7 +701,7 @@ public class DynamicFormReport : XtraReport var lookup = DynamicReportImageHelper.GetLookup(field); var isMultiValue = IsMultiValueLookupEditor(editorType); - if (lookup == null || selectField?.JoinOptions != null) + if (lookup == null || selectField?.IsJoined == true) { return new FormReportField(field, bindingName, editorType, columnSpan, null, null, isMultiValue, DynamicReportImageHelper.IsImageEditor(editorType)); } diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportColumn.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportColumn.cs index 946b13ca..6401a943 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportColumn.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportColumn.cs @@ -44,7 +44,7 @@ internal static class DynamicReportColumnFactory var isImage = DynamicReportImageHelper.IsImageEditor(editorType); var isHtml = editorType == PlatformConsts.EditorTypes.dxHtmlEditor; - if (lookup == null || selectField?.JoinOptions != null) + if (lookup == null || selectField?.IsJoined == true) { return new DynamicReportColumn(field, bindingName, null, null, isMultiValue, isImage, isHtml, editorType); } diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportImageHelper.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportImageHelper.cs index 49b8261a..a861cedd 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportImageHelper.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportImageHelper.cs @@ -95,7 +95,7 @@ internal static class DynamicReportImageHelper public static string GetReportFieldName(SelectField selectField) { - if (selectField?.JoinOptions != null && !string.IsNullOrWhiteSpace(selectField.JoinOptions.FieldNameAlias)) + if (selectField?.IsJoined == true && !string.IsNullOrWhiteSpace(selectField.JoinOptions.FieldNameAlias)) { return selectField.JoinOptions.FieldNameAlias; }