Заполнить Combobox данными из таблицы БД, в зависимости от значения выбранного в другом Combobox'е

Мне нужна помощь с решением небольшой задачи. Сам уже много чего перепробовал, но не выходит( Пишу программу для курсового (для управляющего отелем). У меня есть таблица Rooms с полями room_id и room_type, мне нужно, чтобы при выборе типа комнаты для резервирования в combobox с room_id подставлялись все id комнат из таблицы Rooms, которые имеют данный тип (Single, к примеру). Надеюсь понятно объяснил. Ниже код загрузки данных в комбобоксы(из form_load).введите сюда описание изображения

// loading data to combobox3
            DataTable Rooms = new DataTable();
            using (SqlConnection coon = new SqlConnection(conString))
            {
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = coon;
                cmd.CommandText = "select room_type from Rooms where reservation_id = 0";
                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                adapter.Fill(Rooms);
            }

        for (int i = 0; i < Rooms.Rows.Count; i++)
        {
            comboBox3.Items.Add(Rooms.Rows[i]["room_type"]);
        }

        // loading data to combobox2
        using (SqlConnection coon = new SqlConnection(conString))
        {
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = coon;
            cmd.CommandText = "select froom_id from Rooms where reservation_id = 0"
            SqlDataAdapter adapter = new SqlDataAdapter(cmd);
            adapter.Fill(Rooms);
        }

        for (int i = 0; i < Rooms.Rows.Count; i++)
        {
            comboBox2.Items.Add(Rooms.Rows[i]["froom_id"]);
        }

Пробовал делать как-то так, но чтобы данные в комбобоксе с room_id обновились нужно обновить и форму, а после этого сбрасывается значение в комбобоксе с room_type пробовал сохранять его и подставлять после загрузки формы опять, но ничего так и не получилось. Может кто-нибудь подскажет, как это сделать?

 cmd.CommandText = "select froom_id from Rooms where reservation_id = 0 AND room_type = " + "'" + comboBox3.Text + "'";

Ответы (1 шт):

Автор решения: Bulson

пример работы

Во-первых, типы комнат должны храниться в отдельной таблице, схема такая схема БД

Во-вторых, для заполнения комбобоксов нам понадобиться такой класс

class ComboItem
{
    public int Id { get; set; }
    public string Text { get; set; }
}

Тогда форма будет выглядеть так

public partial class FormMain : Form
{
    private const string _conString = @"Data Source=(localdb)\MSSQLLocalDB;" +
        "Initial Catalog=RoomsDB;Integrated Security=True;" +
        "Connect Timeout=60;Encrypt=False;" +
        "TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";

    //источник данных для комбобокса типов комнат
    private BindingSource _bsTypes;
    //источник данных для комбобокса комнат
    private BindingSource _bsNumbers;

    public FormMain()
    {
        InitializeComponent();

        //привязка к комбобоксу выбора тип комнат
        _bsTypes = new BindingSource();
        _bsTypes.DataSource = typeof(ComboItem);
        _comboBoxTypes.DataSource = _bsTypes;
        _comboBoxTypes.DisplayMember = nameof(ComboItem.Text);

        //привязка к комбобоксу выбора номеров комнат
        _bsNumbers = new BindingSource();
        _bsNumbers.DataSource = typeof(ComboItem);
        _comboBoxNumbers.DataSource = _bsNumbers;
        _comboBoxNumbers.DisplayMember = nameof(ComboItem.Text);

        this.Load += FormMain_Load;
    }

    private async void FormMain_Load(object sender, EventArgs e)
    {
        _bsTypes.Add(new ComboItem { Text = "Любой" });
        _bsNumbers.Add(new ComboItem { Text = "Нет выбора" });

        //извлекаем из БД типы комнат, заполняем комбобокс
        await LoadRoomTypesAsync();
        //подписка на событие выбора типа комнаты
        _bsTypes.CurrentChanged += OnRoomTypeSelected;
    }

    /// <summary>
    /// После выбора типа комнат
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void OnRoomTypeSelected(object sender, EventArgs e)
    {
        //определяем Id выбранного пункта
        int selectedId = (_bsTypes.Current as ComboItem).Id;
        //очищаем комбобокс
        _bsNumbers.Clear();

        //в случае выбора "Любой"
        if (selectedId == 0)
        {
            _bsNumbers.Add(new ComboItem { Text = "Нет выбора" });
            return;
        }

        await LoadRoomNumbersByTypeIdAsync(selectedId);
    }

    /// <summary>
    /// Заполение комбобкса типов комнат
    /// </summary>
    /// <returns></returns>
    private async Task LoadRoomTypesAsync()
    {
        try
        {
            using (var con = new SqlConnection(_conString))
            using (var cmd = con.CreateCommand())
            {
                cmd.CommandText = @"SELECT Id
                                 , Name
                                FROM RoomTypes
                                ORDER BY Name;";
                await con.OpenAsync();
                using (var reader = await cmd.ExecuteReaderAsync())
                {
                    while (await reader.ReadAsync())
                    {
                        var ci = new ComboItem
                        {
                            Id = reader.GetInt32(0),
                            Text = reader.GetString(1)
                        };
                        _bsTypes.Add(ci);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Ошибка",
                MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    /// <summary>
    /// Заполнение комбобокса номерами комнат нужного типа
    /// </summary>
    /// <param name="typeId"></param>
    /// <returns></returns>
    private async Task LoadRoomNumbersByTypeIdAsync(int typeId)
    {
        try
        {
            using (var con = new SqlConnection(_conString))
            using (var cmd = con.CreateCommand())
            {
                cmd.CommandText = @"SELECT r.Id, r.Number
                                    FROM dbo.Rooms AS r
                                    INNER JOIN dbo.RoomTypes AS t
                                        ON r.RoomTypeId = t.Id
                                    WHERE ReservationId = 0 AND t.Id = @id
                                    ORDER BY Number;";

                var param = new SqlParameter();
                param.ParameterName = "@id";
                param.SqlDbType = SqlDbType.Int;
                param.Value = typeId;
                cmd.Parameters.Add(param);

                await con.OpenAsync();
                using (var reader = await cmd.ExecuteReaderAsync())
                {
                    //если есть свободные комнаты данного типа
                    if (reader.HasRows)
                    {
                        while (await reader.ReadAsync())
                        {
                            var ci = new ComboItem
                            {
                                Id = reader.GetInt32(0),
                                Text = reader.GetInt32(1).ToString()
                            };
                            _bsNumbers.Add(ci);
                        }
                    }
                    else
                    {
                        //иначе нет свободных комнат
                        _bsNumbers.Add(new ComboItem { Text = "Нет свободных" });
                    }
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Ошибка",
                MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}

Ну, и в-третьих, в качестве пожелания, код работы с БД должен быть вынесен в отдельный класс, т.к. нужно отделять работу с визуальным интерфейсом и работу со слоем хранения. Так что задумайтесь об этом. Это на будущее, так сказать.

Весь код здесь.

→ Ссылка