From 20215be662750ad628120b3e0b15166c7d70fb41 Mon Sep 17 00:00:00 2001 From: mara-1 <147929076+mara-1@users.noreply.github.com> Date: Tue, 24 Dec 2024 21:26:31 +0400 Subject: [PATCH] =?UTF-8?q?=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=202=20=D0=B8=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ProjectHorseRacingOrg/Entities/Horse.cs | 12 ++++ ProjectHorseRacingOrg/Entities/Jockey.cs | 10 ++++ ProjectHorseRacingOrg/Entities/Race.cs | 11 +++- ProjectHorseRacingOrg/Entities/RaceEntries.cs | 32 ++++++---- .../Entities/RaceEntryDetails.cs | 1 + .../Entities/RacingHorses.cs | 21 +++++++ .../Entities/TempRaceEntryDetails.cs | 16 ----- ProjectHorseRacingOrg/Forms/FormHorses.cs | 7 ++- ProjectHorseRacingOrg/Forms/FormJockeys.cs | 7 ++- .../Forms/FormRaceEntries.cs | 2 +- ProjectHorseRacingOrg/Forms/FormRaces.cs | 7 ++- .../Forms/FormRacesEntries.cs | 7 ++- .../Forms/FormRacingHorse.cs | 4 +- .../Forms/FormRacingHorses.cs | 7 ++- ProjectHorseRacingOrg/Reports/ChartReport.cs | 8 +-- ProjectHorseRacingOrg/Reports/TableReport.cs | 8 +-- .../Implementations/QueryBuilder.cs | 39 ++++++++++++ .../Implementations/RaceEntriesRepository.cs | 59 +++++++++++++++---- .../Implementations/RacingHorsesRepository.cs | 6 +- 19 files changed, 205 insertions(+), 59 deletions(-) delete mode 100644 ProjectHorseRacingOrg/Entities/TempRaceEntryDetails.cs create mode 100644 ProjectHorseRacingOrg/Repositories/Implementations/QueryBuilder.cs diff --git a/ProjectHorseRacingOrg/Entities/Horse.cs b/ProjectHorseRacingOrg/Entities/Horse.cs index 8f1ae42..2706d84 100644 --- a/ProjectHorseRacingOrg/Entities/Horse.cs +++ b/ProjectHorseRacingOrg/Entities/Horse.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,10 +10,21 @@ namespace ProjectHorseRacingOrg.Entities; public class Horse { public int Id { get; private set; } + + [DisplayName("Вид")] public string HorseSpecies { get; private set; } = string.Empty; + + [DisplayName("Кличка")] public string HorseNickName { get; private set; } = string.Empty; + + public string FullName => $"{HorseSpecies} {HorseNickName}"; + + [DisplayName("Возраст")] public int Age { get; private set; } + + [DisplayName("Вес")] public double Weight { get; private set; } + public static Horse CreateEntity(int id, string horseSpecies, string horseNickName, int age, double weight) { diff --git a/ProjectHorseRacingOrg/Entities/Jockey.cs b/ProjectHorseRacingOrg/Entities/Jockey.cs index 244514b..0d6a549 100644 --- a/ProjectHorseRacingOrg/Entities/Jockey.cs +++ b/ProjectHorseRacingOrg/Entities/Jockey.cs @@ -1,6 +1,7 @@ using ProjectHorseRacingOrg.Entities.Enums; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,9 +11,18 @@ namespace ProjectHorseRacingOrg.Entities; public class Jockey { public int Id { get; private set; } + + [DisplayName("Имя")] public string FirstName { get; private set; } = string.Empty; + + [DisplayName("Фамилия")] public string LastName { get; private set; } = string.Empty; + + public string FullName => $"{LastName} {FirstName}"; + + [DisplayName("Титул")] public JockeyTitle JockeyTitle { get; private set; } + public static Jockey CreateEntity(int id, string first, string last, JockeyTitle jockeyTitle) { diff --git a/ProjectHorseRacingOrg/Entities/Race.cs b/ProjectHorseRacingOrg/Entities/Race.cs index b5c95cc..6b4a817 100644 --- a/ProjectHorseRacingOrg/Entities/Race.cs +++ b/ProjectHorseRacingOrg/Entities/Race.cs @@ -2,6 +2,7 @@ using ProjectHorseRacingOrg.Entities.Enums; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -11,11 +12,17 @@ namespace ProjectHorseRacingOrg.Entities; public class Race { public int Id { get; private set; } + + [DisplayName("Тип соревнований")] public RaceType RaceType { get; private set; } + + [DisplayName("Название")] public string Name { get; private set; } = string.Empty; + + [DisplayName("Описание")] public string Description { get; private set; } = string.Empty; - public static Race CreateEntity(int id, RaceType raceType, string name, -string description) + + public static Race CreateEntity(int id, RaceType raceType, string name, string description) { return new Race { diff --git a/ProjectHorseRacingOrg/Entities/RaceEntries.cs b/ProjectHorseRacingOrg/Entities/RaceEntries.cs index 88b79c1..17ddcbe 100644 --- a/ProjectHorseRacingOrg/Entities/RaceEntries.cs +++ b/ProjectHorseRacingOrg/Entities/RaceEntries.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,13 +10,26 @@ namespace ProjectHorseRacingOrg.Entities; public class RaceEntries { public int Id { get; private set; } + + [Browsable(false)] public int JockeyId { get; private set; } + + [DisplayName("Жокей")] + public string JockeyName { get; private set; } = string.Empty; + + [DisplayName("Дата соревнований")] public DateTime DateReceipt { get; private set; } - - public IEnumerable RacesEntryDetails { get; private set; } = []; + + [DisplayName("Соревнования")] + public string Feed => RacesEntryDetails != null ? + string.Join(", ", RacesEntryDetails.Select(x => $"{x.RaceName} {x.Count}")) : string.Empty; + + [Browsable(false)] + public IEnumerable RacesEntryDetails { get; private set;} = []; + public static RaceEntries CreateOpeartion(int id, int jockeyId, - IEnumerable racesEntryDetails) + IEnumerable racesEntryDetails) { return new RaceEntries { @@ -26,16 +40,12 @@ public class RaceEntries }; } - public static RaceEntries CreateOpeartion(TempRaceEntryDetails tempRaceEntryDetails, -IEnumerable racesEntryDetails) + public void SetRacesEntryDetails(IEnumerable racesEntryDetails) { - return new RaceEntries + if (racesEntryDetails != null && racesEntryDetails.Any()) { - Id = tempRaceEntryDetails.Id, - JockeyId = tempRaceEntryDetails.JockeyId, - DateReceipt = tempRaceEntryDetails.DateReceipt, - RacesEntryDetails = racesEntryDetails - }; + RacesEntryDetails = racesEntryDetails; + } } diff --git a/ProjectHorseRacingOrg/Entities/RaceEntryDetails.cs b/ProjectHorseRacingOrg/Entities/RaceEntryDetails.cs index 0e35106..b1dffcf 100644 --- a/ProjectHorseRacingOrg/Entities/RaceEntryDetails.cs +++ b/ProjectHorseRacingOrg/Entities/RaceEntryDetails.cs @@ -11,6 +11,7 @@ public class RaceEntryDetails public int Id { get; private set; } public int RaceId { get; private set; } public int Count { get; private set; } + public string RaceName { get; private set; } = string.Empty; public static RaceEntryDetails CreateElement(int id, int raceId, int count) { diff --git a/ProjectHorseRacingOrg/Entities/RacingHorses.cs b/ProjectHorseRacingOrg/Entities/RacingHorses.cs index fa61eb4..33a1ac9 100644 --- a/ProjectHorseRacingOrg/Entities/RacingHorses.cs +++ b/ProjectHorseRacingOrg/Entities/RacingHorses.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,11 +10,31 @@ namespace ProjectHorseRacingOrg.Entities; public class RacingHorses { public int Id { get; private set; } + + [Browsable(false)] public int RaceId { get; private set; } + + [Browsable(false)] public int JockeyId { get; private set; } + + [Browsable(false)] public int HorseId { get; private set; } + + [DisplayName("Соревнование")] + public string RaceName { get; private set; } = string.Empty; + + [DisplayName("Жокей")] + public string JockeyName { get; private set; } = string.Empty; + + [DisplayName("Лошадь")] + public string HorseName { get; private set; } = string.Empty; + + [DisplayName("Дата соревнования")] public DateTime RacingDate { get; private set; } + + [DisplayName("результаты место")] public int Result { get; private set; } + public static RacingHorses CreateOpeartion(int id, int raceId, int jockeyId, int horseId, int result) { diff --git a/ProjectHorseRacingOrg/Entities/TempRaceEntryDetails.cs b/ProjectHorseRacingOrg/Entities/TempRaceEntryDetails.cs deleted file mode 100644 index 67055c6..0000000 --- a/ProjectHorseRacingOrg/Entities/TempRaceEntryDetails.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ProjectHorseRacingOrg.Entities; - -public class TempRaceEntryDetails -{ - public int Id { get; private set; } - public int JockeyId { get; private set; } - public DateTime DateReceipt { get; private set; } - public int RaceId { get; private set; } - public int Count { get; private set; } -} diff --git a/ProjectHorseRacingOrg/Forms/FormHorses.cs b/ProjectHorseRacingOrg/Forms/FormHorses.cs index 6c80fda..5c3b24d 100644 --- a/ProjectHorseRacingOrg/Forms/FormHorses.cs +++ b/ProjectHorseRacingOrg/Forms/FormHorses.cs @@ -95,7 +95,12 @@ namespace ProjectHorseRacingOrg.Forms MessageBoxButtons.OK, MessageBoxIcon.Error); } } - private void LoadList() => dataGridViewData.DataSource = _horseRepository.ReadHorses(); + private void LoadList() + { + dataGridViewData.DataSource = _horseRepository.ReadHorses(); + dataGridViewData.Columns["Id"].Visible = false; + } + private bool TryGetIdentifierFromSelectedRow(out int id) { id = 0; diff --git a/ProjectHorseRacingOrg/Forms/FormJockeys.cs b/ProjectHorseRacingOrg/Forms/FormJockeys.cs index c73b319..769e515 100644 --- a/ProjectHorseRacingOrg/Forms/FormJockeys.cs +++ b/ProjectHorseRacingOrg/Forms/FormJockeys.cs @@ -94,8 +94,11 @@ private void ButtonUpd_Click(object sender, EventArgs e) MessageBoxButtons.OK, MessageBoxIcon.Error); } } - private void LoadList() => dataGridViewData.DataSource = - _jockeyRepository.ReadJockeys(); + private void LoadList() + { + dataGridViewData.DataSource = _jockeyRepository.ReadJockeys(); + dataGridViewData.Columns["Id"].Visible = false; + } private bool TryGetIdentifierFromSelectedRow(out int id) { id = 0; diff --git a/ProjectHorseRacingOrg/Forms/FormRaceEntries.cs b/ProjectHorseRacingOrg/Forms/FormRaceEntries.cs index c3278da..2821193 100644 --- a/ProjectHorseRacingOrg/Forms/FormRaceEntries.cs +++ b/ProjectHorseRacingOrg/Forms/FormRaceEntries.cs @@ -27,7 +27,7 @@ namespace ProjectHorseRacingOrg.Forms throw new ArgumentNullException(nameof(raceEntriesRepository)); comboBoxJockey.DataSource = jockeyRepository.ReadJockeys(); - comboBoxJockey.DisplayMember = "FirstName"; + comboBoxJockey.DisplayMember = "FullName"; comboBoxJockey.ValueMember = "Id"; ColumnRace.DataSource = raceRepository.ReadRaces(); ColumnRace.DisplayMember = "Name"; diff --git a/ProjectHorseRacingOrg/Forms/FormRaces.cs b/ProjectHorseRacingOrg/Forms/FormRaces.cs index 59e00a9..107f46e 100644 --- a/ProjectHorseRacingOrg/Forms/FormRaces.cs +++ b/ProjectHorseRacingOrg/Forms/FormRaces.cs @@ -92,7 +92,12 @@ namespace ProjectHorseRacingOrg.Forms MessageBoxButtons.OK, MessageBoxIcon.Error); } } - private void LoadList() => dataGridViewData.DataSource = _raceRepository.ReadRaces(); + private void LoadList() + { + dataGridViewData.DataSource = _raceRepository.ReadRaces(); + dataGridViewData.Columns["Id"].Visible = false; + } + private bool TryGetIdentifierFromSelectedRow(out int id) { diff --git a/ProjectHorseRacingOrg/Forms/FormRacesEntries.cs b/ProjectHorseRacingOrg/Forms/FormRacesEntries.cs index e64ef07..aa0904e 100644 --- a/ProjectHorseRacingOrg/Forms/FormRacesEntries.cs +++ b/ProjectHorseRacingOrg/Forms/FormRacesEntries.cs @@ -75,8 +75,11 @@ namespace ProjectHorseRacingOrg.Forms MessageBoxButtons.OK, MessageBoxIcon.Error); } } - private void LoadList() => dataGridViewData.DataSource = - _raceEntriesRepository.ReadRaceEntries(); + private void LoadList() + { + dataGridViewData.DataSource = _raceEntriesRepository.ReadRaceEntries(); + dataGridViewData.Columns["Id"].Visible = false; + } private bool TryGetIdentifierFromSelectedRow(out int id) { id = 0; diff --git a/ProjectHorseRacingOrg/Forms/FormRacingHorse.cs b/ProjectHorseRacingOrg/Forms/FormRacingHorse.cs index 3120026..e49a11c 100644 --- a/ProjectHorseRacingOrg/Forms/FormRacingHorse.cs +++ b/ProjectHorseRacingOrg/Forms/FormRacingHorse.cs @@ -28,13 +28,13 @@ namespace ProjectHorseRacingOrg.Forms throw new ArgumentNullException(nameof(racingHorsesRepository)); comboBoxJockey.DataSource = jockeyRepository.ReadJockeys(); - comboBoxJockey.DisplayMember = "FirstName"; + comboBoxJockey.DisplayMember = "FullName"; comboBoxJockey.ValueMember = "Id"; comboBoxRace.DataSource = raceRepository.ReadRaces(); comboBoxRace.DisplayMember = "Name"; comboBoxRace.ValueMember = "Id"; comboBoxHorse.DataSource = horseRepository.ReadHorses(); - comboBoxHorse.DisplayMember = "HorseNickName"; + comboBoxHorse.DisplayMember = "FullName"; comboBoxHorse.ValueMember = "Id"; } private void ButtonSave_Click(object sender, EventArgs e) diff --git a/ProjectHorseRacingOrg/Forms/FormRacingHorses.cs b/ProjectHorseRacingOrg/Forms/FormRacingHorses.cs index e249bbc..1613fa1 100644 --- a/ProjectHorseRacingOrg/Forms/FormRacingHorses.cs +++ b/ProjectHorseRacingOrg/Forms/FormRacingHorses.cs @@ -52,8 +52,11 @@ namespace ProjectHorseRacingOrg.Forms MessageBoxButtons.OK, MessageBoxIcon.Error); } } - private void LoadList() => dataGridViewData.DataSource = - _racingHorsesRepository.ReadRacingHorses(); + private void LoadList() + { + dataGridViewData.DataSource = _racingHorsesRepository.ReadRacingHorses(); + dataGridViewData.Columns["Id"].Visible = false; + } } } diff --git a/ProjectHorseRacingOrg/Reports/ChartReport.cs b/ProjectHorseRacingOrg/Reports/ChartReport.cs index 3aa7d70..650f5d7 100644 --- a/ProjectHorseRacingOrg/Reports/ChartReport.cs +++ b/ProjectHorseRacingOrg/Reports/ChartReport.cs @@ -28,7 +28,7 @@ public class ChartReport { new PdfBuilder(filePath) .AddHeader("Участие лошадей") - .AddPieChart("Состоявшиеся соревнования", GetData(dateTime)) + .AddPieChart($"Состоявшиеся соревнования на {dateTime:dd MMMM yyyy}", GetData(dateTime)) .Build(); return true; } @@ -43,11 +43,11 @@ public class ChartReport return _racingHorsesRepository .ReadRacingHorses() .Where(x => x.RacingDate.Date == dateTime.Date) - .GroupBy(x => x.HorseId, (key, group) => new { - Id = key, + .GroupBy(x => x.HorseName, (key, group) => new { + Name = key, Count = group.Sum(x => x.Result) }) - .Select(x => (x.Id.ToString(), (double)x.Count)) + .Select(x => (x.Name, (double)x.Count)) .ToList(); } } diff --git a/ProjectHorseRacingOrg/Reports/TableReport.cs b/ProjectHorseRacingOrg/Reports/TableReport.cs index 206f541..e02130e 100644 --- a/ProjectHorseRacingOrg/Reports/TableReport.cs +++ b/ProjectHorseRacingOrg/Reports/TableReport.cs @@ -33,7 +33,7 @@ internal class TableReport { new ExcelBuilder(filePath) .AddHeader("Сводка по движению соревнований", 0, 4) - .AddParagraph("за период", 0) + .AddParagraph($"за период c {startDate:dd.MM.yyyy} по {endDate: dd.MM.yyyy}", 0) .AddTable([10, 10, 15, 15], GetData(raceId, startDate, endDate)) .Build(); return true; @@ -49,19 +49,19 @@ internal class TableReport var data = _raceEntriesRepository .ReadRaceEntries() .Where(x => x.DateReceipt >= startDate && x.DateReceipt <= endDate && x.RacesEntryDetails.Any(y => y.RaceId == raceId)) - .Select(x => new { x.JockeyId, Date = x.DateReceipt, CountIn = x.RacesEntryDetails.FirstOrDefault(y => y.RaceId == raceId)?.Count, CountOut = (int?)null }) + .Select(x => new { x.JockeyName, Date = x.DateReceipt, CountIn = x.RacesEntryDetails.FirstOrDefault(y => y.RaceId == raceId)?.Count, CountOut = (int?)null }) .Union( _racingHorsesRepository .ReadRacingHorses() .Where(x => x.RacingDate >= startDate && x.RacingDate <= endDate && x.RaceId == raceId) - .Select(x => new { x.JockeyId, Date = x.RacingDate, CountIn = (int?)null, CountOut = (int?)x.Result })) + .Select(x => new { x.JockeyName, Date = x.RacingDate, CountIn = (int?)null, CountOut = (int?)x.Result })) .OrderBy(x => x.Date); return new List() { item } .Union( data - .Select(x => new string[] { x.JockeyId.ToString(), x.Date.ToString(), x.CountIn?.ToString() ?? string.Empty, x.CountOut?.ToString() ?? string.Empty})) + .Select(x => new string[] { x.JockeyName, x.Date.ToString(), x.CountIn?.ToString() ?? string.Empty, x.CountOut?.ToString() ?? string.Empty})) .Union( [["Всего", "", data.Sum(x => x.CountIn ?? 0).ToString(), data.Sum(x => x.CountOut ?? 0).ToString()]]) diff --git a/ProjectHorseRacingOrg/Repositories/Implementations/QueryBuilder.cs b/ProjectHorseRacingOrg/Repositories/Implementations/QueryBuilder.cs new file mode 100644 index 0000000..9b53d34 --- /dev/null +++ b/ProjectHorseRacingOrg/Repositories/Implementations/QueryBuilder.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProjectHorseRacingOrg.Repositories.Implementations; + +public class QueryBuilder +{ + private readonly StringBuilder _builder; + + public QueryBuilder() + { + _builder = new(); + } + + public QueryBuilder AddCondition(string condition) + { + if (_builder.Length > 0) + { + _builder.Append(" AND "); + } + + _builder.Append(condition); + + return this; + } + + public string Build() + { + if (_builder.Length == 0) + { + return string.Empty; + } + + return $"WHERE {_builder}"; + } +} diff --git a/ProjectHorseRacingOrg/Repositories/Implementations/RaceEntriesRepository.cs b/ProjectHorseRacingOrg/Repositories/Implementations/RaceEntriesRepository.cs index 3bfb1be..0088d00 100644 --- a/ProjectHorseRacingOrg/Repositories/Implementations/RaceEntriesRepository.cs +++ b/ProjectHorseRacingOrg/Repositories/Implementations/RaceEntriesRepository.cs @@ -88,24 +88,63 @@ WHERE Id=@id"; _logger.LogInformation("Получение всех объектов"); try { + var builder = new QueryBuilder(); + if (dateForm.HasValue) + { + builder.AddCondition("re.DateReceipt >= @dateForm"); + } + if (dateTo.HasValue) + { + builder.AddCondition("re.DateReceipt <= @dateTo"); + } + if (raceId.HasValue) + { + builder.AddCondition("re.RaceId = @raceId"); + } + using var connection = new NpgsqlConnection(_connectionString.ConnectionString); - var querySelect = @" - SELECT fr.*, ffr.RaceId, ffr.Count FROM RaceEntries fr -INNER JOIN RaceEntryDetails ffr ON ffr.RaceEntryId = fr.Id"; + var querySelect = @$" + SELECT +re.*, +CONCAT(j.LastName, ' ', j.FirstName) as JockeyName, +red.RaceId, +red.Count, +r.Name as RaceName +FROM RaceEntries re +LEFT JOIN Jockeys j ON j.Id = re.JockeyId +INNER JOIN RaceEntryDetails red ON red.RaceEntryId = re.Id +LEFT JOIN Races r ON r.Id = red.RaceId +{builder.Build()}"; - var racesEntries = connection.Query(querySelect); - _logger.LogDebug("Полученные объекты: {json}", JsonConvert.SerializeObject(racesEntries)); + var raceEntryDict = new Dictionary>(); - return racesEntries.GroupBy(x => x.Id, y => y, - (key, value) => - RaceEntries.CreateOpeartion(value.First(), - value.Select(z => - RaceEntryDetails.CreateElement(0, z.RaceId, z.Count)))).ToList(); + var raceEntries = connection.Query(querySelect, + (entry, details) => + { + if (!raceEntryDict.TryGetValue(entry.Id, out var red)) + { + red = new List(); + raceEntryDict.Add(entry.Id, red); + } + + red.Add(details); + return entry; + }, splitOn: "RaceId", param: new { dateForm, dateTo, raceId }); + + _logger.LogDebug("Полученные объекты: {json}", JsonConvert.SerializeObject(raceEntries)); + + return raceEntryDict.Select(x => + { + var re = raceEntries.First(y => y.Id == x.Key); + re.SetRacesEntryDetails(x.Value); + return re; + }).ToArray(); } catch (Exception ex) { _logger.LogError(ex, "Ошибка при чтении объектов"); throw; } + } } diff --git a/ProjectHorseRacingOrg/Repositories/Implementations/RacingHorsesRepository.cs b/ProjectHorseRacingOrg/Repositories/Implementations/RacingHorsesRepository.cs index e4b0d0b..2c8512e 100644 --- a/ProjectHorseRacingOrg/Repositories/Implementations/RacingHorsesRepository.cs +++ b/ProjectHorseRacingOrg/Repositories/Implementations/RacingHorsesRepository.cs @@ -50,7 +50,11 @@ VALUES (@RaceId, @JockeyId, @HorseId, @RacingDate, @Result)"; { using var connection = new NpgsqlConnection(_connectionString.ConnectionString); - var querySelect = "SELECT * FROM RacingHorses"; + var querySelect = @"select rh.*, r.RaceType as RaceName, CONCAT(j.LastName, ' ', j.FirstName) as JockeyName, h.HorseNickName as HorseName + from racingHorses rh + INNER JOIN Races r ON r.Id = rh.RaceId + INNER JOIN Jockeys j ON j.Id = rh.JockeyId + INNER JOIN Horses h ON h.Id = rh.HorseId"; var racingHorses = connection.Query(querySelect); _logger.LogDebug("Полученные объекты: {json}", -- 2.25.1