- •Введение
- •1 ИНФОЛОГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ БАЗЫ ДАННЫХ
- •1.2 Концептуальная модель данных
- •2 ДАТОЛОГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ БД
- •2.1 Логическое проектирование
- •2.2 Физическое проектирование
- •2.2.1 Создание базы данных в СУБД PostgreSQL
- •2.2.2 Вопросы безопасности данных
- •3 ОПИСАНИЕ ПРИКЛАДНОЙ ПРОГРАММЫ
- •3.1 Создание функций для работы прикладной программы
- •3.2 Внешний вид и описание работы программы
- •3.3 Поиск и манипулирование данными
- •Заключение
- •Список использованных источников
Заключение
В результате выполнения курсовой работы выполнено проектирование инфологической модели данных с последующим проектированием логической модели данных, с результатом в виде построения модели IDEF0, её декомпозиции, концептуальной модели «Сущность-связь» и логической модели IDEF1X с глоссарием атрибутов; завершено физическое проектирование базы данных и обеспечение её безопасности, результатом чего стала реализованная база данных в PostgreSQL с созданными таблицами, ограничениями, ролевой моделью доступа и механизмом защиты на уровне строк (RLS); развиты компетенции по разработке прикладной программы с пользовательским интерфейсом для взаимодействия с созданной системой, результатом чего явилось оконное приложение на C# с графическим интерфейсом. Таким образом, цель курсовой работы достигнута, все поставленные задачи реализованы в полном объеме, что подтверждает получение практических навыков в области проектирования, реализации и защиты систем баз данных.
57
Список использованных источников
1.Образовательный стандарт вуза ОС ТУСУР 01-2021 [Электронный ресурс]: сайт ТУСУРа. URL: https://regulations.tusur.ru/documents/70 (дата обращения: 30.12.2025);
2.Курс «Безопасность систем баз данных» [Электронный ресурс]: сайт Система дистанционного обучения ТУСУРа URL: https://sdo.tusur.ru/course/view.php?id=2121 (дата обращения: 21.10.2025);
3.Документация к PostgreSQL 18.1 PostgresPro [Электронный ресурс]: Официальная документация PostgreSQL URL: https://postgrespro.ru/docs/postgresql/current (дата обращения: 15.11.2025)
58
Приложение А
(обязательное)
Запрос на создание базы данных, таблиц и ограничений к ним
CREATE DATABASE hoteldb;
CREATE TABLE hotel_room (
room int primary key check(room > 0),
room_type varchar(11) check (room_type = 'одноместный' or room_type = 'двухместный'), one_night_cost numeric check(one_night_cost >= 0) not null,
room_description varchar(200) );
CREATE TABLE manager (
manager_id serial primary key check (manager_id > 0),
manager_surname varchar(50) check(manager_surname ~ '^[А-Яа-я]+(-[А-Яа-я]+)*$') not null, manager_name varchar(50) check(manager_name ~ '^^[А-Я][а-я]*(-[А-Я][а-я]*)*$') not null, manager_patronymic varchar(50) check(manager_patronymic ~ '^[А-Я][а-я]*(-[А-Я][а-я]*)*$'), experience int check (experience >= 0),
date_of_birth date,
gender varchar(7) check (gender = 'мужской' or gender = 'женский'),
phone_number varchar(20) unique check(phone_number ~ '^\+7\(\d{3}\)\d{3}-\d{2}-\d{2}$'), email varchar(255) unique check(email like '%@%.%')
);
CREATE TABLE guest (
guest_id serial primary key check (guest_id > 0),
guest_surname varchar(50) check(guest_surname ~ '^[А-Яа-я]+(-[А-Яа-я]+)*$') not null, guest_name varchar(50) check(guest_name ~ '^[А-Я][а-я]*(-[А-Я][а-я]*)*$') not null, guest_patronymic varchar(50) check(guest_patronymic ~ '^[А-Я][а-я]*(-[А-Я][а-я]*)*$'), document_type varchar(13) check (document_type = 'паспорт' or document_type = 'загранпаспорт' or document_type = 'свидетельство'),
document_series varchar(6) not null, document_number varchar(7) not null, date_of_birth date not null,
59
gender varchar(7) check (gender = 'мужской' or gender = 'женский'),
phone_number varchar(20) unique check(phone_number ~ '^\+7\(\d{3}\)\d{3}-\d{2}-\d{2}$'), email varchar(255) unique check(email like '%@%.%')
);
CREATE TABLE request (
request_id serial primary key check (request_id > 0), room int references hotel_room(room) on delete cascade,
manager_id int references manager(manager_id) on delete cascade, guest_id int references guest(guest_id) on delete cascade, guest_quantity int check(guest_quantity > 0),
check_in_date date not null, check_out_date date not null, check(check_out_date > check_in_date), total_cost numeric check(total_cost >= 0) );
CREATE TABLE check_in (
guest_id int references guest(guest_id) on delete cascade, request_id int references request(request_id) on delete cascade );
60
Приложение Б
(обязательное)
Триггер для гостя, подающего заявку
CREATE OR REPLACE FUNCTION check_request_main_guest_adult() RETURNS TRIGGER AS $$
DECLARE guest_age int;
BEGIN
SELECT EXTRACT(YEAR FROMAGE(date_of_birth)) INTO guest_age
FROM guest
WHERE guest_id = NEW.guest_id;
IF guest_age < 18 THEN
RAISE EXCEPTION 'Гость, подающий заявку, должен быть старше 18 лет.'; END IF;
RETURN NEW; END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_check_request_main_guest_adult BEFORE INSERT OR UPDATE ON request
FOR EACH ROW EXECUTE FUNCTION check_request_main_guest_adult(); FOR EACH ROW EXECUTE FUNCTION check_request_guest_adult();
61
Приложение В
(обязательное)
Ограничение не дающее заселить гостя в занятую комнату
CREATE EXTENSION IF NOT EXISTS btree_gist;
ALTER TABLE request ADD EXCLUDE USING gist (
room WITH =,
daterange(check_in_date, check_out_date, '[)') WITH &&
);
62
Приложение Г
(обязательное)
Заполнение таблиц
insert into hotel_room values
(201, 'одноместный', 2000,'Кондиционер, Туалетные принадлежности, Минибар, Доступ к
WIFI'),
(202, 'одноместный', 2500,'Кондиционер, Телевизор, Туалетные принадлежности, Минибар, Доступ к WIFI'),
(203, 'двухместный', 2600,'Кондиционер, Туалетные принадлежности, Минибар, Доступ к
WIFI'),
(204, 'двухместный', 3000,'Кондиционер, Телевизор, Туалетные принадлежности, Минибар, Доступ к WIFI'),
(205, 'двухместный', 3400,'Кондиционер, Телевизор, Туалетные принадлежности, Сейф, Минибар, Доступ к WIFI');
insert into manager values
(default, 'xxxxxxxx', 'xxxxxxxx', 'xxxxxxxxxxxx', 2, '20000531', 'женский', '+7(999)999-99-97', 'coolxxxxxxx@mail.com'),
(default, 'yyyyyy', 'yyyyyy', 'yyyyyyyyyyyyy', 2, '20001212', 'женский', '+7(999)999-99-98', 'coolyyyyyyyy@mail.com'),
(default, 'zzzzzzz', 'zzzzzzz', 'zzzzzzzzzzzzzzzzzz', 2, '20000712', 'мужской', '+7(999)999-99-99', 'belzzzzzzz@mail.com'),
(default, 'wwwwww', 'wwww', 'wwwwwwwww', 2, '20000222', 'мужской', '+7(999)999-99-09', 'wwwwww@mail.com'),
(default, 'qqqqqqq', 'qqqqqqqq', 'qqqqqqqqqqqqq', 2, '20000227', 'мужской', '+7(999)999-99-19', 'qqqqqqqq@mail.com');
select * from manager;
insert into guest values
(default, 'eeeeeee', 'eeeeeeee', ' eeeeeeeeeeee', 'паспорт', '0000', '123456', '20000408', 'женский', '+7(999)999-99-90', 'eeeeeeee@mail.com'),
(default, 'rrrrrrrr', 'rrrrrrrrr', 'rrrrrrrrrrrrrrrrrrrr', 'паспорт', '0000', '123456', '20000823', 'мужской', '+7(999)999-99-91', 'rrrrr52@mail.com'),
63
(default, 'ttttt', 'tttttt', 'tttttttttttttttttttttttttt', 'загранпаспорт', '00', '1234567', '20000207', 'мужской', '+7(999)999-99-92', 'bradok@mail.com'),
(default, 'uuuuu', 'uuuuuuu', 'uuuuuuuu', 'загранпаспорт', '00', '1234567', '20000703', 'мужской', '+7(999)999-99-93', 'uuuuuu@mail.com'),
(default, 'iiiiiiiiiiii', 'iiiiiiiii', 'iiiiiiiiiiiiiiiiiiiiiiii', 'паспорт', '0000', '123456', '20001020', 'женский', '+7(999)999-99-94', 'ribbitribbit@mail.com'),
(default, 'oooooooooo', 'oooooo', 'oooooo', 'свидетельство', 'II', '123456', '20090529', 'мужской', '+7(999)999-99-95', 'glazapolzet@mail.com'),
(default, 'ppppppp', 'pppppp', 'pppppppp', 'свидетельство', 'IV', '123456', '20090928', 'мужской', '+7(999)999-99-96', 'aetokto@mail.com');
insert into request values
(default, 201, 3, 1, 1, '20250228', '20250302', 2000 * 3), (default, 202, 4, 5, 1, '20250328', '20250330', 2500 * 3), (default, 203, 5, 2, 2, '20250428', '20250430', 2600 * 3), (default, 204, 2, 4, 2, '20250528', '20250530', 3000 * 3), (default, 205, 1, 3, 2, '20250628', '20250630', 2600 * 3);
insert into check_in values (1,1), (5,1), (2,3), (6,3), (4,4), (7,4), (3,5), (5,5);
64
Приложение Д
(обязательное)
Создание ролей БД и выдача прав
create role manager;
grant select on hotel_room to manager; grant select on manager to manager;
grant select, insert, update on guest to manager; grant select, insert, update on request to manager; grant select, insert, update on check_in to manager;
grant usage on all sequences in schema public to manager;
create role guest;
grant select on hotel_room to guest;
grant select (manager_surname, manager_name, phone_number) on manager to guest; grant select, insert, update on guest to guest;
grant select (guest_id, manager_id, room, guest_quantity, check_in_date, check_out_date, total_cost) on request to guest;
grant insert (guest_id, room, guest_quantity, check_in_date, check_out_date) on request to guest; grant usage on all sequences in schema public to guest;
create role dbadmin;
grant select, insert, update, delete on hotel_room to dbadmin; grant select, insert, update, delete on manager to dbadmin; grant select, insert, update, delete on guest to dbadmin; grant select, insert, update, delete on request to dbadmin; grant select, insert, update, delete on check_in to dbadmin; grant usage on all sequences in schema public to dbadmin;
65
Приложение Е
(обязательное)
Создание пользователей БД и присваивание ролей
create user "XXXXXXXXXX" with password '1234567890'; grant manager to "XXXXXXXXXX";
create user guest1 with password '1234567890'; grant guest to guest1;
create user "DB_ADMIN" with password '1234567890'; grant dbadmin to "DB_ADMIN";
66
Приложение Ж
(обязательное)
Включение RLS и создание политик
ALTER TABLE guest ENABLE ROW LEVEL SECURITY;
CREATE POLICY guest_select_own ON guest
FOR SELECT TO guest
USING (current_user = 'guest' || guest_id::text);
CREATE POLICY guest_insert_own ON guest FOR INSERT TO guest
WITH CHECK (current_user = 'guest' || guest_id::text);
CREATE POLICY guest_update_own ON guest FOR UPDATE TO guest
USING (current_user = 'guest' || guest_id::text) WITH CHECK (current_user = 'guest' || guest_id::text);
CREATE POLICY guest_select_request ON request
FOR SELECT TO guest
USING (current_user = 'guest' || guest_id::text);
CREATE POLICY guest_insert_request ON request FOR INSERT TO guest
WITH CHECK (current_user = 'guest' || guest_id::text);
CREATE POLICY guest_select_manager ON manager FOR SELECT TO guest
USING ( EXISTS (
SELECT 1 FROM request r
WHERE r.manager_id = manager.manager_id
67
AND r.guest_id = CAST(SUBSTRING(current_user, 6) AS INTEGER)
)
);
68
Приложение И
(обязательное)
Функции СУБД
CREATE OR REPLACE FUNCTION get_all_rooms() RETURNS TABLE (
room INT, room_type TEXT,
one_night_cost NUMERIC, room_description TEXT
)
LANGUAGE sql AS $$
SELECT room, room_type, one_night_cost, room_description FROM hotel_room;
$$;
CREATE OR REPLACE FUNCTION get_room_numbers() RETURNS SETOF integer
LANGUAGE sql AS $$
SELECT DISTINCT room FROM hotel_room ORDER BY room;
$$;
CREATE OR REPLACE FUNCTION create_request( p_room INTEGER,
p_guest_id INTEGER, p_guest_quantity INTEGER,
p_check_in_date TIMESTAMP WITHOUT TIME ZONE, p_check_out_date TIMESTAMP WITHOUT TIME ZONE
)
RETURNS VOID
69
LANGUAGE sql AS $$
INSERT INTO request ( room,
guest_id, guest_quantity, check_in_date, check_out_date
) VALUES ( p_room, p_guest_id, p_guest_quantity,
p_check_in_date::DATE, p_check_out_date::DATE
); $$;
CREATE OR REPLACE FUNCTION get_guest_data(p_guest_id INTEGER) RETURNS TABLE (
guest_surname TEXT, guest_name TEXT, guest_patronymic TEXT, document_series TEXT, document_number TEXT, phone_number TEXT, email TEXT, date_of_birth DATE
)
LANGUAGE sql AS $$
SELECT guest_surname, guest_name, guest_patronymic,
70
document_series, document_number, phone_number, email, date_of_birth
FROM guest
WHERE guest_id = p_guest_id; $$;
CREATE OR REPLACE FUNCTION update_guest_data(
p_guest_id |
INTEGER, |
|
p_surname |
TEXT, |
|
p_name |
TEXT, |
|
p_patronymic |
TEXT, |
|
p_document_series TEXT, |
||
p_document_number TEXT, |
||
p_phone_number |
TEXT, |
|
p_email |
TEXT |
|
) |
|
|
RETURNS BOOLEAN |
||
LANGUAGE plpgsql |
|
|
AS $$ |
|
|
DECLARE |
|
|
updated_rows INT; |
|
|
BEGIN |
|
|
UPDATE guest |
|
|
SET |
|
|
guest_surname |
= p_surname, |
|
guest_name |
= p_name, |
|
guest_patronymic |
= p_patronymic, |
|
document_series |
= p_document_series, |
|
document_number = p_document_number, |
||
phone_number |
= p_phone_number, |
|
= p_email |
||
71
WHERE guest_id = p_guest_id;
GET DIAGNOSTICS updated_rows = ROW_COUNT;
RETURN updated_rows > 0; END;
$$;
CREATE OR REPLACE FUNCTION get_user_requests(p_guest_id INTEGER) RETURNS TABLE (
request_number BIGINT, manager_full_name TEXT, manager_phone TEXT, room INTEGER, guest_quantity INTEGER, check_in_date DATE, check_out_date DATE, total_cost NUMERIC
)
LANGUAGE sql AS $$
SELECT
ROW_NUMBER() OVER (ORDER BY r.check_in_date, r.room)AS request_number, COALESCE(m.manager_surname || ' ' || m.manager_name, 'Не назначен') AS
manager_full_name,
COALESCE(m.phone_number, '')AS manager_phone, r.room,
r.guest_quantity, r.check_in_date, r.check_out_date,
COALESCE(r.total_cost, 0)AS total_cost FROM request r
LEFT JOIN manager m ON r.manager_id = m.manager_id WHERE r.guest_id = p_guest_id
72
ORDER BY r.check_in_date, r.room; $$;
73
Приложение К
(обязательное)
Класс DatabaseFunctions
public class DatabaseFunctions
{
private static string? dbUsername; private static string? dbPassword;
public static void SetCredentials(string username, string password)
{
dbUsername = username; dbPassword = password;
}
// Параметры подключения к PostgreSQL private static string GetConnectionString()
{
string username = dbUsername ?? "guest1"; string password = dbPassword ?? "1234567890";
string connectionString = $"Host=localhost;Port=5433;Database=hoteldb;Username={username};Password={password};SSL Mode=Prefer;Timeout=10;";
return connectionString;
}
// Параметры подключения для регистрации private static string GetRegistrationConnectionString()
{
string connectionString = "Host=localhost;Port=5433;Database=hoteldb;Username=postgres;Password=1234567890;SSL Mode=Prefer;Timeout=10;";
return connectionString;
}
74
// Проверка подключения
public static (bool Success, string ErrorMessage) TestConnection()
{
try
{
using (var conn = new NpgsqlConnection(GetConnectionString()))
{
conn.Open();
return (true, string.Empty);
}
}
catch (NpgsqlException ex)
{
return (false, $"Ошибка PostgreSQL: {ex.Message}\nКод ошибки:
{ex.SqlState}");
}
catch (Exception ex)
{
return (false, $"Ошибка: {ex.Message}\nТип: {ex.GetType().Name}");
}
}
// Получение ID гостя по имени пользователя
public static (bool Success, int? GuestId, string ErrorMessage) GetGuestIdByUsername()
{
try
{
string? currentUser = dbUsername;
if (string.IsNullOrEmpty(currentUser))
{
using (var conn = new NpgsqlConnection(GetConnectionString()))
{
conn.Open();
using var cmd = new NpgsqlCommand("SELECT
current_user", conn);
75
var result = cmd.ExecuteScalar(); currentUser = result?.ToString();
}
}
if (string.IsNullOrEmpty(currentUser))
{
return (false, null, "Имя пользователя не задано.");
}
if (!currentUser.StartsWith("guest", StringComparison.OrdinalIgnoreCase))
{
return (false, null, $"Имя пользователя '{currentUser}' не соответствует ожидаемому формату 'guestN'.");
}
string numberPart = currentUser.Substring(5);
if (int.TryParse(numberPart, out int guestId) && guestId > 0)
{
return (true, guestId, string.Empty);
}
else
{
return (false, null, $"Невозможно извлечь корректный ID гостя из имени пользователя '{currentUser}'. Ожидалось 'guest' + положительное целое число.");
}
}
catch (NpgsqlException ex)
{
return (false, null, $"Ошибка PostgreSQL: {ex.Message}");
}
catch (Exception ex)
{
return (false, null, $"Ошибка: {ex.Message}");
}
76
}
// Вывод таблицы с гостиничными номерами public static void GetAllRooms(DataGridView dgv)
{
try
{
using (var conn = new NpgsqlConnection(GetConnectionString()))
{
conn.Open();
var cmd = new NpgsqlCommand("SELECT * FROM
get_all_rooms()", conn);
using (var reader = cmd.ExecuteReader())
{
var dataTable = new DataTable(); dataTable.Load(reader);
if (dataTable.Rows.Count == 0)
{
MessageBox.Show("В таблице гостиничных номеров нет данных", "Информация", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
dgv.DataSource = null; dgv.Rows.Clear();
dgv.DataSource = dataTable;
foreach (DataGridViewColumn column in
dgv.Columns)
{
if (column.DataPropertyName ==
"room_description" ||
77
(column.Name == "Column4" &&
column.HeaderText == "Описание"))
{
column.AutoSizeMode =
DataGridViewAutoSizeColumnMode.AllCells;
break;
}
}
}
}
}
}
catch (NpgsqlException ex)
{
string detailedError = $"Ошибка PostgreSQL:\n{ex.Message}"; if (!string.IsNullOrEmpty(ex.SqlState))
{
detailedError += $"\nКод ошибки SQL: {ex.SqlState}";
}
MessageBox.Show(detailedError, "Ошибка БД", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка: {ex.Message}\n\nТип ошибки: {ex.GetType().Name}\n\nДетали: {ex.StackTrace}",
"Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// Вывод списка комнат
public static List<int> GetRoomNumbers()
{
var roomNumbers = new List<int>(); try
78
{
using (var conn = new NpgsqlConnection(GetConnectionString()))
{
conn.Open();
var cmd = new NpgsqlCommand("SELECT * FROM
get_room_numbers()", conn);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
if (!reader.IsDBNull(0))
{
roomNumbers.Add(reader.GetInt32(0));
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при загрузке номеров: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return roomNumbers;
}
// Создание новой заявки
public static bool CreateRequest(int roomNumber, int guestQuantity, DateTime checkInDate, DateTime checkOutDate, int guestId)
{
try
{
using (var conn = new NpgsqlConnection(GetConnectionString()))
{
conn.Open();
79
var cmd = new NpgsqlCommand("SELECT create_request(@room, @guest_id, @guest_quantity, @check_in_date, @check_out_date)", conn);
cmd.Parameters.AddWithValue("@room", roomNumber); cmd.Parameters.AddWithValue("@guest_id", guestId); cmd.Parameters.AddWithValue("@guest_quantity", guestQuantity); cmd.Parameters.AddWithValue("@check_in_date",
checkInDate.Date);
cmd.Parameters.AddWithValue("@check_out_date",
checkOutDate.Date);
cmd.ExecuteNonQuery(); return true;
}
}
catch (NpgsqlException ex)
{
string errorDetails = $"Ошибка PostgreSQL:\n{ex.Message}"; if (!string.IsNullOrEmpty(ex.SqlState))
{
errorDetails += $"\nКод ошибки SQL: {ex.SqlState}";
}
MessageBox.Show(errorDetails, "Ошибка БД", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
} |
|
|
catch (Exception ex) |
|
|
{ |
|
|
MessageBox.Show($"Ошибка: |
{ex.Message}", |
"Ошибка", |
MessageBoxButtons.OK, MessageBoxIcon.Error); |
|
|
return false; |
|
|
} |
|
|
} |
|
|
80
// Вывод информации о госте
public static (bool Success, GuestData Data, string ErrorMessage) GetGuestData(int guestId)
{
try
{
using (var conn = new NpgsqlConnection(GetConnectionString()))
{
conn.Open();
var cmd = new NpgsqlCommand("SELECT * FROM get_guest_data(@guest_id)", conn);
cmd.Parameters.AddWithValue("@guest_id", guestId);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
var data = new GuestData
{
Surname = reader.IsDBNull(0) ? string.Empty :
reader.GetString(0),
Name = reader.IsDBNull(1) ? string.Empty :
reader.GetString(1),
Patronymic = reader.IsDBNull(2) ?
string.Empty : reader.GetString(2),
DocumentSeries = reader.IsDBNull(3) ?
string.Empty : reader.GetString(3),
DocumentNumber = reader.IsDBNull(4) ?
string.Empty : reader.GetString(4),
PhoneNumber = reader.IsDBNull(5) ?
string.Empty : reader.GetString(5),
Email = reader.IsDBNull(6) ? string.Empty :
reader.GetString(6),
BirthDate = reader.IsDBNull(7) ?
(DateTime?)null : reader.GetDateTime(7)
};
81
return (true, data, string.Empty);
}
else
{
return (false, null, "Гость с указанным ID не
найден.");
}
}
}
}
catch (NpgsqlException ex)
{
return (false, null, $"Ошибка PostgreSQL: {ex.Message}");
}
catch (Exception ex)
{
return (false, null, $"Ошибка: {ex.Message}");
}
}
// Изменение информации о госте
public static bool UpdateGuestData(int guestId, string surname, string name, string patronymic, string documentSeries, string documentNumber, string phoneNumber, string email)
{
try
{
using (var conn = new NpgsqlConnection(GetConnectionString()))
{
conn.Open();
var cmd = new NpgsqlCommand("SELECT update_guest_data(@guest_id, @surname, @name, @patronymic, @document_series, @document_number, @phone_number, @email)",conn);
cmd.Parameters.AddWithValue("@guest_id", guestId);
82
cmd.Parameters.AddWithValue("@surname", (object)surname ??
DBNull.Value);
cmd.Parameters.AddWithValue("@name", (object)name ??
DBNull.Value);
cmd.Parameters.AddWithValue("@patronymic", (object)patronymic
?? DBNull.Value);
cmd.Parameters.AddWithValue("@document_series", (object)documentSeries ?? DBNull.Value);
cmd.Parameters.AddWithValue("@document_number", (object)documentNumber ?? DBNull.Value);
cmd.Parameters.AddWithValue("@phone_number", (object)phoneNumber ?? DBNull.Value);
cmd.Parameters.AddWithValue("@email", (object)email ??
DBNull.Value);
bool success = (bool)cmd.ExecuteScalar(); return success;
}
}
catch (NpgsqlException ex)
{
string errorDetails = $"Ошибка PostgreSQL:\n{ex.Message}"; if (!string.IsNullOrEmpty(ex.SqlState))
{
errorDetails += $"\nКод ошибки SQL: {ex.SqlState}";
}
MessageBox.Show(errorDetails, "Ошибка БД", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
} |
|
|
catch (Exception ex) |
|
|
{ |
|
|
MessageBox.Show($"Ошибка: |
{ex.Message}", |
"Ошибка", |
MessageBoxButtons.OK, MessageBoxIcon.Error); |
|
|
return false; |
|
|
83
}
}
// Регистрация нового гостя
public static (bool Success, int? GuestId, string Username, string ErrorMessage) RegisterNewGuest(string surname, string name, string? patronymic, string gender, string documentSeries, string documentNumber, DateTime birthDate, string? phoneNumber, string? email)
{
try
{
string documentType;
if (documentSeries.Length == 4 && int.TryParse(documentSeries, out _) && documentNumber.Length == 6 && int.TryParse(documentNumber,
out _))
{
documentType = "паспорт";
}
else if (documentSeries.Length == 2 && int.TryParse(documentSeries, out _)
&&
documentNumber.Length |
== |
7 |
&& |
int.TryParse(documentNumber, out _))
{
documentType = "загранпаспорт";
}
else
{
return (false, null, string.Empty, "Неверный формат серии или
номера документа");
}
using var conn = new NpgsqlConnection(GetRegistrationConnectionString()); conn.Open();
using var cmd = new NpgsqlCommand("SELECT * FROM register_guest(@surname, @name, @patronymic, @gender, @doc_type, @doc_series, @doc_number, @birth_date, @phone, @email)", conn);
84
cmd.Parameters.Add("@surname", NpgsqlDbType.Text).Value = surname; cmd.Parameters.Add("@name", NpgsqlDbType.Text).Value = name; cmd.Parameters.Add("@patronymic", NpgsqlDbType.Text).Value =
patronymic ?? (object)DBNull.Value;
cmd.Parameters.Add("@gender", NpgsqlDbType.Text).Value = gender; cmd.Parameters.Add("@doc_type", NpgsqlDbType.Text).Value =
documentType;
cmd.Parameters.Add("@doc_series", NpgsqlDbType.Text).Value =
documentSeries;
cmd.Parameters.Add("@doc_number", NpgsqlDbType.Text).Value =
documentNumber;
cmd.Parameters.Add("@birth_date", NpgsqlDbType.Date).Value =
birthDate.Date;
cmd.Parameters.Add("@phone", NpgsqlDbType.Text).Value = phoneNumber ?? (object)DBNull.Value;
cmd.Parameters.Add("@email", NpgsqlDbType.Text).Value = email ??
(object)DBNull.Value;
using var reader = cmd.ExecuteReader(); if (reader.Read())
{
bool success = reader.GetBoolean(0);
int? guestId = reader.IsDBNull(1) ? null : reader.GetInt32(1);
string username = reader.IsDBNull(2) ? string.Empty :
reader.GetString(2);
string errorMsg = reader.IsDBNull(3) ? string.Empty :
reader.GetString(3);
return (success, guestId, username, errorMsg);
}
return (false, null, string.Empty, "Функция register_guest не вернула
результат");
}
catch (Exception ex)
85
{
return (false, null, string.Empty, $"Ошибка при вызове register_guest:
{ex.Message}");
}
}
// Вывод заявок гостя
public static void GetUserRequests(DataGridView dgv, int guestId)
{
try
{
using (var conn = new NpgsqlConnection(GetConnectionString()))
{
conn.Open();
var cmd = new NpgsqlCommand("SELECT * FROM get_user_requests(@guest_id)", conn);
cmd.Parameters.AddWithValue("@guest_id", guestId);
var dataTable = new DataTable();
using (var reader = cmd.ExecuteReader())
{
dataTable.Load(reader);
}
dgv.DataSource = null; dgv.Rows.Clear(); dgv.AutoGenerateColumns = false;
if (dgv.Columns.Count >= 8)
{
dgv.Columns[0].DataPropertyName = "request_number"; dgv.Columns[1].DataPropertyName = "manager_full_name"; dgv.Columns[2].DataPropertyName = "manager_phone"; dgv.Columns[3].DataPropertyName = "room"; dgv.Columns[4].DataPropertyName = "guest_quantity";
86
dgv.Columns[5].DataPropertyName = "check_in_date"; dgv.Columns[6].DataPropertyName = "check_out_date"; dgv.Columns[7].DataPropertyName = "total_cost";
dgv.Columns[5].DefaultCellStyle.Format = "dd.MM.yyyy"; dgv.Columns[6].DefaultCellStyle.Format = "dd.MM.yyyy"; dgv.Columns[7].DefaultCellStyle.Format = "N2";
}
dgv.DataSource = dataTable;
if (dataTable.Rows.Count == 0)
{
MessageBox.Show("У вас пока нет заявок", "Информация", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
catch (NpgsqlException ex)
{
string detailedError = $"Ошибка PostgreSQL:\n{ex.Message}"; if (!string.IsNullOrEmpty(ex.SqlState))
{
detailedError += $"\nКод ошибки SQL: {ex.SqlState}";
}
MessageBox.Show(detailedError, "Ошибка БД", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка: {ex.Message}\n\nТип ошибки: {ex.GetType().Name}",
"Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
87
Приложение Л
(обязательное)
Листинг кода программы и руководство
Для запуска системы необходимо установить Microsoft Visual Studio 2026 последней версии и СУБД PostgreSQL 18 с графическим клиентом pgAdmin 4.
Инструкция по установке проекта:
1.Скачать ZIP-файл проекта по ссылке: https://github.com/notmadasmr/hotel_kurs. К проекту также приложен скрипт
«script.sql» для создания базы данных с тестовыми записями в каждой из таблиц. Извлеките файлы из архива.
2.В графическом клиенте pgAdmin 4 откройте сервер PostgreSQL 18 , импортируйте приложенный скрипт и запустите его для создания готовой БД.
3.Запустите файл «kursach_bsbd.slnx» с помощью Microsoft Visual Studio 2026.
88
