Перейти к содержанию

Этап 2. База данных и слои приложения

Задание

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

Ход работы

На этом этапе создается проект Windows Forms или WPF, подключается пакет Microsoft.Data.Sqlite, добавляется структура папок и создаются классы доступа к базе данных. В базе должны появиться системные таблицы Roles, Users, LoginAttempts и не менее трех таблиц выбранной предметной области.

Работа в проекте

Сначала создайте проект и убедитесь, что он запускается с пустым окном. Затем добавьте SQLite, создайте AppConfig, DbConnectionFactory и DatabaseInitializer. Вызов DatabaseInitializer.Initialize() выполняется до открытия первой формы или окна. После первого запуска рядом с приложением должен появиться файл practice.db, который можно открыть через DB Browser for SQLite.

Команды

Windows Forms:

dotnet new winforms -n PracticeApp
cd PracticeApp
dotnet add package Microsoft.Data.Sqlite

WPF:

dotnet new wpf -n PracticeApp
cd PracticeApp
dotnet add package Microsoft.Data.Sqlite

Рекомендуемая структура проекта

ProjectName/
  Models/
    User.cs
    Role.cs
    LoginAttempt.cs
  Data/
    DbConnectionFactory.cs
    UserRepository.cs
    <Entity>Repository.cs
  Services/
    AuthService.cs
    CaptchaService.cs
    PasswordHasher.cs
  Forms/ или Views/
    LoginForm.cs / LoginWindow.xaml
    RegisterForm.cs / RegisterWindow.xaml
    MainForm.cs / MainWindow.xaml

Минимальный набор классов этапа

Файл Назначение
Models/User.cs модель пользователя
Models/Book.cs или аналог модель предметной сущности
Data/DbConnectionFactory.cs создание подключения к БД
Data/DatabaseInitializer.cs создание таблиц и начальных данных
Data/UserRepository.cs запросы к таблице пользователей
Data/<Entity>Repository.cs запросы к предметной таблице

Строка подключения и фабрика

public static class AppConfig
{
    public const string ConnectionString = "Data Source=practice.db";
}
using Microsoft.Data.Sqlite;

public static class DbConnectionFactory
{
    public static SqliteConnection Create()
    {
        return new SqliteConnection(AppConfig.ConnectionString);
    }
}

Инициализация SQLite

Ниже приведен фрагмент для системных таблиц и предметной области «Библиотека». В своем варианте замените Authors и Books на таблицы выбранной предметной области.

using Microsoft.Data.Sqlite;

public static class DatabaseInitializer
{
    public static void Initialize()
    {
        using var connection = DbConnectionFactory.Create();
        connection.Open();

        Execute(connection, """
            CREATE TABLE IF NOT EXISTS Roles (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                Name TEXT NOT NULL UNIQUE
            );

            CREATE TABLE IF NOT EXISTS Users (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                Login TEXT NOT NULL UNIQUE,
                PasswordHash TEXT NOT NULL,
                PasswordSalt TEXT NOT NULL,
                FullName TEXT NOT NULL,
                RoleId INTEGER NOT NULL,
                IsActive INTEGER NOT NULL DEFAULT 1,
                CreatedAt TEXT NOT NULL,
                FOREIGN KEY (RoleId) REFERENCES Roles(Id)
            );

            CREATE TABLE IF NOT EXISTS LoginAttempts (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                UserLogin TEXT NOT NULL,
                IsSuccess INTEGER NOT NULL,
                Message TEXT NOT NULL,
                CreatedAt TEXT NOT NULL
            );

            CREATE TABLE IF NOT EXISTS Authors (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                FullName TEXT NOT NULL,
                Country TEXT
            );

            CREATE TABLE IF NOT EXISTS Books (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                Title TEXT NOT NULL,
                AuthorId INTEGER NOT NULL,
                Year INTEGER,
                InventoryNumber TEXT NOT NULL UNIQUE,
                IsAvailable INTEGER NOT NULL DEFAULT 1,
                FOREIGN KEY (AuthorId) REFERENCES Authors(Id)
            );
            """);

        Execute(connection, "INSERT OR IGNORE INTO Roles (Id, Name) VALUES (1, 'admin'), (2, 'operator'), (3, 'user');");
        Execute(connection, "INSERT OR IGNORE INTO Authors (Id, FullName, Country) VALUES (1, 'А. С. Пушкин', 'Россия');");
        Execute(connection, "INSERT OR IGNORE INTO Books (Id, Title, AuthorId, Year, InventoryNumber, IsAvailable) VALUES (1, 'Капитанская дочка', 1, 1836, 'B-0001', 1);");
    }

    private static void Execute(SqliteConnection connection, string sql)
    {
        using var command = connection.CreateCommand();
        command.CommandText = sql;
        command.ExecuteNonQuery();
    }
}

Для Windows Forms вызов инициализации размещается в Program.cs:

ApplicationConfiguration.Initialize();
DatabaseInitializer.Initialize();
Application.Run(new LoginForm());

Для WPF вызов можно выполнить в App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    DatabaseInitializer.Initialize();
    new LoginWindow().Show();
}

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