본문 바로가기
대한상공회의소 스마트팩토리 교육/데이터베이스

[데이터베이스 운영] DBMS 기초 «수업-6» : 데이터베이스(DB) 연동 프로그래밍 기초 Using C# - ② : GUI 환경 기초

by 나는영하 2022. 4. 28.

※ 주의사항 

본 블로그는 수업 내용을 바탕으로 제가 이해한 부분을 정리한 블로그입니다.
본 내용을 참고로만 보시고, 틀린 부분이 있다면 지적 부탁드립니다!

감사합니다😁

 


데이터베이스(DB) 연동 - GUI


안녕하세요!!

저번에는 CUI(Console User Inteface) 환경에서 데이터베이스(My SQL)을 C#으로 연동해서 DB를 처리하는 과정을 알아보았습니다. 오늘은 GUI(Graphical User Inteface) 환경에서 데이터베이스(My SQL)을 C#으로 연동해서 DB를 처리하는 과정을 알아보겠습니다.

 

코드자체는 지난번과 거의 동일합니다.

지난 데이터베이스를 연동하는 과정이 기억이 안난다면 지난 글을 한번 보고 오는것을 추천드립니다. 

2022.04.27 - [데이터베이스] - [데이터베이스 운영] DBMS 기초 «수업-5» : 데이터베이스(DB) 연동 프로그래밍 기초 Using C#

 

[데이터베이스 운영] DBMS 기초 «수업-5» : 데이터베이스(DB) 연동 프로그래밍 기초 Using C# - ① : CUI

※ 주의사항 ※ 본 블로그는 수업 내용을 바탕으로 제가 이해한 부분을 정리한 블로그입니다. 본 내용을 참고로만 보시고, 틀린 부분이 있다면 지적 부탁드립니다! 감사합니다😁 데이터베이스

920416.tistory.com

 

오늘은 윈도우 폼(Windows Form)을 사용하기 때문에 좀 더 디테일하면서 사용자 편의성이 뛰어나다는 장점이 있습니다. 본 교육은 SQL Server로 진행하였지만 복습은 My SQL로 진행하였습니다.

 

 

1. 기본 설정 (폼 및 데이터베이스 연결) 

✔ 당연히 지난시간에 배운 NuGET 패키지 관리에서 MySqlConnector를 설치해주셔야 합니다!!

1-1. 직원 데이터베이스 입력 폼 작성

(좌) 실습용 Win Form 제작 / (우) 실습용 데이터베이스 employees 테이블

My SQL employees 데이터베이스의 employees 테이블을 가지고 실습을 진행해보고자 합니다.

따라서 해당 테이블의 열에 해당하는 데이터들을 가지고 가공하기위해 위와같은 Windows Form을 만들어 보았습니다. WinForm 제작은 지난 Image Processing 프로젝트를 통해 많이 배웠기 때문에 과정은 생략하겠습니다. 각 구성 요소에 대한 명칭은 빨간글씨와 같으니 추후 코드를 확인하실때 참고 바랍니다!!!

 

각 열에대한 데이터 타입 확인

DESC employees를 통해 각 열에대한 데이터타입을 알아보았습니다.

 


1-2. 데이터베이스 연결을 위한 기본 코드 작성

먼저 데이터베이스 연결을 하기위해 필요한 변수들을 전역변수로 선언하겠습니다.

// 전역 변수부
String connStr = "Server = 192.168.56.101; Uid = smartUSER; Pwd = 1234, Database = employees, Charset = UTF8"; // 연결 문자열
MySqlConnection conn; // 연결자(교량) 
MySqlCommand cmd; // 쿼리문을 보낼 트럭
String sql; // SQL문

 

해당 폼이 열릴때 데이터베이스를 자동으로 연결하고, 해당 폼이 닫히면 자동으로 데이터베이스 연결을 끊도록 하기 위해 Form1_Load 이벤트와 Form1_FormClosed 이벤트를 사용하겠습니다. 

 

먼저 Main Form이 열리면 데이터베이스를 연결하고 쿼리문을 보낼 Command를 준비하겠습니다.

 

다음은 Main Form이 닫히면 데이터베이스와의 연결을 해제하고 특정한 메세지 박스를 출력하겠습니다.

 

1단계와 4단계는 데이터베이스를 입력하든, 수정 또는 조회를하든 변하지 않는 부분입니다.

하지만 아래와 같이 3단계는 상황에 따라 코드가 달라져야 하기 때문에 각기 다른 네개의 버튼 이벤트들로 구성하겠습니다.

3단계에 해당하는 코드!!!

3단계에 해당하는 코드는 TextLabel에 입력된 Text 값을 받아서 변수에 저장하고 쿼리문으로 구성하여 전송하는 방식으로 구성할 예정입니다. 코드는 지난시간을 통해 익숙해졌으니 GUI환경적인 측면에서 보면 더 좋을 것 같습니다. 


2. 데이터베이스 입력 / 수정 / 삭제

2-1. 데이터베이스 입력

직원 등록창에서 직원 데이터를 입력하고 "입력" 버튼을 클릭하면 발생하는 이벤트를 통해 MySQL DB에 데이터를 입력하도록 하겠습니다.

 

(1) 먼저 쿼리문에 사용될 데이터 값(TextBox.Text)들을 저장할 변수를 선언하고 변수에 값들을 저장하는 과정입니다.

// 먼저 SQL문에 넣을 값(TextBox의 Text)들을 변수에 저장하기
String emp_no, birth_date, first_name, last_name, gender, hire_date;

emp_no = tb_emp_no.Text.ToString();
birth_date = tb_birth_date.Text.ToString();
first_name = tb_first_name.Text.ToString();
last_name = tb_last_name.Text.ToString();
gender = tb_gender.Text.ToString();            
hire_date = DateTime.Today.ToString("yyyyMMdd"); // 시스템의 현재 날짜와 시간을 받아서 문자열 변환

포인트로 확인해야할 점은 두가지가 있습니다.

1. TextBox에 입력하는 모든 것은 문자열로 변환해서 보냅니다. (ex. tb_first_name.Text.ToString();)

2. hire_date는 DB를 입력할때의 시스템 시간을 실시간으로 저장서 보내는데, DB상에 hire_date는 '년,월,일'만 저장되어있기 때문에 문자열로 변환할때 이와 동일하게 변환해줬습니다. (MM만 대문자인 이유는 소문자 엠(mm)은 날짜의 '월'이 아닌 시간의 '분'을 나타내기 때문입니다.) 

 

(2) 위에서 준비한 변수를 토대로 쿼리문을 작성합니다.

// 3-1. SQL문 준비하기
sql = "INSERT INTO employees(emp_no, birth_date, first_name, last_name, gender, hire_date) VALUES ('" + emp_no + "' , '" + birth_date;
sql += "','" + first_name + "','" + last_name + "' , '" + gender + "','"+ hire_date + "')";

큰따옴표와 작은따옴표가 반복되는데 많이 틀리는 부분이니 유의깊게 봐야합니다. 

특히 변수의 양옆에는 플러스(+)와 큰따옴표가 먼저 오게됩니다. 쿼리문에서의 큰따옴표의 역할은 작은따옴표가 하기 때문에 잘 구분지어서 확인 바랍니다 ^^;

 

(3) 위의 과정에서 만든 쿼리문을 Command에 실어서 보내도록 하겠습니다. 

// 3-2. SQL문을 트럭에(C0MMAND) 싣기
cmd.CommandText = sql;
// 3-3. 트럭이 교량을 건너서 부어 넣기
cmd.ExecuteNonQuery();

 

(4) 마지막으로 사용자 편의를 위해 입력이 끝나면 자동으로 TextBox를 비우도록 하겠습니다.

tb_emp_no.Text = tb_birth_date.Text = tb_first_name.Text = tb_last_name.Text = tb_gender.Text = " ";

✔ "2-1. 데이터베이스 입력"만 코드를 구분지어서 설명했습니다. 수정 및 삭제는 비슷하기때문에 코드 전문을 첨부해서 설명하도록 하겠습니다.

 

(5) 결과

(좌) 입력 전 테이블 / (중) DB 입력 Form / (우) 입력 후 테이블

Form을 통해 사용자가 입력한 데이터가 정상적으로 DB에 저장된것을 확인 할 수 있습니다!! 


2-2. 데이터베이스 수정

private void btn_update_Click(object sender, EventArgs e)
        {
            // 3단계. 쿼리문을 트럭에 실어서 교량을 건너 목적지에 붓기 --> UPDATE SQL
            // 먼저 SQL문에 넣을 값(TextBox의 Text)들을 변수에 저장하기
            String emp_no, birth_date, first_name, last_name, gender, hire_date;

            emp_no = tb_emp_no.Text.ToString();
            birth_date = tb_birth_date.Text.ToString();
            first_name = tb_first_name.Text.ToString();
            last_name = tb_last_name.Text.ToString();
            gender = tb_gender.Text.ToString();
            hire_date = DateTime.Today.ToString("yyyyMMdd"); // 시스템의 현재 날짜와 시간을 받아서 문자열 변환

            // 3-1. SQL문 준비하기
            sql = "UPDATE employees SET birth_date = '" + birth_date + "', first_name = '" + first_name + "', last_name = '" + last_name;
            sql += "', gender = '" + gender + "', hire_date = '" + hire_date + "' WHERE emp_no = '" + emp_no + "'";
            // 3-2. SQL문을 트럭에(C0MMAND) 싣기
            cmd.CommandText = sql;
            // 3-3. 트럭이 교량을 건너서 부어 넣기
            cmd.ExecuteNonQuery();

            // 입력이 끝나면 자동으로 TextBox를 비우기 
            tb_emp_no.Text = tb_birth_date.Text = tb_first_name.Text = tb_last_name.Text = tb_gender.Text = " ";
        }

sql 변수에 INSERT 쿼리문 대신 UPDATE 쿼리문으로 변경해준것 말고는 데이터베이스 입력과정과 달라진 점이 없습니다. UPDATE는 WHERE절도 나와서 INSERT 보다 쿼리문이 조금더 길고 혼잡하니 참고 바랍니다. WHERE절을 빼고 UPDATE를 하면 모든 DB가 바뀌는 불상사가 발생하니 꼭 WHERE절을 넣어주세요! (WHERE절의 열은 PRIMARY KEY 열로 해주세요!!)

 

(좌) 수정 전 테이블 / (중) DB Form / (우) 수정 후 테이블

3번 LEE YOUNGPYO 데이터가 완벽하게 HAL MONEY 데이터로 바뀌었습니다. 


2-3. 데이터베이스 삭제

private void btn_delete_Click(object sender, EventArgs e)
        {
            // 3단계. 쿼리문을 트럭에 실어서 교량을 건너 목적지에 붓기 --> DELETE SQL
            // 먼저 SQL문에 넣을 값(TextBox의 Text)들을 변수에 저장하기
            String emp_no;
            emp_no = tb_emp_no.Text.ToString();
            // 3-1. SQL문 준비하기
            sql = "DELETE FROM employees WHERE emp_no = '" + emp_no + "'";
            // 3-2. SQL문을 트럭에(C0MMAND) 싣기
            cmd.CommandText = sql;
            // 3-3. 트럭이 교량을 건너서 부어 넣기
            cmd.ExecuteNonQuery();
            MessageBox.Show("SQL 전송이 완료되었습니다.");

            // 입력이 끝나면 자동으로 TextBox를 비우기 
            tb_emp_no.Text = tb_birth_date.Text = tb_first_name.Text = tb_last_name.Text = tb_gender.Text = " ";
        }

삭제는 PRIMARY KEY 열인 직원 번호(emp_no)열만을 WHERE절 변수로 사용해서 삭제하기때문에 더 간단합니다. 삭제가 정상적으로 이루어졌는지 확인하기 위해 삭제가 완료되면 메세지박스를 출력하도록 하였습니다. 

(좌) 삭제 전 테이블 / (중) DB Form / (우) 삭제 후 테이블


3. 데이터베이스 조회

데이터베이스 조회는 입력 / 수정 / 삭제와는 살짝 다릅니다. 기존에는 C#에서 쿼리문을 보내 데이터를 저장했다면 반대로 조회는 C#에서 쿼리문을 보내 DB에서 데이터를 가져와야합니다. 따라서 사용되는 메서드도 다릅니다.

cmd.ExcuteNonQuery --> cmd.ExcuteReader

private void btn_select_Click(object sender, EventArgs e)
        {
            // 3단계. 쿼리문을 트럭에 실어서 교량을 건너 목적지에 붓기 --> SELECT SQL
            // 3-1. SQL문 준비하기
            sql = "SELECT emp_no, birth_date, first_name, last_name, gender, hire_date FROM employees";
            // 3-2. SQL문을 트럭에(C0MMAND) 싣기
            cmd.CommandText = sql;
            // 3-3. 트럭이 교량을 건너서 부어 넣고 끈만 가져오기
            MySqlDataReader reader;
            reader = cmd.ExecuteReader();

            // RichTextBox1에 표시하기 위한 열제목 표시
            String txt = "직원번호 \t 생년월일 \t FirstName \t LastName \t 성별 \t 고용날짜 \n";
            txt += "---------------------------------------------------------------------------------------------------------\n";
            richTextBox1.Text = txt;

            // DB의 데이터를 저장할 변수 선언
            String emp_no, birth_date, first_name, last_name, gender, hire_date;
            
            while (reader.Read()) // DB에 데이터가 안읽힐떄까지 반복
            {   if (ab >1000) break; // 데이터가 너무 많아서 1000개만 가져오기
                emp_no = reader["emp_no"].ToString();

                birth_date = reader["birth_date"].ToString(); 
                DateTime dt1 = Convert.ToDateTime(birth_date); // string 타입 날짜데이터 --> date 타입변환
                birth_date = dt1.ToString("yyyy-MM-dd");// date 타입을 string 타입으로 변환

                first_name = reader["first_name"].ToString();
                last_name = reader["last_name"].ToString();
                gender = reader["gender"].ToString();

                hire_date = reader["hire_date"].ToString();
                DateTime dt2 = Convert.ToDateTime(hire_date);
                hire_date = dt2.ToString("yyyy-MM-dd");

                txt = emp_no.PadRight(20) + birth_date.PadRight(25) + first_name.PadRight(23);
                txt += last_name.PadRight(20)  + gender.PadRight(15)  + hire_date + "\n";
                richTextBox1.Text += txt;
                ab++;
            }
            reader.Close();
        }

저의 코드에서 특이한점은 두가지가 있습니다.

첫째, Date타입의 데이터를 날짜만 표시하기위해 두번의 형변환을 거쳤습니다.

생년월일이나 고용날짜 데이터는 문자열로 들어오게되는데 이를 바로 RichTextBox에 출력을 하면 시간까지 표시가 됩니다. 하지만 우리가 필요한 정보는 '년월일'만 필요하기 때문에 형변환을 두번 거쳐서 작업을 해주어야 합니다. 

 

처음 값을 저장할때는 birth_date = reader["birth_date"].ToString() --> 날짜의 데이터를 가지고 있는 String 타입.

첫번째 형변환 DateTime dt1 = Convert.ToDateTime(birth_date) --> 날짜의 데이터를 가지고 있는 Date 타입

두번째 형변환 birth_date = dt1.Tostring("yyyy-MM-dd") --> yyyy-MM-dd 데이터 형식을 띄는 String 타입

이렇게 형변환이 진행이 됩니다. 다른 더 쉽고 간편한 방법이 있다면 많은 조언 부탁드립니다..ㅠ😥

 

둘째, "\t"를 사용하면 오와열이 흐트러져서 padRight를 사용해서 문자열을 정렬하였습니다.

탭(\t, Tab)을 사용해서 문자열의 간격을 벌려 가독성을 올리려고 하였지만 문자열이 저장된 길이에 따라 벌어지는 간격이 제각각이라 생각했던것과는 다르게 가독성이 많이 떨어졌습니다. 따라서 String.padRight 메서드를 사용해서 현재 문자열의 끝 부분이 공백으로 채워지도록 코딩하였습니다.

 

ex) emp.no.PadRight(20)을 하게 되면 emp.no에 들어가있는데이터가 "10"이라면 "10"이 왼쪽에 정렬되고 나머지 18칸은 공백으로 채워지게 됩니다. 

탭을 사용한 것보다는 많이 정렬됐지만 아직 좀 부족한 모습이 보입니다. 문자열 정렬방법에 대해서는 조금 더 고민이 필요할 것 같습니다.  아래와 같은 방식으로 RichTextBox를 나누는것도 깔끔하고 좋은 방법이 될 것 같습니다.

RichTextBox를 나누면 좀 더 깔끔한 화면 구성이 될 듯 싶다.

 

댓글