Почему C# и PostgreSQL — это сила, которую стоит освоить
Мир разработки — это постоянный выбор. Выбирая язык, фреймворк и базу данных, мы фактически закладываем фундамент будущего проекта. И если вы оказались на этой странице, значит, вас интересует одна из самых мощных и современных связок в enterprise-разработке: C# и PostgreSQL.
Почему именно эта пара? C# — зрелый, строго типизированный язык с огромной экосистемой и фантастической производительностью. PostgreSQL — объектно-реляционная СУБД, которая обгоняет многих конкурентов по возможностям, стабильности и поддержке сложных типов данных (например, JSONB, массивы, полнотекстовый поиск). Вместе они дают вам не просто "базу и язык", а гибкий, масштабируемый инструмент для создания веб-приложений, микросервисов и аналитических систем.
В этом руководстве мы не просто пройдемся по теории. Мы с головой нырнем в практику: от установки драйвера до написания сложных транзакций. Вы узнаете, как правильно настроить подключение, выполнять CRUD-операции, использовать современные ORM (Entity Framework Core и Dapper) и избегать типовых граблей. Поехали!
Шаг 1. Подготовка: что нужно установить
Прежде чем писать код, давайте убедимся, что у вас есть всё необходимое.
- PostgreSQL — скачайте последнюю версию с официального сайта. Во время установки запомните порт (по умолчанию 5432) и пароль для суперпользователя
postgres. - Visual Studio / Rider / VS Code — любая IDE, поддерживающая .NET.
- .NET SDK (6.0, 7.0 или 8.0) — чем новее, тем лучше. Мы будем использовать .NET 8.
Теперь создайте новый проект. Для консольного приложения это просто:
dotnet new console -n CsharpPostgresDemo
cd CsharpPostgresDemo
Самое главное — установить провайдер для PostgreSQL. В мире .NET это пакет Npgsql (произносится как "Эн-пи-эс-кью-эл"). Он является основой для всех остальных библиотек.
dotnet add package Npgsql
Шаг 2. Первое подключение: проверяем связь
Создадим простейший скрипт, который подключится к базе и выведет версию сервера. Это лучший способ убедиться, что всё работает.
using Npgsql;
// Строка подключения: укажите свои данные
string connectionString = "Host=localhost;Port=5432;Database=postgres;Username=postgres;Password=your_password";
using var connection = new NpgsqlConnection(connectionString);
connection.Open();
// Выполняем запрос
using var command = new NpgsqlCommand("SELECT version();", connection);
string version = (string)await command.ExecuteScalarAsync();
Console.WriteLine($"Подключение успешно! Версия PostgreSQL: {version}");
Запустите код. Если видите в консоли что-то вроде "PostgreSQL 16.1 on x86_64-pc-linux-gnu...", вы сделали это! Если нет — проверьте пароль, имя хоста и убедитесь, что служба PostgreSQL запущена.
Шаг 3. CRUD-операции в C# с PostgreSQL
Теперь, когда подключение работает, давайте создадим таблицу и выполним полный цикл: Create, Read, Update, Delete.
Создание таблицы
string createTableSql = @"
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);";
using var cmdCreate = new NpgsqlCommand(createTableSql, connection);
await cmdCreate.ExecuteNonQueryAsync();
Console.WriteLine("Таблица users создана.");
Вставка данных (INSERT)
// Используем параметризованный запрос — это защита от SQL-инъекций!
string insertSql = "INSERT INTO users (name, email) VALUES (@name, @email) RETURNING id;";
using var cmdInsert = new NpgsqlCommand(insertSql, connection);
cmdInsert.Parameters.AddWithValue("@name", "Алексей Иванов");
cmdInsert.Parameters.AddWithValue("@email", "alex@example.com");
int newId = (int)await cmdInsert.ExecuteScalarAsync();
Console.WriteLine($"Добавлен пользователь с ID: {newId}");
Чтение данных (SELECT)
string selectSql = "SELECT id, name, email, created_at FROM users;";
using var cmdSelect = new NpgsqlCommand(selectSql, connection);
using var reader = await cmdSelect.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
Console.WriteLine($"ID: {reader["id"]}, Name: {reader["name"]}, Email: {reader["email"]}");
}
Обновление и удаление (UPDATE / DELETE)
// Обновляем email
string updateSql = "UPDATE users SET email = @newEmail WHERE id = @id;";
using var cmdUpdate = new NpgsqlCommand(updateSql, connection);
cmdUpdate.Parameters.AddWithValue("@newEmail", "alex_new@example.com");
cmdUpdate.Parameters.AddWithValue("@id", newId);
int rowsUpdated = await cmdUpdate.ExecuteNonQueryAsync();
Console.WriteLine($"Обновлено строк: {rowsUpdated}");
// Удаляем пользователя
string deleteSql = "DELETE FROM users WHERE id = @id;";
using var cmdDelete = new NpgsqlCommand(deleteSql, connection);
cmdDelete.Parameters.AddWithValue("@id", newId);
int rowsDeleted = await cmdDelete.ExecuteNonQueryAsync();
Console.WriteLine($"Удалено строк: {rowsDeleted}");
Обратите внимание: мы всегда используем параметризованные запросы. Никогда не вставляйте значения напрямую в строку SQL через конкатенацию — это главный путь к уязвимостям.
Шаг 4. Entity Framework Core: ORM для ленивых (но умных)
Писать SQL вручную — это круто, но в больших проектах удобнее использовать Object-Relational Mapping (ORM). Entity Framework Core (EF Core) — стандарт де-факто для C#. Он берет на себя генерацию SQL, миграции и отслеживание изменений.
Установка пакетов
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Microsoft.EntityFrameworkCore.Design
Создаем модель и контекст
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public DateTime CreatedAt { get; set; }
}
public class AppDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("Host=localhost;Database=mydb;Username=postgres;Password=your_password");
}
}
Выполняем CRUD через EF Core
using var db = new AppDbContext();
await db.Database.EnsureCreatedAsync(); // Автосоздание таблицы
// Create
var user = new User { Name = "Мария Петрова", Email = "maria@example.com" };
db.Users.Add(user);
await db.SaveChangesAsync();
Console.WriteLine($"User created with ID: {user.Id}");
// Read
var