C# Portal | Программирование
15.1K subscribers
929 photos
111 videos
24 files
771 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

Связь: @devmangx

РКН: https://clck.ru/3FocB6
Download Telegram
Встраивать бизнес-логику прямо в SQL-запросы?

Это верный способ превратить код в нечто нетестируемое и хрупкое.

Представь, ты делаешь поиск по инвойсам. Нужно фильтровать по:

- номеру инвойса
- имени клиента
- email
- статусу заказа
- названию продукта

И всё это в любых комбинациях.

Самое быстрое, но грязное решение — напихать всю эту логику прямо в SQL-запрос.
И вот теперь все твои бизнес-правила оказались заперты внутри базы.
Тестировать их без реальной базы уже не выйдет.

Альтернатива — Specification Pattern.

Это способ вынести сложную логику формирования запросов в отдельный класс, чтобы можно было её переиспользовать и тестировать.

Как это работает:

Создаёшь класс спецификации, который описывает критерии поиска.

Он принимает фильтры и строит выражение (например, LINQ).

Потом передаёшь эту спецификацию в репозиторий или обработчик запросов.

Этот подход отлично подходит для фильтрации и сложных запросов.

Результат:

- тесты запускаются быстрее
- бизнес-логика понятнее
- код запросов проще поддерживать

Specification Pattern это про то, чтобы держать логику в месте, где её можно понять, протестировать и не проклинать через полгода. 🔫

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
8🔥3👍2
Please open Telegram to view this post
VIEW IN TELEGRAM
31😁20👍6😈1
На Хабре вышла статья о том, как с помощью EF Core и PostgreSQL избежать deadlock и oversell при работе со стоками. Автор разбирает подход с сортировкой обновлений по ключам, использованием ExecuteUpdateAsync, повторными попытками (retry), триггерами, очередями и батчами.

В статье есть бенчмарки, примеры кода и ссылка на репозиторий на GitHub.

Читать подробнее: habr.com/ru/articles/955714/

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72
В превью C# 14 появились partial-конструкторы и partial-события.

Каждый из них должен состоять ровно из одного объявления-определения и одного объявления-реализации.

Реализация partial-события обязана содержать add и remove аксессоры.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👎8👍4🤔2
На GitHub появился классный репозиторий с чётко структурированным материалом по system design. В нём собраны:

- основы проектирования крупных систем,
- типичные вопросы и решения для собеседований,
- карточки Anki для запоминания ключевых концепций.

Сохрани, чтобы не потерять: https://github.com/donnemartin/system-design-primer

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍83
Ты правильно называешь свои DTO?

Какую схему именования выбрать

Когда ты делаешь Web API, твои эндпоинты принимают и отдают данные.

Частая практика — добавлять к таким моделям суффикс Dto

Но вот в чём проблема:

DTO часто смешивают входные и выходные данные в одном классе.
Со временем такие классы разрастаются и становятся непонятными.

Мой вариант: использовать суффиксы Request и Response вместо Dto:

• CreateUserRequest —> для входных данных
• UserResponse —> для выходных

Почему так лучше:

Чёткое назначение —> сразу видно, модель для входа или для выхода.
Масштабируемость —> изменения в Response не ломают Request.
Поддерживаемость —> не надо гадать, что вообще делает UserDto.

Совет: выбери один подход и используй его последовательно во всём проекте.

А ты как называешь свои модели Request/Response или Dto? Делись опытом

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
10👍8🤣3🔥2
Деревья выражений в C# помогают создавать быстрые и эффективные методы преобразования данных, ускоряя работу с объектами и запросами в Entity Framework Core. В статье раскрываются механизмы мэппинга и построения сложных фильтров через IQueryable.

Читать подробнее: https://habr.com/ru/articles/932110/

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43
Экономим память как профи: 5 продвинутых техник

Если вы работаете с .NET, то знаете, под капотом куча мощных инструментов, про которые редко говорят. Вот 5 API, которые реально экономят память и ускоряют код.

1. CollectionsMarshal.AsSpan() — прямой доступ к списку

Обычно List<T> это удобная, но безопасная обёртка над массивом.
Если нужен Span без копирования:

using System.Runtime.InteropServices;

var numbers = new List<int> { 1, 2, 3, 4, 5 };
Span<int> span = CollectionsMarshal.AsSpan(numbers);


Работает напрямую с внутренним массивом списка, без ToArray().
Важно: при изменении размера списка Span станет недействительным.
Когда использовать: большие буферы, короткие циклы.
Выигрыш: до 2 раз меньше памяти.

2. CollectionsMarshal.GetValueRefOrNullRef() — доступ к словарю без двойного поиска

Обычный способ вызывает поиск ключа дважды:

if (dict.TryGetValue("foo", out var value)) {
value++;
dict["foo"] = value;
}


Лучше так:

using System.Runtime.InteropServices;

ref int valueRef = ref CollectionsMarshal.GetValueRefOrNullRef(dict, "foo");
if (!Unsafe.IsNullRef(ref valueRef))
valueRef++;


Получаем ссылку прямо на значение без повторного поиска.
Когда использовать: большие словари, горячие циклы.
Выигрыш: примерно в 2 раза быстрее.

3. GC.AllocateUninitializedArray<T>() — массив без обнуления

.NET по умолчанию обнуляет массив:

int[] arr = new int[1000];


Если вы всё равно перезаписываете элементы - то это лишняя работа.
Быстрее:

int[] arr = GC.AllocateUninitializedArray<int>(1000);
for (int i = 0; i < arr.Length; i++) arr[i] = i;


Когда использовать: если массив заполняется сразу.
Выигрыш: ~15% быстрее на больших массивах.

4. ArrayPool<T>.Shared и IMemoryOwner — аренда массивов

Постоянные аллокации убивают GC:

for (int i = 0; i < 1000; i++) {
var buffer = new byte[1024];
DoSomething(buffer);
}


Используем пул:

using System.Buffers;

for (int i = 0; i < 1000; i++) {
using IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(1024);
DoSomething(owner.Memory.Span);
}


Когда использовать: сетевые серверы, конвейеры, потоковые операции.
Выигрыш: до 1000 раз меньше аллокаций.

5. ObjectPool<T> — переиспользование дорогих объектов

Создание тяжёлых объектов вроде StringBuilder дорого:

for (int i = 0; i < 100; i++) {
var sb = new StringBuilder(1024);
sb.Append("Hello ").Append(i);
Console.WriteLine(sb.ToString());
}


Пулим:

using Microsoft.Extensions.ObjectPool;

var provider = new DefaultObjectPoolProvider();
var pool = provider.CreateStringBuilderPool();

for (int i = 0; i < 100; i++) {
var sb = pool.Get();
sb.Clear();
sb.Append("Hello ").Append(i);
Console.WriteLine(sb.ToString());
pool.Return(sb);
}


Когда использовать: логирование, сериализация, временные буферы.
Выигрыш: до 4 раз быстрее, в 50 раз меньше памяти.

Если вы когда-нибудь заглядывали в свой профилировщик и задавались вопросом, почему так много времени тратится на сборку мусора или копирование памяти, эти приёмы помогут вам это исправить. Они требуют аккуратности, но дают настоящую производительность.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍9
Rider 2025.3 EAP 6 уже доступен!

В этом билде появилась поддержка ASP. NET и обнаружения проблем с базой данных прямо в окне Monitoring 🔥

Теперь, когда ты запускаешь или отлаживаешь приложение, мониторинг автоматически определяет:

Медленные или чрезмерно частые запросы к БД
Слишком большие результаты выборок
Медленные действия MVC или обработчики Razor-страниц
…и многое другое

Подробнее — здесь

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
14
This media is not supported in your browser
VIEW IN TELEGRAM
Задумывался, почему приложение ощущается «тормозным», хотя с пропускной способностью вроде всё ок? Дело в том, что latency и throughput описывают два совершенно разных аспекта производительности.

Latency — это задержка на один пакет. То, что ощущает пользователь, когда нажимает кнопку. Это отзывчивость системы. Это время, за которое один запрос проходит путь от сервера до конечного устройства. В это входит время обработки на сервере, ожидание в очереди, распространение по сети, задержка при передаче и последний участок соединения до устройства пользователя.

Throughput — это объём данных в секунду. Не скорость отдельного пакета, а то, сколько пакетов проходит через «трубу» за определённый промежуток времени. Throughput — это ёмкость системы. Высокий throughput означает, что система справляется с нагрузкой, не захлёбываясь.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥63👏2
C# и LINQ = функциональный коктейль для кодинга

Если объяснить максимально просто — функциональный стиль позволяет писать код так, как ты о нём говоришь.

«Отфильтровать пользователей старше 30»
«Сгруппировать пользователей по школе»
«Показать все имена пользователей»

В отличие от процедурного подхода, где нужно думать и о том, что делать, и как именно это сделать — управлять переменными, добавлять и удалять элементы из списков, сортировать результаты и так далее.

В LINQ больше двух десятков операторов, но чтобы начать, достаточно пары базовых:

Select — выбрать нужные данные
Where — отфильтровать записи
Any — проверить, существует ли хотя бы один элемент
GroupBy — сгруппировать совпадающие элементы
ToList — собрать результат в List<T>
ToDictionary — собрать результат в Dictionary<K,V>

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥222
Одно небольшое изменение = запрос в 400 раз быстрее

Вот что было сделано, чтобы добиться такого прироста.

Реализовывалась пагинация с курсором через EF и Postgres.

Но нужно было сделать запрос быстрее.

Как ускорить SQL-запрос?

Добавить индекс, и всё должно полететь.

Так ведь?

Не совсем…

Был создан составной индекс по нужным колонкам, чтобы ускорить выборку.

НО ЗАПРОС СТАЛ МЕДЛЕННЕЕ!!!

Пришлось разбираться, почему индекс не используется.

Оказалось, что дело в сравнении кортежей — это и решило проблему.

Но непонятно было, как перенести это в запрос EF Core.

К счастью, провайдер Postgres поддерживает это через кастомную функцию.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3
Настройка batch size в Entity Framework

По умолчанию для провайдера SQL Server batch size равен 42.
Это значит, что при вставке 100 строк произойдёт 5 отдельных запросов к базе.

Я недавно гонял простой бенчмарк в .NET, и вот что получилось:
даже если уменьшить количество раунд-трипов, batch size 1000 оказался самым медленным, а вот 200 показал себя лучше всего — некий "sweet spot".

Вывод простой: тестируйте на своих сценариях.
Оптимальный размер batch может отличаться в зависимости от типа нагрузки и объёмов данных.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
1
В свежей статье «Обзор нововведений в C# 14» собрали ключевые фичи новых версий C#:
появилось ключевое слово field, добавили модификаторы в лямбдах, перегрузки присваиваний, extension-свойства, неявные преобразования к Span и даже partial-конструкторы.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍4
В Entity Framework 10 есть анализатор, который выдает предупреждение, если выполняется конкатенация внутри вызова «сырого» SQL-метода, как показано ниже

var users = context.Users
.FromSqlRaw("SELECT * FROM Users WHERE [" + fieldName + "] IS NULL");


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍93🥴1
Планирование в Visual Studio теперь доступно в публичной превью-версии

Это обновление добавляет новый способ, с помощью которого Copilot может разруливать сложные, многошаговые задачи. Благодаря Planning Copilot теперь может изучать твой код, разбивать большие задачи на подзадачи и выполнять их пошагово, в итоге ты получаешь более предсказуемые результаты и лучше понимаешь, что именно он делает.

Мы уже видим обнадёживающие результаты: улучшилась успешность и стабильность работы разных моделей. Но это только начало


Попробуй в Visual Studio 2022 версии 17.14:
зайди в Tools → Options → Copilot → Enable Planning и включи функцию.

После этого расскажи, что думаешь.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
1🥴1
6 Шагов для Правильной Настройки Нового .NET-проекта

1. Задай единый стиль кода

Первое, что я добавляю в проект — файл .editorconfig.

Он заставляет всех в команде придерживаться одинакового форматирования и соглашений об именах, чтобы не было разношерстных отступов и случайных неймингов.

Создать его можно прямо в Visual Studio.

Стандартная конфигурация - хороший старт, но можно подстроить под вкусы команды.

Положи файл в корень решения, чтобы все проекты следовали тем же правилам. При желании можно переопределить настройки в отдельных подпапках, добавив туда свой .editorconfig.

Вот два примера .editorconfig, которые можно использовать:

- из репозитория .NET runtime
- вариант для обычных .NET-проектов

2. Централизуй настройки сборки

Дальше я добавляю файл Directory.Build.props в корень решения. Он позволяет задавать настройки сборки, общие для всех проектов.

Пример:

<Project>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project>


Так .csproj файлы остаются чистыми и единообразными, поэтому не нужно повторять эти свойства в каждом проекте.

Если потом захочешь подключить статические анализаторы или поменять параметры сборки, то делается это в одном месте.

Фишка в том, что .csproj файлы становятся почти пустыми, кроме ссылок на NuGet-пакеты.

3. Централизуй управление пакетами

Когда решение разрастается, версии NuGet-пакетов в разных проектах начинают расходиться и чёрт, это превращается в кошмар 😬

Тут помогает централизованное управление пакетами.

Создай в корне файл Directory.Packages.props:

<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

<ItemGroup>
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.15.0.120848" />
</ItemGroup>
</Project>


Теперь, когда подключаешь пакет в проекте, указываешь только имя, без версии:

<PackageReference Include="Microsoft.AspNetCore.OpenApi" />


Все версии хранятся централизованно. Обновлять зависимости становится проще, а рассинхрон версий между проектами исчезает.

Если нужно, можно переопределить версию в конкретном проекте.

4. Подключи статический анализ кода

Статический анализ помогает ловить потенциальные баги и следить за качеством кода. В .NET уже есть встроенные анализаторы, но я обычно добавляю SonarAnalyzer.CSharp, ведь он делает проверку глубже.

Установи пакет: Install-Package SonarAnalyzer.CSharp

И добавь его как глобальную зависимость в Directory.Build.props:

<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" />
</ItemGroup>


Дополнительно настрой сборку:

<Project>
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AnalysisLevel>latest</AnalysisLevel>
<AnalysisMode>All</AnalysisMode>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>
</Project>


Теперь билд упадет, если будут серьезные проблемы с качеством кода = неплохая страховка.

Если какие-то правила не подходят, можно понизить их уровень до none в .editorconfig.

5. Настрой локальную оркестрацию

Чтобы у всех разработчиков среда была одинаковой, стоит настроить контейнерную оркестрацию.

Один из вариантов это .NET Aspire

.NET Aspire добавляет сервис-дискавери, телеметрию и упрощает конфигурацию. Все это встроено прямо в .NET-проекты.

Пример добавления проекта и Postgres-ресурса:

var postgres = builder.AddPostgres("demo-db");

builder.AddProject<WebApi>("webapi")
.WithReference(postgres)
.WaitFor(postgres);

builder.Build().Run();


Aspire под капотом использует Docker, но разработчику с ним работать приятнее.

В любом случае цель одна.

6. Автоматизируй сборку через CI

В конце я настраиваю простой workflow в GitHub Actions, чтобы проверять каждый коммит.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1710❤‍🔥1
Отличный плейлист для тех, кто только начинает изучать бэкенд

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
9