Перейти к основному содержимому

Работа с БД на C#

Работа с БД на C#

Работа с базой данных — это фундаментальная задача в большинстве приложений: от простых утилит до масштабных корпоративных систем. В экосистеме .NET существует несколько подходов к взаимодействию с реляционными СУБД, и все они опираются на стандартные интерфейсы из пространства имён Система.Данные. Наиболее распространённые способы:

  • ADO.NET — низкоуровневый доступ к данным через провайдеры.
  • Entity Framework (EF Core) — высокоуровневый ORM (Object-Relational Mapper).
  • Dapper — лёгкий микрослой поверх ADO.NET для удобного маппинга.

В этом примере рассматриваются все три подхода на основе Microsoft SQL Server и SQLite, чтобы показать разницу в уровне абстракции и объёме кода.


Подготовка: создание тестовой базы данных

Для демонстрации используется SQLite — встраиваемая СУБД без необходимости установки сервера. Файл базы создаётся автоматически при первом подключении.

SQL-скрипт для создания таблицы:

CREATE TABLE IF NOT EXISTS Users (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Email TEXT NOT NULL UNIQUE,
Age INTEGER
);

1. Работа через ADO.NET (низкоуровневый подход)

ADO.NET предоставляет прямой контроль над соединением, командами и транзакциями. Этот подход требует больше шаблонного кода, но даёт максимальную гибкость.

using Система;
using Система.Данные.SQLite;

class AdoNetExample
{
private const string ConnectionString = "Данные Source=users.db;Version=3;";

static void Main()
{
// Создание таблицы
CreateUsersTable();

// Вставка записи
InsertUser("Алиса", "alice@example.com", 28);

// Чтение всех записей
ReadAllUsers();
}

static void CreateUsersTable()
{
using var connection = new SQLiteConnection(ConnectionString);
connection.Open();

string sql = @"
CREATE TABLE IF NOT EXISTS Users (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Email TEXT NOT NULL UNIQUE,
Age INTEGER
);";

using var command = new SQLiteCommand(sql, connection);
command.ExecuteNonQuery();
}

static void InsertUser(string name, string email, int age)
{
using var connection = new SQLiteConnection(ConnectionString);
connection.Open();

string sql = "INSERT INTO Users (Name, Email, Age) VALUES (@name, @email, @age);";

using var command = new SQLiteCommand(sql, connection);
command.Parameters.AddWithValue("@name", name);
command.Parameters.AddWithValue("@email", email);
command.Parameters.AddWithValue("@age", age);

int rowsAffected = command.ExecuteNonQuery();
Console.WriteLine($"Добавлено строк: {rowsAffected}");
}

static void ReadAllUsers()
{
using var connection = new SQLiteConnection(ConnectionString);
connection.Open();

string sql = "SELECT Id, Name, Email, Age FROM Users;";
using var command = new SQLiteCommand(sql, connection);
using var reader = command.ExecuteReader();

while (reader.Read())
{
int id = reader.GetInt32("Id");
string name = reader.GetString("Name");
string email = reader.GetString("Email");
int age = reader.GetInt32("Age");

Console.WriteLine($"ID: {id}, Имя: {name}, Email: {email}, Возраст: {age}");
}
}
}

Особенности ADO.NET:

  • Явное управление соединением (Open, Close).
  • Использование параметризованных запросов для защиты от SQL-инъекций.
  • Ручная обработка DataReader для чтения результатов.
  • Отсутствие автоматического преобразования строк в объекты.

2. Работа через Entity Framework Core (ORM)

Entity Framework Core — официальный ORM от Microsoft. Он позволяет работать с базой данных через объекты C#, а не через SQL-запросы.

Шаг 1: Установка зависимостей

Добавьте пакеты через NuGet:

dotnet add package Microsoft.EntityFrameworkCore.Sqlite

Шаг 2: Определение модели и контекста

using Microsoft.EntityFrameworkCore;

public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public int Age { get; set; }
}

public class AppDbContext : DbContext
{
public DbSet<User> Users { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Данные Source=users_ef.db");
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>(entity =>
{
entity.HasIndex(u => u.Email).IsUnique();
});
}
}

Шаг 3: Использование

using var context = new AppDbContext();

// Создание базы и таблиц (если не существует)
context.Database.EnsureCreated();

// Добавление пользователя
var user = new User
{
Name = "Боб",
Email = "bob@example.com",
Age = 34
};
context.Users.Add(user);
context.SaveChanges();

// Чтение всех пользователей
var allUsers = context.Users.ToList();
foreach (var u in allUsers)
{
Console.WriteLine($"ID: {u.Id}, Имя: {u.Name}, Email: {u.Email}, Возраст: {u.Age}");
}

Преимущества EF Core:

  • Автоматическое создание схемы БД из моделей (Code First).
  • LINQ-запросы вместо SQL.
  • Отслеживание изменений объектов.
  • Миграции для управления изменениями схемы.

Недостатки:

  • Больший оверхед по сравнению с ADO.NET.
  • Сложность отладки «сгенерированного» SQL.

3. Работа через Dapper (микро-ORM)

Dapper — лёгкая библиотека от команды Stack Overflow. Она расширяет IDbConnection, добавляя методы для автоматического маппинга результатов SQL-запросов в объекты.

Установка

dotnet add package Dapper
dotnet add package Система.Данные.SQLite

Пример использования

using Система;
using Система.Данные.SQLite;
using Dapper;

class DapperExample
{
private const string ConnectionString = "Данные Source=users_dapper.db;Version=3;";

static void Main()
{
using var connection = new SQLiteConnection(ConnectionString);
connection.Open();

// Создание таблицы
connection.Execute(@"
CREATE TABLE IF NOT EXISTS Users (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Email TEXT NOT NULL UNIQUE,
Age INTEGER
);");

// Вставка
var userId = connection.Execute(
"INSERT INTO Users (Name, Email, Age) VALUES (@Name, @Email, @Age);",
new { Name = "Карина", Email = "karina@example.com", Age = 25 });

// Чтение
var users = connection.Query<User>("SELECT * FROM Users;");
foreach (var u in users)
{
Console.WriteLine($"ID: {u.Id}, Имя: {u.Name}, Email: {u.Email}, Возраст: {u.Age}");
}
}
}

public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public int Age { get; set; }
}

Особенности Dapper:

  • Минимальный оверхед — почти как ADO.NET по скорости.
  • Автоматический маппинг полей в свойства объекта.
  • Поддержка множественных результатов, списков, асинхронных операций.
  • Требует написания SQL вручную, но без ручной обработки DataReader.

Сравнение подходов

КритерийADO.NETEntity Framework CoreDapper
Уровень абстракцииНизкийВысокийСредний
ПроизводительностьМаксимальнаяНиже из-за оверхедаПочти как ADO.NET
Объём кодаБольшойМинимальныйУмеренный
Гибкость SQLПолнаяОграниченная (LINQ)Полная
Защита от инъекцийЧерез параметрыАвтоматическаяЧерез параметры
МиграцииНетВстроеныНет

Рекомендации по выбору

  • Используйте ADO.NET, если требуется максимальный контроль, работа с legacy-системами или высокая производительность критична.
  • Выбирайте EF Core, если проект новый, команда предпочитает объектную модель, и важна скорость разработки.
  • Отдавайте предпочтение Dapper, если нужно сочетать производительность ADO.NET с удобством маппинга, особенно в микросервисах или API с большим числом запросов.

Безопасность и лучшие практики

  • Всегда используйте параметризованные запросы — никогда не конкатенируйте строки для формирования SQL.
  • Не храните строки подключения в коде — используйте appsettings.json или переменные окружения.
  • Оборачивайте соединения в using, чтобы гарантировать их закрытие.
  • Для продакшена применяйте пулы соединений, таймауты и логирование ошибок.
  • При работе с паролями или персональными данными — шифруйте их перед сохранением.

См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).