Загрузка данных


ПОЛНАЯ ИНСТРУКЦИЯ — от А до Я

Что тебе нужно сделать в итоге:

Создать библиотеку классов (DLL) на C#, которая умеет работать с твоей базой данных "Пасека".

---

ЧАСТЬ 1 — УСТАНОВКА ВСЕГО НЕОБХОДИМОГО

Шаг 1.1 — Установить Visual Studio

1. Зайди на сайт: https://visualstudio.microsoft.com/ru/
2. Нажми "Скачать Visual Studio"
3. Выбери Community (бесплатная версия)
4. Скачай установщик и запусти его
5. В установщике выбери:
   · Разработка классических приложений .NET
   · Нажми Установить

---

Шаг 1.2 — Убедись, что у тебя есть база данных

У тебя должен быть файл apiary.db (или любое другое название) с таблицами:

· Ульи
· Пчеловоды
· Инвентарь
· Мед
· Обслуживание_ульев

Если нет — создай через DB Browser for SQLite (я давал код выше).

Запомни путь к этому файлу, например:

```
C:\Users\ТвоеИмя\Desktop\apiary.db
```

---

ЧАСТЬ 2 — СОЗДАНИЕ ПРОЕКТА БИБЛИОТЕКИ

Шаг 2.1 — Открыть Visual Studio и создать проект

1. Запусти Visual Studio
2. Нажми "Создать новый проект"
3. В поиске напиши "Class Library"
4. Выбери "Библиотека классов (Class Library)" (не путай с .NET Core!)
5. Нажми "Далее"

Шаг 2.2 — Настройка проекта

Поле Что вписать
Имя проекта PasikaLibrary
Расположение C:\Users\ТвоеИмя\Desktop\ (или любая папка)
Решение PasikaLibrary
Нажми "Далее"

Шаг 2.3 — Выбор версии .NET

Выбери .NET 6.0 или .NET 8.0 (долгосрочная поддержка)
Нажми "Создать"

---

ЧАСТЬ 3 — УСТАНОВКА NUGet ПАКЕТОВ

Шаг 3.1 — Открыть менеджер пакетов

1. В правой части экрана найди Обозреватель решений (Solution Explorer)
2. Кликни правой кнопкой мыши по PasikaLibrary
3. Выбери "Управление пакетами NuGet..."

Шаг 3.2 — Установить SQLite пакет

1. В открывшемся окне нажми "Обзор"
2. В поиске напиши: System.Data.SQLite
3. Выбери пакет с иконкой синего куба
4. Нажми "Установить"
5. Согласись с лицензией (нажми "Принимаю")

Готово! Теперь в проекте есть всё для работы с SQLite.

---

ЧАСТЬ 4 — СОЗДАНИЕ КЛАССОВ (СУЩНОСТЕЙ)

Шаг 4.1 — Удалить лишний файл

В Обозревателе решений удали файл Class1.cs (кликни правой кнопкой → Удалить)

Шаг 4.2 — Создать класс Улей

1. Кликни правой кнопкой по PasikaLibrary → "Добавить" → "Класс..."
2. Назови: Улей.cs
3. Нажми "Добавить"
4. Вставь этот код:

```csharp
using System;

namespace PasikaLibrary
{
    /// <summary>
    /// Класс для хранения информации об улье
    /// </summary>
    public class Улей
    {
        public int Id { get; set; }
        public string Номер { get; set; }
        public int ВозрастМакти { get; set; }
        public string СилаСемьи { get; set; }
    }
}
```

Шаг 4.3 — Создать класс Пчеловод

1. Кликни правой кнопкой по PasikaLibrary → "Добавить" → "Класс..."
2. Назови: Пчеловод.cs
3. Вставь код:

```csharp
using System;

namespace PasikaLibrary
{
    /// <summary>
    /// Класс для хранения информации о пчеловоде
    /// </summary>
    public class Пчеловод
    {
        public int Id { get; set; }
        public string Фио { get; set; }
        public string Телефон { get; set; }
    }
}
```

Шаг 4.4 — Создать класс Инвентарь

1. Кликни правой кнопкой по PasikaLibrary → "Добавить" → "Класс..."
2. Назови: Инвентарь.cs
3. Вставь код:

```csharp
using System;

namespace PasikaLibrary
{
    /// <summary>
    /// Класс для хранения информации об инвентаре
    /// </summary>
    public class Инвентарь
    {
        public int Id { get; set; }
        public string Название { get; set; }
        public bool Защитный { get; set; }
        public int Количество { get; set; }
    }
}
```

Шаг 4.5 — Создать класс Мед

1. Кликни правой кнопкой по PasikaLibrary → "Добавить" → "Класс..."
2. Назови: Мед.cs
3. Вставь код:

```csharp
using System;

namespace PasikaLibrary
{
    /// <summary>
    /// Класс для хранения информации о собранном мёде
    /// </summary>
    public class Мед
    {
        public int Id { get; set; }
        public int IdУлья { get; set; }
        public DateTime ДатаСбора { get; set; }
        public decimal ВесКг { get; set; }
        public string СортМеда { get; set; }
    }
}
```

Шаг 4.6 — Создать класс Обслуживание

1. Кликни правой кнопкой по PasikaLibrary → "Добавить" → "Класс..."
2. Назови: Обслуживание.cs
3. Вставь код:

```csharp
using System;

namespace PasikaLibrary
{
    /// <summary>
    /// Класс для хранения информации об обслуживании улья
    /// </summary>
    public class Обслуживание
    {
        public int Id { get; set; }
        public int IdУлья { get; set; }
        public int IdПчеловода { get; set; }
        public DateTime ДатаОбслуживания { get; set; }
        public bool ЗащитаИспользована { get; set; }
    }
}
```

---

ЧАСТЬ 5 — СОЗДАНИЕ ИНТЕРФЕЙСА (ШАБЛОНА МЕТОДОВ)

Шаг 5.1 — Создать интерфейс

1. Кликни правой кнопкой по PasikaLibrary → "Добавить" → "Новый элемент..."
2. Выбери "Интерфейс"
3. Назови: IPasikaRepository.cs
4. Нажми "Добавить"
5. Вставь код:

```csharp
using System;
using System.Collections.Generic;

namespace PasikaLibrary
{
    /// <summary>
    /// Интерфейс для работы с базой данных пасеки
    /// </summary>
    public interface IPasikaRepository
    {
        // ============ CREATE (INSERT) ============
        int AddУлей(Улей улей);
        int AddПчеловод(Пчеловод пчеловод);
        int AddИнвентарь(Инвентарь инвентарь);
        int AddМед(Мед мед);
        int AddОбслуживание(Обслуживание обслуживание);

        // ============ READ (SELECT) ============
        List<Улей> GetAllУльи();
        Улей GetУлейById(int id);
        List<Улей> GetУльиByСила(string сила);
        List<Пчеловод> GetAllПчеловоды();
        Пчеловод GetПчеловодById(int id);
        List<Инвентарь> GetAllИнвентарь();
        Инвентарь GetИнвентарьById(int id);
        List<Мед> GetAllМед();
        List<Мед> GetМедByУлей(int idУлья);
        List<Обслуживание> GetAllОбслуживания();
        List<Обслуживание> GetОбслуживанияByПчеловод(int idПчеловода);
        List<Обслуживание> GetНарушенияБезЗащиты();

        // ============ UPDATE ============
        bool UpdateУлей(Улей улей);
        bool UpdateПчеловод(Пчеловод пчеловод);
        bool UpdateИнвентарь(Инвентарь инвентарь);
        bool UpdateМед(Мед мед);
        bool UpdateОбслуживание(Обслуживание обслуживание);

        // ============ DELETE ============
        bool DeleteУлей(int id);
        bool DeleteПчеловод(int id);
        bool DeleteИнвентарь(int id);
        bool DeleteМед(int id);
        bool DeleteОбслуживание(int id);

        // ============ ТРАНЗАКЦИЯ ============
        void AddОбслуживаниеСПроверкой(Обслуживание обслуживание);
    }
}
```

---

ЧАСТЬ 6 — СОЗДАНИЕ ГЛАВНОГО КЛАССА (РЕПОЗИТОРИЙ)

Шаг 6.1 — Создать класс Repository

1. Кликни правой кнопкой по PasikaLibrary → "Добавить" → "Класс..."
2. Назови: PasikaRepository.cs
3. Нажми "Добавить"

---

Шаг 6.2 — Вставить весь код

ВАЖНО: В коде ниже замени путь к базе данных на свой!

Найди строку:

```csharp
private string _connectionString = "Data Source=C:\\Users\\YourName\\Desktop\\apiary.db";
```

Замени на свой путь. Например, у тебя файл apiary.db лежит на рабочем столе:

```csharp
private string _connectionString = "Data Source=C:\\Users\\" + Environment.UserName + "\\Desktop\\apiary.db";
```

Или просто укажи полный путь.

---

Теперь вставь ЭТОТ КОД в PasikaRepository.cs:

```csharp
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Transactions;

namespace PasikaLibrary
{
    /// <summary>
    /// Репозиторий для работы с базой данных пасеки
    /// </summary>
    public class PasikaRepository : IPasikaRepository
    {
        // !!! ЗДЕСЬ ЗАМЕНИ ПУТЬ НА СВОЙ !!!
        private string _connectionString = "Data Source=C:\\Users\\YourName\\Desktop\\apiary.db";

        /// <summary>
        /// Конструктор с возможностью указать свой путь к БД
        /// </summary>
        public PasikaRepository() { }

        public PasikaRepository(string connectionString)
        {
            _connectionString = connectionString;
        }

        // ================================================================
        // 1. INSERT (ДОБАВЛЕНИЕ)
        // ================================================================

        public int AddУлей(Улей улей)
        {
            if (улей == null)
                throw new ArgumentNullException("Улей не может быть null");
            
            if (string.IsNullOrEmpty(улей.Номер))
                throw new Exception("Номер улья обязателен");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"INSERT INTO Ульи (номер_улья, возраст_матки, сила_семьи) 
                           VALUES (@номер, @возраст, @сила);
                           SELECT last_insert_rowid();";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@номер", улей.Номер);
            cmd.Parameters.AddWithValue("@возраст", улей.ВозрастМакти);
            cmd.Parameters.AddWithValue("@сила", улей.СилаСемьи);

            return Convert.ToInt32(cmd.ExecuteScalar());
        }

        public int AddПчеловод(Пчеловод пчеловод)
        {
            if (пчеловод == null)
                throw new ArgumentNullException("Пчеловод не может быть null");

            if (string.IsNullOrEmpty(пчеловод.Фио))
                throw new Exception("ФИО обязательно");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"INSERT INTO Пчеловоды (фио, телефон) 
                           VALUES (@фио, @телефон);
                           SELECT last_insert_rowid();";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@фио", пчеловод.Фио);
            cmd.Parameters.AddWithValue("@телефон", пчеловод.Телефон ?? "");

            return Convert.ToInt32(cmd.ExecuteScalar());
        }

        public int AddИнвентарь(Инвентарь инвентарь)
        {
            if (инвентарь == null)
                throw new ArgumentNullException("Инвентарь не может быть null");

            if (string.IsNullOrEmpty(инвентарь.Название))
                throw new Exception("Название обязательно");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"INSERT INTO Инвентарь (название, защитный, количество) 
                           VALUES (@название, @защитный, @количество);
                           SELECT last_insert_rowid();";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@название", инвентарь.Название);
            cmd.Parameters.AddWithValue("@защитный", инвентарь.Защитный ? 1 : 0);
            cmd.Parameters.AddWithValue("@количество", инвентарь.Количество);

            return Convert.ToInt32(cmd.ExecuteScalar());
        }

        public int AddМед(Мед мед)
        {
            if (мед == null)
                throw new ArgumentNullException("Мед не может быть null");

            if (мед.ВесКг <= 0)
                throw new Exception("Вес должен быть больше 0");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"INSERT INTO Мед (id_улья, дата_сбора, вес_кг, сорт_меда) 
                           VALUES (@id_улья, @дата, @вес, @сорт);
                           SELECT last_insert_rowid();";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id_улья", мед.IdУлья);
            cmd.Parameters.AddWithValue("@дата", мед.ДатаСбора.ToString("yyyy-MM-dd"));
            cmd.Parameters.AddWithValue("@вес", мед.ВесКг);
            cmd.Parameters.AddWithValue("@сорт", мед.СортМеда ?? "");

            return Convert.ToInt32(cmd.ExecuteScalar());
        }

        public int AddОбслуживание(Обслуживание обслуживание)
        {
            if (обслуживание == null)
                throw new ArgumentNullException("Обслуживание не может быть null");

            // ===== БИЗНЕС-ПРАВИЛО: проверка защитного инвентаря =====
            if (!обслуживание.ЗащитаИспользована)
            {
                using var connCheck = new SQLiteConnection(_connectionString);
                connCheck.Open();

                string checkSql = "SELECT COUNT(*) FROM Инвентарь WHERE защитный = 1 AND количество > 0";
                using var checkCmd = new SQLiteCommand(checkSql, connCheck);
                int count = Convert.ToInt32(checkCmd.ExecuteScalar());

                if (count == 0)
                {
                    throw new Exception("НЕТ ЗАЩИТНОГО ИНВЕНТАРЯ! Нельзя работать с ульем без защиты!");
                }
            }
            // =========================================================

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"INSERT INTO Обслуживание_ульев 
                           (id_улья, id_пчеловода, дата_обслуживания, защита_использована) 
                           VALUES (@id_улья, @id_пчеловода, @дата, @защита);
                           SELECT last_insert_rowid();";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id_улья", обслуживание.IdУлья);
            cmd.Parameters.AddWithValue("@id_пчеловода", обслуживание.IdПчеловода);
            cmd.Parameters.AddWithValue("@дата", обслуживание.ДатаОбслуживания.ToString("yyyy-MM-dd"));
            cmd.Parameters.AddWithValue("@защита", обслуживание.ЗащитаИспользована ? 1 : 0);

            return Convert.ToInt32(cmd.ExecuteScalar());
        }

        // ================================================================
        // 2. READ (ЧТЕНИЕ)
        // ================================================================

        public List<Улей> GetAllУльи()
        {
            var result = new List<Улей>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_улья, номер_улья, возраст_матки, сила_семьи FROM Ульи";
            using var cmd = new SQLiteCommand(sql, conn);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Улей
                {
                    Id = reader.GetInt32(0),
                    Номер = reader.GetString(1),
                    ВозрастМакти = reader.GetInt32(2),
                    СилаСемьи = reader.GetString(3)
                });
            }

            return result;
        }

        public Улей GetУлейById(int id)
        {
            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_улья, номер_улья, возраст_матки, сила_семьи FROM Ульи WHERE id_улья = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", id);
            using var reader = cmd.ExecuteReader();

            if (reader.Read())
            {
                return new Улей
                {
                    Id = reader.GetInt32(0),
                    Номер = reader.GetString(1),
                    ВозрастМакти = reader.GetInt32(2),
                    СилаСемьи = reader.GetString(3)
                };
            }

            return null;
        }

        public List<Улей> GetУльиByСила(string сила)
        {
            var result = new List<Улей>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_улья, номер_улья, возраст_матки, сила_семьи FROM Ульи WHERE сила_семьи = @сила";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@сила", сила);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Улей
                {
                    Id = reader.GetInt32(0),
                    Номер = reader.GetString(1),
                    ВозрастМакти = reader.GetInt32(2),
                    СилаСемьи = reader.GetString(3)
                });
            }

            return result;
        }

        public List<Пчеловод> GetAllПчеловоды()
        {
            var result = new List<Пчеловод>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_пчеловода, фио, телефон FROM Пчеловоды";
            using var cmd = new SQLiteCommand(sql, conn);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Пчеловод
                {
                    Id = reader.GetInt32(0),
                    Фио = reader.GetString(1),
                    Телефон = reader.IsDBNull(2) ? null : reader.GetString(2)
                });
            }

            return result;
        }

        public Пчеловод GetПчеловодById(int id)
        {
            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_пчеловода, фио, телефон FROM Пчеловоды WHERE id_пчеловода = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", id);
            using var reader = cmd.ExecuteReader();

            if (reader.Read())
            {
                return new Пчеловод
                {
                    Id = reader.GetInt32(0),
                    Фио = reader.GetString(1),
                    Телефон = reader.IsDBNull(2) ? null : reader.GetString(2)
                };
            }

            return null;
        }

        public List<Инвентарь> GetAllИнвентарь()
        {
            var result = new List<Инвентарь>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_инвентаря, название, защитный, количество FROM Инвентарь";
            using var cmd = new SQLiteCommand(sql, conn);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Инвентарь
                {
                    Id = reader.GetInt32(0),
                    Название = reader.GetString(1),
                    Защитный = reader.GetInt32(2) == 1,
                    Количество = reader.GetInt32(3)
                });
            }

            return result;
        }

        public Инвентарь GetИнвентарьById(int id)
        {
            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_инвентаря, название, защитный, количество FROM Инвентарь WHERE id_инвентаря = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", id);
            using var reader = cmd.ExecuteReader();

            if (reader.Read())
            {
                return new Инвентарь
                {
                    Id = reader.GetInt32(0),
                    Название = reader.GetString(1),
                    Защитный = reader.GetInt32(2) == 1,
                    Количество = reader.GetInt32(3)
                };
            }

            return null;
        }

        public List<Мед> GetAllМед()
        {
            var result = new List<Мед>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_меда, id_улья, дата_сбора, вес_кг, сорт_меда FROM Мед";
            using var cmd = new SQLiteCommand(sql, conn);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Мед
                {
                    Id = reader.GetInt32(0),
                    IdУлья = reader.GetInt32(1),
                    ДатаСбора = DateTime.Parse(reader.GetString(2)),
                    ВесКг = (decimal)reader.GetDouble(3),
                    СортМеда = reader.IsDBNull(4) ? null : reader.GetString(4)
                });
            }

            return result;
        }

        public List<Мед> GetМедByУлей(int idУлья)
        {
            var result = new List<Мед>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_меда, id_улья, дата_сбора, вес_кг, сорт_меда FROM Мед WHERE id_улья = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", idУлья);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Мед
                {
                    Id = reader.GetInt32(0),
                    IdУлья = reader.GetInt32(1),
                    ДатаСбора = DateTime.Parse(reader.GetString(2)),
                    ВесКг = (decimal)reader.GetDouble(3),
                    СортМеда = reader.IsDBNull(4) ? null : reader.GetString(4)
                });
            }

            return result;
        }

        public List<Обслуживание> GetAllОбслуживания()
        {
            var result = new List<Обслуживание>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "SELECT id_записи, id_улья, id_пчеловода, дата_обслуживания, защита_использована FROM Обслуживание_ульев";
            using var cmd = new SQLiteCommand(sql, conn);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Обслуживание
                {
                    Id = reader.GetInt32(0),
                    IdУлья = reader.GetInt32(1),
                    IdПчеловода = reader.GetInt32(2),
                    ДатаОбслуживания = DateTime.Parse(reader.GetString(3)),
                    ЗащитаИспользована = reader.GetInt32(4) == 1
                });
            }

            return result;
        }

        public List<Обслуживание> GetОбслуживанияByПчеловод(int idПчеловода)
        {
            var result = new List<Обслуживание>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"SELECT id_записи, id_улья, id_пчеловода, дата_обслуживания, защита_использована 
                           FROM Обслуживание_ульев 
                           WHERE id_пчеловода = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", idПчеловода);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Обслуживание
                {
                    Id = reader.GetInt32(0),
                    IdУлья = reader.GetInt32(1),
                    IdПчеловода = reader.GetInt32(2),
                    ДатаОбслуживания = DateTime.Parse(reader.GetString(3)),
                    ЗащитаИспользована = reader.GetInt32(4) == 1
                });
            }

            return result;
        }

        // ===== JOIN запрос (нарушения без защиты) =====
        public List<Обслуживание> GetНарушенияБезЗащиты()
        {
            var result = new List<Обслуживание>();

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"
                SELECT 
                    Обслуживание_ульев.id_записи,
                    Обслуживание_ульев.id_улья,
                    Обслуживание_ульев.id_пчеловода,
                    Обслуживание_ульев.дата_обслуживания,
                    Обслуживание_ульев.защита_использована,
                    Ульи.номер_улья,
                    Пчеловоды.фио
                FROM Обслуживание_ульев
                JOIN Ульи ON Обслуживание_ульев.id_улья = Ульи.id_улья
                JOIN Пчеловоды ON Обслуживание_ульев.id_пчеловода = Пчеловоды.id_пчеловода
                WHERE Обслуживание_ульев.защита_использована = 0";

            using var cmd = new SQLiteCommand(sql, conn);
            using var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                result.Add(new Обслуживание
                {
                    Id = reader.GetInt32(0),
                    IdУлья = reader.GetInt32(1),
                    IdПчеловода = reader.GetInt32(2),
                    ДатаОбслуживания = DateTime.Parse(reader.GetString(3)),
                    ЗащитаИспользована = reader.GetInt32(4) == 1
                });
            }

            return result;
        }

        // ================================================================
        // 3. UPDATE (ОБНОВЛЕНИЕ)
        // ================================================================

        public bool UpdateУлей(Улей улей)
        {
            if (улей == null)
                throw new ArgumentNullException("Улей не может быть null");

            // Проверяем, существует ли улей
            var existing = GetУлейById(улей.Id);
            if (existing == null)
                throw new Exception($"Улей с id {улей.Id} не найден");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"UPDATE Ульи SET 
                           номер_улья = @номер,
                           возраст_матки = @возраст,
                           сила_семьи = @сила
                           WHERE id_улья = @id";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@номер", улей.Номер);
            cmd.Parameters.AddWithValue("@возраст", улей.ВозрастМакти);
            cmd.Parameters.AddWithValue("@сила", улей.СилаСемьи);
            cmd.Parameters.AddWithValue("@id", улей.Id);

            return cmd.ExecuteNonQuery() > 0;
        }

        public bool UpdateПчеловод(Пчеловод пчеловод)
        {
            if (пчеловод == null)
                throw new ArgumentNullException("Пчеловод не может быть null");

            var existing = GetПчеловодById(пчеловод.Id);
            if (existing == null)
                throw new Exception($"Пчеловод с id {пчеловод.Id} не найден");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"UPDATE Пчеловоды SET 
                           фио = @фио,
                           телефон = @телефон
                           WHERE id_пчеловода = @id";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@фио", пчеловод.Фио);
            cmd.Parameters.AddWithValue("@телефон", пчеловод.Телефон ?? "");
            cmd.Parameters.AddWithValue("@id", пчеловод.Id);

            return cmd.ExecuteNonQuery() > 0;
        }

        public bool UpdateИнвентарь(Инвентарь инвентарь)
        {
            if (инвентарь == null)
                throw new ArgumentNullException("Инвентарь не может быть null");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"UPDATE Инвентарь SET 
                           название = @название,
                           защитный = @защитный,
                           количество = @количество
                           WHERE id_инвентаря = @id";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@название", инвентарь.Название);
            cmd.Parameters.AddWithValue("@защитный", инвентарь.Защитный ? 1 : 0);
            cmd.Parameters.AddWithValue("@количество", инвентарь.Количество);
            cmd.Parameters.AddWithValue("@id", инвентарь.Id);

            return cmd.ExecuteNonQuery() > 0;
        }

        public bool UpdateМед(Мед мед)
        {
            if (мед == null)
                throw new ArgumentNullException("Мед не может быть null");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"UPDATE Мед SET 
                           id_улья = @id_улья,
                           дата_сбора = @дата,
                           вес_кг = @вес,
                           сорт_меда = @сорт
                           WHERE id_меда = @id";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id_улья", мед.IdУлья);
            cmd.Parameters.AddWithValue("@дата", мед.ДатаСбора.ToString("yyyy-MM-dd"));
            cmd.Parameters.AddWithValue("@вес", мед.ВесКг);
            cmd.Parameters.AddWithValue("@сорт", мед.СортМеда ?? "");
            cmd.Parameters.AddWithValue("@id", мед.Id);

            return cmd.ExecuteNonQuery() > 0;
        }

        public bool UpdateОбслуживание(Обслуживание обслуживание)
        {
            if (обслуживание == null)
                throw new ArgumentNullException("Обслуживание не может быть null");

            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = @"UPDATE Обслуживание_ульев SET 
                           id_улья = @id_улья,
                           id_пчеловода = @id_пчеловода,
                           дата_обслуживания = @дата,
                           защита_использована = @защита
                           WHERE id_записи = @id";

            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id_улья", обслуживание.IdУлья);
            cmd.Parameters.AddWithValue("@id_пчеловода", обслуживание.IdПчеловода);
            cmd.Parameters.AddWithValue("@дата", обслуживание.ДатаОбслуживания.ToString("yyyy-MM-dd"));
            cmd.Parameters.AddWithValue("@защита", обслуживание.ЗащитаИспользована ? 1 : 0);
            cmd.Parameters.AddWithValue("@id", обслуживание.Id);

            return cmd.ExecuteNonQuery() > 0;
        }

        // ================================================================
        // 4. DELETE (УДАЛЕНИЕ с проверкой связей)
        // ================================================================

        public bool DeleteУлей(int id)
        {
            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            // Проверяем, есть ли связанные записи в таблице Мед
            string checkMed = "SELECT COUNT(*) FROM Мед WHERE id_улья = @id";
            using var cmdMed = new SQLiteCommand(checkMed, conn);
            cmdMed.Parameters.AddWithValue("@id", id);
            if (Convert.ToInt32(cmdMed.ExecuteScalar()) > 0)
            {
                throw new Exception("Нельзя удалить улей! Сначала удалите записи о собранном мёде.");
            }

            // Проверяем, есть ли связанные записи в таблице Обслуживание
            string checkService = "SELECT COUNT(*) FROM Обслуживание_ульев WHERE id_улья = @id";
            using var cmdService = new SQLiteCommand(checkService, conn);
            cmdService.Parameters.AddWithValue("@id", id);
            if (Convert.ToInt32(cmdService.ExecuteScalar()) > 0)
            {
                throw new Exception("Нельзя удалить улей! Сначала удалите записи об обслуживании.");
            }

            // Если связей нет — удаляем
            string sql = "DELETE FROM Ульи WHERE id_улья = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", id);
            return cmd.ExecuteNonQuery() > 0;
        }

        public bool DeleteПчеловод(int id)
        {
            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            // Проверяем, есть ли связанные записи в таблице Обслуживание
            string check = "SELECT COUNT(*) FROM Обслуживание_ульев WHERE id_пчеловода = @id";
            using var cmdCheck = new SQLiteCommand(check, conn);
            cmdCheck.Parameters.AddWithValue("@id", id);
            if (Convert.ToInt32(cmdCheck.ExecuteScalar()) > 0)
            {
                throw new Exception("Нельзя удалить пчеловода! Сначала удалите записи об обслуживании.");
            }

            string sql = "DELETE FROM Пчеловоды WHERE id_пчеловода = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", id);
            return cmd.ExecuteNonQuery() > 0;
        }

        public bool DeleteИнвентарь(int id)
        {
            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "DELETE FROM Инвентарь WHERE id_инвентаря = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", id);
            return cmd.ExecuteNonQuery() > 0;
        }

        public bool DeleteМед(int id)
        {
            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "DELETE FROM Мед WHERE id_меда = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", id);
            return cmd.ExecuteNonQuery() > 0;
        }

        public bool DeleteОбслуживание(int id)
        {
            using var conn = new SQLiteConnection(_connectionString);
            conn.Open();

            string sql = "DELETE FROM Обслуживание_ульев WHERE id_записи = @id";
            using var cmd = new SQLiteCommand(sql, conn);
            cmd.Parameters.AddWithValue("@id", id);
            return cmd.ExecuteNonQuery() > 0;
        }

        // ================================================================
        // 5. ТРАНЗАКЦИЯ (TransactionScope)
        // ================================================================

        public void AddОбслуживаниеСПроверкой(Обслуживание обслуживание)
        {
            using var scope = new TransactionScope();
            try
            {
                using var conn = new SQLiteConnection(_connectionString);
                conn.Open();

                // 1. Проверяем, есть ли защитный инвентарь
                string checkSql = "SELECT COUNT(*) FROM Инвентарь WHERE защитный = 1 AND количество > 0";
                using var checkCmd = new SQLiteCommand(checkSql, conn);
                int count = Convert.ToInt32(checkCmd.ExecuteScalar());

                if (count == 0 && !обслуживание.ЗащитаИспользована)
                {
                    throw new Exception("НЕТ ЗАЩИТНОГО ИНВЕНТАРЯ! Операция отменена!");
                }

                // 2. Добавляем обслуживание
                int newId = AddОбслуживание(обслуживание);

                // 3. Если использовалась защита — уменьшаем количество инвентаря
                if (обслуживание.ЗащитаИспользована)
                {
                    string updateSql = @"UPDATE Инвентарь 
                                       SET количество = количество - 1 
                                       WHERE защитный = 1 AND количество > 0 
                                       LIMIT 1";
                    using var updateCmd = new SQLiteCommand(updateSql, conn);
                    updateCmd.ExecuteNonQuery();
                }

                // Подтверждаем транзакцию
                scope.Complete();

                Console.WriteLine($"Обслуживание добавлено! ID: {newId}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Ошибка в транзакции: {ex.Message}");
                throw;
            }
        }
    }
}
```

---

ЧАСТЬ 7 — СБОРКА ПРОЕКТА

Шаг 7.1 — Собрать библиотеку

1. В меню сверху нажми "Сборка" → "Собрать решение"
2. Или нажми клавишу Ctrl + Shift + B

Шаг 7.2 — Найти готовую DLL

После сборки файл PasikaLibrary.dll появится в папке:

```
C:\Users\ТвоеИмя\Desktop\PasikaLibrary\PasikaLibrary\bin\Debug\net6.0\
```

---

ЧАСТЬ 8 — СОЗДАНИЕ ПРИМЕРА ИСПОЛЬЗОВАНИЯ (ДЛЯ ТЕСТА)

Шаг 8.1 — Создать консольное приложение

1. Кликни правой кнопкой по Решению (в Обозревателе решений) → "Добавить" → "Новый проект"
2. Выбери "Консольное приложение"
3. Назови: TestApp
4. Нажми "Создать"

Шаг 8.2 — Добавить ссылку на библиотеку

1. В Обозревателе решений кликни правой кнопкой по TestApp
2. Выбери "Добавить" → "Ссылка на проект..."
3. Выбери PasikaLibrary → OK

Шаг 8.3 — Установить SQLite в тестовом проекте

1. Кликни правой кнопкой по TestApp → "Управление пакетами NuGet..."
2. Установи System.Data.SQLite (так же как делали выше)

Шаг 8.4 — Вставить тестовый код

Замени весь код в Program.cs на этот:

```csharp
using System;
using System.Collections.Generic;
using PasikaLibrary;

class Program
{
    static void Main()
    {
        Console.WriteLine("=== ТЕСТ БАЗЫ ДАННЫХ ПАСЕКА ===\n");

        // Укажи путь к своей БД
        string path = @"C:\Users\" + Environment.UserName + @"\Desktop\apiary.db";
        var repo = new PasikaRepository($"Data Source={path}");

        try
        {
            // ======= 1. ВЫВЕСТИ ВСЕ УЛЬИ =======
            Console.WriteLine("--- Все ульи ---");
            var ульи = repo.GetAllУльи();
            foreach (var u in ульи)
            {
                Console.WriteLine($"ID: {u.Id}, Номер: {u.Номер}, Сила: {u.СилаСемьи}");
            }

            // ======= 2. ДОБАВИТЬ НОВЫЙ УЛЕЙ =======
            Console.WriteLine("\n--- Добавляем новый улей ---");
            var newУлей = new Улей
            {
                Номер = "Улей-Тест",
                ВозрастМакти = 1,
                СилаСемьи = "сильная"
            };
            int newId = repo.AddУлей(newУлей);
            Console.WriteLine($"Добавлен улей с ID: {newId}");

            // ======= 3. ПОЛУЧИТЬ УЛЕЙ ПО ID =======
            Console.WriteLine("\n--- Получаем улей по ID ---");
            var улей = repo.GetУлейById(newId);
            Console.WriteLine($"Найден: {улей.Номер}, Сила: {улей.СилаСемьи}");

            // ======= 4. ОБНОВИТЬ УЛЕЙ =======
            Console.WriteLine("\n--- Обновляем улей ---");
            улей.СилаСемьи = "средняя";
            repo.UpdateУлей(улей);
            Console.WriteLine("Улей обновлён!");

            // ======= 5. ВСЕ ПЧЕЛОВОДЫ =======
            Console.WriteLine("\n--- Все пчеловоды ---");
            var пчеловоды = repo.GetAllПчеловоды();
            foreach (var p in пчеловоды)
            {
                Console.WriteLine($"ID: {p.Id}, ФИО: {p.Фио}, Телефон: {p.Телефон}");
            }

            // ======= 6. ДОБАВИТЬ МЁД =======
            Console.WriteLine("\n--- Добавляем мёд ---");
            var newМед = new Мед
            {
                IdУлья = 1,
                ДатаСбора = DateTime.Now,
                ВесКг = 15.5m,
                СортМеда = "липовый"
            };
            int medId = repo.AddМед(newМед);
            Console.WriteLine($"Добавлен мёд с ID: {medId}");

            // ======= 7. ВСЕ ЗАПИСИ О МЁДЕ =======
            Console.WriteLine("\n--- Весь мёд ---");
            var меды = repo.GetAllМед();
            foreach (var m in меды)
            {
                Console.WriteLine($"ID: {m.Id}, Улей: {m.IdУлья}, Вес: {m.ВесКг} кг, Сорт: {m.СортМеда}");
            }

            // ======= 8. ДОБАВИТЬ ОБСЛУЖИВАНИЕ =======
            Console.WriteLine("\n--- Добавляем обслуживание (С ЗАЩИТОЙ) ---");
            var обслуживание = new Обслуживание
            {
                IdУлья = 1,
                IdПчеловода = 1,
                ДатаОбслуживания = DateTime.Now,
                ЗащитаИспользована = true
            };
            int servId = repo.AddОбслуживание(обслуживание);
            Console.WriteLine($"Добавлено обслуживание с ID: {servId}");

            // ======= 9. ПОПРОБОВАТЬ БЕЗ ЗАЩИТЫ (должна быть ошибка!) =======
            Console.WriteLine("\n--- Пробуем добавить обслуживание БЕЗ ЗАЩИТЫ ---");
            try
            {
                var badService = new Обслуживание
                {
                    IdУлья = 2,
                    IdПчеловода = 2,
                    ДатаОбслуживания = DateTime.Now,
                    ЗащитаИспользована = false
                };
                repo.AddОбслуживание(badService);
                Console.WriteLine("❌ ОШИБКА: Удалось добавить без защиты!");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"✅ ЗАЩИТА СРАБОТАЛА: {ex.Message}");
            }

            // ======= 10. НАРУШЕНИЯ БЕЗ ЗАЩИТЫ (JOIN) =======
            Console.WriteLine("\n--- Нарушения (работа без защиты) ---");
            var нарушения = repo.GetНарушенияБезЗащиты();
            foreach (var n in нарушения)
            {
                Console.WriteLine($"Нарушение: ID записи {n.Id}, Улей {n.IdУлья}, Пчеловод {n.IdПчеловода}");
            }

            // ======= 11. ТРАНЗАКЦИЯ =======
            Console.WriteLine("\n--- Транзакция: добавляем обслуживание + списываем инвентарь ---");
            try
            {
                var serviceWithCheck = new Обслуживание
                {
                    IdУлья = 1,
                    IdПчеловода = 1,
                    ДатаОбслуживания = DateTime.Now,
                    ЗащитаИспользована = true
                };
                repo.AddОбслуживаниеСПроверкой(serviceWithCheck);
                Console.WriteLine("✅ Транзакция выполнена успешно!");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"❌ Ошибка: {ex.Message}");
            }

            // ======= 12. УДАЛЕНИЕ =======
            Console.WriteLine("\n--- Пытаемся удалить улей (есть связи) ---");
            try
            {
                repo.DeleteУлей(1);
                Console.WriteLine("❌ ОШИБКА: Удалось удалить улей со связями!");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"✅ ЗАЩИТА СРАБОТАЛА: {ex.Message}");
            }

            Console.WriteLine("\n=== ТЕСТ ЗАВЕРШЁН ===");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Общая ошибка: {ex.Message}");
        }

        Console.ReadKey();
    }
}
```

Шаг 8.5 — Запустить тест

1. Сделай TestApp запускаемым проектом (кликни правой кнопкой по TestApp → "Назначить запускаемым проектом")
2. Нажми F5 (Запуск)

---

ЧАСТЬ 9 — ЧТО СДАВАТЬ

Тебе нужно сдать:

1. Файл PasikaLibrary.dll (библиотека) — лежит в папке bin\Debug
2. Исходный код (все .cs файлы) — можно скопировать в Word или архив
3. Скриншоты работы тестового приложения (как оно выполняется)
4. Скриншоты базы данных (что данные добавились)

---

Если что-то пошло не так:

Проблема Решение
Не видит System.Data.SQLite Установи NuGet пакет в оба проекта
Ошибка "no such table" Проверь путь к БД и название таблиц
Не компилируется Проверь, что все классы в namespace PasikaLibrary
Ошибка "FOREIGN KEY" Проверь, что id в таблицах существуют

---

Готово! Всё подробно расписал. Если что-то непонятно — спрашивай конкретно, где застрял!