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


По методичке нужно сделать Windows Forms приложение с Entity Framework, подключённое к твоей базе `VasilisaSalon`. Вот полный код под твой салон:

---

**Шаги по методичке (1-5 делаешь руками в Visual Studio):**

1. Создаёшь проект **Windows Forms (.NET Framework)**
2. Создаёшь папку `Models`
3. В папке Models добавляешь **Модель ADO.NET EDM** → называешь `Model1`
4. Выбираешь **Конструктор EF из базы данных** → создаёшь соединение → указываешь сервер и базу `VasilisaSalon`
5. Ставишь галочку **Таблицы** → Готово → пересобираешь проект

---

После этого в `Model1Context.cs` дописываешь Singleton:

```csharp
public partial class VasilisaSalonEntities : DbContext
{
    private static VasilisaSalonEntities _context;

    public static VasilisaSalonEntities GetContext()
    {
        if (_context == null)
            _context = new VasilisaSalonEntities();
        return _context;
    }

    public VasilisaSalonEntities()
        : base("name=VasilisaSalonEntities")
    {
    }
}
```

---

**На форму кидаешь:**
- `DataGridView` → имя `dataGridViewClients`
- `TextBox` → имя `txtSearch`
- `ComboBox` → имя `cmbSort`
- Кнопка → имя `SaveButton`, текст "Сохранить", Visible = False
- Кнопка → имя `CancelButton`, текст "Отменить", Visible = False

---

**Полный код Form1.cs:**

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using VasilisaSalon.Models;

namespace VasilisaSalon
{
    public partial class Form1 : Form
    {
        // список для отображения в таблице
        private List<ClientDisplayItem> displayClients = new List<ClientDisplayItem>();
        // списки для отслеживания изменений
        private List<ClientDisplayItem> newClients = new List<ClientDisplayItem>();
        private List<ClientDisplayItem> changedClients = new List<ClientDisplayItem>();
        private List<ClientDisplayItem> deletedClients = new List<ClientDisplayItem>();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            LoadClientsData();
            InitializeComboBoxes();
            InitializeContextMenu();
            dataGridViewClients.CellValueChanged += dataGridViewClients_CellValueChanged;
        }

        // класс для отображения клиентов в таблице
        private class ClientDisplayItem
        {
            public int ClientId { get; set; }
            public string FullName { get; set; }
            public string Phone { get; set; }
            public string Email { get; set; }
            public string Contraindications { get; set; }
            public string Allergies { get; set; }
        }

        // загрузка данных из БД
        private void LoadClientsData()
        {
            try
            {
                var db = VasilisaSalonEntities.GetContext();

                displayClients = db.client
                    .Select(c => new ClientDisplayItem
                    {
                        ClientId = c.client_id,
                        FullName = c.full_name,
                        Phone = c.phone,
                        Email = c.email ?? "Не указан",
                        Contraindications = c.contraindications ?? "Нет",
                        Allergies = c.allergies ?? "Нет"
                    })
                    .ToList();

                dataGridViewClients.DataSource = displayClients;
                FormatDataGridView();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Ошибка при загрузке данных: " + ex.Message);
            }
        }

        // настройка внешнего вида таблицы
        private void FormatDataGridView()
        {
            dataGridViewClients.ReadOnly = false;
            dataGridViewClients.AutoGenerateColumns = false;
            dataGridViewClients.Columns.Clear();

            dataGridViewClients.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "ClientId",
                HeaderText = "ID",
                ReadOnly = true,
                Width = 40
            });
            dataGridViewClients.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "FullName",
                HeaderText = "ФИО клиента",
                Width = 200
            });
            dataGridViewClients.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "Phone",
                HeaderText = "Телефон",
                Width = 130
            });
            dataGridViewClients.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "Email",
                HeaderText = "Email",
                Width = 160
            });
            dataGridViewClients.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "Contraindications",
                HeaderText = "Противопоказания",
                Width = 160
            });
            dataGridViewClients.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "Allergies",
                HeaderText = "Аллергии",
                Width = 130
            });
        }

        // инициализация сортировки и поиска
        private void InitializeComboBoxes()
        {
            cmbSort.Items.AddRange(new[] { "По ФИО", "По телефону" });
            cmbSort.SelectedIndex = 0;

            txtSearch.TextChanged += FilterControls_Changed;
            cmbSort.SelectedIndexChanged += FilterControls_Changed;
        }

        private void FilterControls_Changed(object sender, EventArgs e)
        {
            ApplyFilters();
        }

        private void ApplyFilters()
        {
            string searchText = txtSearch.Text.Trim();
            string selectedSort = cmbSort.SelectedItem?.ToString();

            var filtered = displayClients.AsQueryable();

            // поиск по ФИО или телефону
            if (!string.IsNullOrEmpty(searchText))
            {
                filtered = filtered.Where(c =>
                    c.FullName.ToLower().Contains(searchText.ToLower()) ||
                    c.Phone.Contains(searchText));
            }

            // сортировка
            switch (selectedSort)
            {
                case "По ФИО":
                    filtered = filtered.OrderBy(c => c.FullName);
                    break;
                case "По телефону":
                    filtered = filtered.OrderBy(c => c.Phone);
                    break;
            }

            dataGridViewClients.DataSource = filtered.ToList();
        }

        // контекстное меню (правая кнопка мыши)
        private void InitializeContextMenu()
        {
            ToolStripMenuItem deleteMenuItem = new ToolStripMenuItem("Удалить");
            ToolStripMenuItem addMenuItem = new ToolStripMenuItem("Добавить");

            ContextMenu.Items.AddRange(new[] { deleteMenuItem, addMenuItem });
            dataGridViewClients.ContextMenuStrip = ContextMenu;

            deleteMenuItem.Click += DeleteItem_Click;
            addMenuItem.Click += AddItem_Click;
        }

        // добавление нового клиента
        private void AddItem_Click(object sender, EventArgs e)
        {
            SaveButton.Visible = true;
            CancelButton.Visible = true;

            var newClient = new ClientDisplayItem
            {
                ClientId = -1,
                FullName = "Новый клиент",
                Phone = "+7",
                Email = "",
                Contraindications = "Нет",
                Allergies = "Нет"
            };

            newClients.Add(newClient);
            displayClients.Add(newClient);
            dataGridViewClients.DataSource = displayClients;
            FormatDataGridView();
        }

        // удаление клиента
        private void DeleteItem_Click(object sender, EventArgs e)
        {
            SaveButton.Visible = true;
            CancelButton.Visible = true;

            var rows = dataGridViewClients.SelectedRows;
            if (rows.Count > 0)
            {
                foreach (DataGridViewRow row in rows)
                {
                    var item = displayClients[row.Index];
                    if (!newClients.Contains(item))
                        deletedClients.Add(item);
                    displayClients.Remove(item);
                    newClients.Remove(item);
                    changedClients.Remove(item);
                }
                dataGridViewClients.DataSource = displayClients;
                FormatDataGridView();
            }
            else
            {
                MessageBox.Show("Выберите строку", "Ошибка",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        // фиксация изменений в ячейке
        private void dataGridViewClients_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            SaveButton.Visible = true;
            CancelButton.Visible = true;

            if (e.RowIndex >= 0)
            {
                var item = displayClients[e.RowIndex];
                if (!newClients.Contains(item) && !changedClients.Contains(item))
                    changedClients.Add(item);

                var value = dataGridViewClients.Rows[e.RowIndex].Cells[e.ColumnIndex].Value?.ToString();
                switch (e.ColumnIndex)
                {
                    case 1: item.FullName = value; break;
                    case 2: item.Phone = value; break;
                    case 3: item.Email = value; break;
                    case 4: item.Contraindications = value; break;
                    case 5: item.Allergies = value; break;
                }
            }
        }

        // отмена всех изменений
        private void CancelButton_Click(object sender, EventArgs e)
        {
            newClients.Clear();
            changedClients.Clear();
            deletedClients.Clear();
            LoadClientsData();
            SaveButton.Visible = false;
            CancelButton.Visible = false;
        }

        // сохранение изменений в БД
        private void SaveButton_Click(object sender, EventArgs e)
        {
            try
            {
                var db = VasilisaSalonEntities.GetContext();

                // сохраняем изменения
                foreach (var item in changedClients)
                {
                    var dbItem = db.client.Find(item.ClientId);
                    if (dbItem != null)
                    {
                        dbItem.full_name = item.FullName;
                        dbItem.phone = item.Phone;
                        dbItem.email = item.Email;
                        dbItem.contraindications = item.Contraindications;
                        dbItem.allergies = item.Allergies;
                    }
                }

                // удаляем записи
                foreach (var item in deletedClients)
                {
                    var dbItem = db.client.Find(item.ClientId);
                    if (dbItem != null)
                        db.client.Remove(dbItem);
                }

                // добавляем новых клиентов
                foreach (var item in newClients)
                {
                    db.client.Add(new client
                    {
                        full_name = item.FullName,
                        phone = item.Phone,
                        email = item.Email,
                        contraindications = item.Contraindications,
                        allergies = item.Allergies,
                        reg_date = DateTime.Now,
                        pd_consent = true
                    });
                }

                db.SaveChanges();

                newClients.Clear();
                changedClients.Clear();
                deletedClients.Clear();
                LoadClientsData();

                SaveButton.Visible = false;
                CancelButton.Visible = false;

                MessageBox.Show("Данные сохранены успешно!");
            }
            catch (Exception ex)
            {
                MessageBox.Show("Ошибка при сохранении: " + ex.Message);
            }
        }
    }
}
```

---

**Что тут сделано по сравнению с методичкой:**
- Вместо книг и авторов — клиенты салона с полями ФИО, телефон, противопоказания, аллергии
- Поиск работает по ФИО и номеру телефона
- Сортировка по ФИО или телефону
- Добавление, удаление и изменение клиентов с сохранением в БД — всё по той же логике что в методичке, просто под твои таблицы