Заполнить 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 шт):
Во-первых, типы комнат должны храниться в отдельной таблице, схема такая

Во-вторых, для заполнения комбобоксов нам понадобиться такой класс
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);
}
}
}
Ну, и в-третьих, в качестве пожелания, код работы с БД должен быть вынесен в отдельный класс, т.к. нужно отделять работу с визуальным интерфейсом и работу со слоем хранения. Так что задумайтесь об этом. Это на будущее, так сказать.
Весь код здесь.
