본문 바로가기
Development/.NET

[.NET] C# & WPF MySQL Data Base 연동 🚩 #2

by Kyunghoon Kim 2020. 5. 28.

안녕하세요 이번 시간에는 지난 1편에 이어서 XAML을 이용한 간단한 UI 디자인 후 로직을 구현해 보도록 하겠습니다. 아직 이전 편의 내용을 보고 오시지 않았다면 이전 편을 미리 보고 오시는 것을 추천드립니다.

 

https://devkyunghoon.tistory.com/6

 

🚩 C# & WPF를 이용한 MySQL Data Base 연동 #1

안녕하세요 이번 시간에는 C#과 WPF를 통해 MySQL DataBase를 연동하여 값을 저장하고, 저장한 값을 불러와 일치했는지 아닌지 파악할 수 있도록 해보는 예제를 만들어 보았습니다. 오늘 다룰 예제는

devkyunghoon.tistory.com

 


 

🎄 3.  XAML을 통한 간단한 UI 디자인

 

이제부터 간단하게 XAML로 UI를 디자인 해주도록 하겠습니다. 로그인과 회원가입은 공통으로 Id와 Password를 입력하기 위한 TextBox가 필요할 것이고, 또 로그인 버튼과 회원가입 버튼이 있으면 최소한의 구성은 충족하게 됩니다. 그러면 한번 코드로 간단하게 작성해 볼게요

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<Window x:Class="DB_Linkage.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DB_Linkage"
        mc:Ignorable="d"
        Title="MySQL DB 연동" Height="450" Width="800">
    <Window.Resources>
        <Style TargetType="TextBox" x:Key="tbStyle">
            <Setter Property="Height" Value="30"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
        </Style>
    </Window.Resources>
    
    <Grid>
        <GroupBox x:Name="gdInfo" Header="MySQL DataBase 연동" Margin="10" 
                  Height="300" Width="500">
            <StackPanel Width="200" VerticalAlignment="Center">
                <StackPanel Margin="5">
                    <Label Content="아이디"/>
                    <TextBox x:Name="tbId" Style="{DynamicResource tbStyle}"/>
                </StackPanel>
                <StackPanel Margin="5">
                    <Label Content="비밀번호"/>
                    <TextBox x:Name="tbPw" Style="{DynamicResource tbStyle}"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="5" HorizontalAlignment="Center">
                    <StackPanel.Resources>
                        <Style TargetType="Button">
                            <Setter Property="Background" Value="Transparent"/>
                            <Setter Property="BorderBrush" Value="Transparent"/>
                            <Setter Property="Height" Value="30"/>
                            <Setter Property="Width" Value="70"/>
                        </Style>
                    </StackPanel.Resources>
                    <StackPanel Orientation="Horizontal">
                        <Button Content="회원가입" Margin="5" Click="btnSignUp_Click"/>
                        <Button Content="로그인" Margin="5" Click="btnLogin_Click"/>
                    </StackPanel>
                </StackPanel>
            </StackPanel>
        </GroupBox>
 
        <TextBlock x:Name="tbMsg" Visibility="Collapsed" 
                   Text="메인 페이지 이동" FontSize="50" 
                   VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </Grid>
</Window>
 
cs

 

저는 로그인 & 회원가입을 GroupBox를 통해 묶어 주었고 Label을 통해 아이디와 비밀번호라는 문구를 같이 붙여주었습니다. 그리고 Button 두 개와 로그인 후 나타내 줄 TextBlock을 만들어 두었습니다. 이렇게 작성하고 제작된 UI를 볼까요?

 

UI

 

어떤가요? 사실 아주 기본적인 Control들만으로 구성했기 때문에 그렇게 대단하지는 않습니다. 오늘의 핵심은 DB연동이기에 UI는 크게 중요하지 않습니다. 그러면 이제부터 로직을 짜 봅시다.

 


🎄 4. 로직(Logic) 구현하기

 

이제부터는 코드를 살펴보도록 하겠습니다. 제일 먼저 프로젝트에 폴더 하나를 만들어 주세요. 이곳에 MySQLManager.cs 파일을 만들고 DB와의 연결과 종료, INSERT, SELECT를 할 것입니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using MySql.Data.MySqlClient;
using System.Collections.Generic;
using System.Diagnostics;
 
namespace DB_Linkage.Service
{
    public class MySQLManager
    {
        public void Initialize()
        {
            Debug.WriteLine("DataBase Initialize");
 
            string connectionPath = $"SERVER=localhost;DATABASE=profile;UID=root;PASSWORD=비밀번호";
            App.connection = new MySqlConnection(connectionPath);
        }
 
        // Create MySqlCommand
        public MySqlCommand CreateCommand(string query)
        {
            MySqlCommand command = new MySqlCommand(query, App.connection);
            return command;
        }
 
        // DataBase Connection
        public bool OpenMySqlConnection()
        {
            try
            {
                App.connection.Open();
                return true;
            }
            catch (MySqlException e)
            {
                switch (e.Number)
                {
                    case 0:
                        Debug.WriteLine("Unable to Connect to Server");
                        break;
                    case 1045:
                        Debug.WriteLine("Please check your ID or PassWord");
                        break;
                }
                return false;
            }
        }
 
        // DataBase Close
        public bool CloseMySqlConnection()
        {
            try
            {
                App.connection.Close();
                return true;
            }
            catch (MySqlException e)
            {
                Debug.WriteLine(e.Message);
                return false;
            }
        }
 
        // Queyr Executer(Insert, Delete, Update ...)
        public void MySqlQueryExecuter(string userQuery)
        {
            string query = userQuery;
 
            if (OpenMySqlConnection() == true)
            {
                MySqlCommand command = new MySqlCommand(query, App.connection);
 
                if (command.ExecuteNonQuery() == 1)
                {
                    Debug.WriteLine("값 저장 성공");
                    App.DataSaveResult = true;
                }
                else
                {
                    Debug.WriteLine("값 저장 실패");
                    App.DataSaveResult = false;
                }
 
                CloseMySqlConnection();
            }
        }
 
        public List<string>[] Select(string tableName, int columnCnt, string id, string pw)
        {
            string query = "SELECT * FROM" + " " + tableName;
 
            List<string>[] element = new List<string>[columnCnt];
 
            for (int index = 0; index < element.Length; index++)
            {
                element[index] = new List<string>();
            }
 
            if (this.OpenMySqlConnection() == true)
            {
                MySqlCommand command = CreateCommand(query);
                MySqlDataReader dataReader = command.ExecuteReader();
 
                while (dataReader.Read())
                {
                    element[0].Add(dataReader["id"].ToString());
                    element[1].Add(dataReader["pw"].ToString());
                }
 
                // 추가된 코드
                if (element != null)
                {
                    for (int i = 0; i < element[0].Count; i++)
                    {
                        if (element[0][i].Contains(id))
                        {
                            for (int j = 0; j < element[1].Count; i++)
                            {
                                if (element[1][i].Contains(pw))
                                {
                                    App.DataSearchResult = true;
                                    break;
                                }
                            }
                        }
                        break;
                    }
                }
 
                dataReader.Close();
                this.CloseMySqlConnection();
 
                return element;
            }
            else
            {
                return null;
            }
        }
    }
}
 
cs

 

제일 상단에 Initialize()라는 함수가 있습니다. 이 함수는 Path를 MySqlConnection의 인자로 넘겨 연결합니다. 여기서 App.connection은 App.xaml.cs에 작성해두었습니다. 그 이유는 이 connection이 한 곳에서만 쓰이는 것이 아니기 때문에 공통 자원으로 올려두었습니다. App.xaml.cs 코드는 이후에 첨부할게요.

 

Initialize() 메서드

다음으로는 query를 인자로 받아 명령을 수행하는 CreateCommand 메서드를 보겠습니다. 이 메서드는 크게 어려운 것 없이 query를 인자로 받아서 넣어주고, connection도 같이 넣어주면 끝입니다.

 

CreateCommand() 메서드

 

다음으로는 OpenMySqlConnection() 메서드를 볼게요. 이 메서드는 이름에서도 알 수 있듯이 Connection을 여는 작업을 수행합니다. 이에 대하여 return 값으로 다음 명령을 진행할지 안 할지 결정합니다. CloseMySqlConnection() 메서드 또한 return 값으로 정상적으로 종료되었는지 아닌지 파악합니다.

 

OpenMySqlConnection() 메서드와 CloseMySqlConnection() 메서드

 

다음으로는 MySqlQueryExecuter() 메서드를 살펴볼게요. 모든 로직 중에서 제일 중요하게 쓰이면서도 기반이 되는 메서드입니다. 이 메서드를 통해 Insert, Delete, Update... 등등 여러 가지 쿼리문을 다 수행할 수 있습니다. 한번 볼까요?

 

MySqlQueryExecuter() 메서드

 

이 메서드에서는 사용가 수행할 쿼리를 인자로 받습니다. 그리고 위에서 작성했던 Open과 Close를 사용합니다. 만약 true이라면 명령을 수행하는데 ExecuteNonQuery() 메서드를 사용해서 성공적으로 수행되었는지 안되었는지 확인할 수 있습니다. ExecuteNonQuery() 메서드의 값이 1이라면 성공적으로 수행이 된 것이고 그게 아니라면 실패를 한 것입니다. 다음으로는 값을 가져오는 Select() 메서드를 살펴볼게요.

 

Select() 메서드

 

이 메서드는 조금 난잡해 보일 수 있으나 부분별로 보면 크게 어렵지 않습니다. 우선 인자로 tableName, columnCnt, id, pw를 받습니다. 즉 DataBase의 Table 이름과 그 안에 속해 있는 Column의 개수 그리고 입력한 Id와 Pw를 받습니다.

 

그 이유는 회원 가입을 통해 Id와 Pw가 저장이 되고 로그인 과정을 수행할 때 입력한 Id와 Pw의 값을 비교해야 하기 때문입니다. 그렇기 때문에 Column의 값인 id와 pw의 값을 데이터베이스로부터 불러와 배열에 저장하고 그 값을 비교하여 로그인을 성공할지 실패할지를 정할 수 있는 것입니다.

 


 

다음으로는 App.xaml.cs의 코드를 볼까요? 사실 위의 MySQLManger.cs 파일에서 언급되지 않았던 DataSaveResult 변수와 DataSearchResult 변수는 DB에 값이 잘 저장되었는지를 확인하기 위한 bool DataType변수와 Select를 통해 값을 정확히 가져왔는지 확인하기 위한 bool DataType 변수입니다.

 

App.xaml.cs

App.xaml.cs의 코드는 그렇게 어려운 게 없기에 따로 설명은 하지 않겠습니다. 그저 공용으로 사용되는 자원이라고 생각하시면 되겠습니다.

 


 

정말 마지막 작업으로 UI와 이를 연결해주기 위한 MainWindow.xaml.cs를 살펴보도록 할게요. 조금 난잡해 보일 수 있지만 #region ~ #endregion으로 회원가입 부분과 로그인 부분을 끊어놨으니 참고해서 봐주세요.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using DB_Linkage.Service;
using System;
using System.Windows;
 
namespace DB_Linkage
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        MySQLManager manager = new MySQLManager();
 
        public MainWindow()
        {
            Loaded += MainWindow_Loaded;
        }
 
        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // DB Connection
            manager.Initialize();
        }
 
        #region SignUp
 
        public class SignUpEventArgs : EventArgs
        {
            public bool isSignUp;
        }
 
        private void btnSignUp_Click(object sender, RoutedEventArgs e)
        {
            SignUpEventArgs args = new SignUpEventArgs();
 
            string query = "INSERT INTO signup_tb(id, pw)" + "VALUES('" + tbId.Text + "'," + tbPw.Text + ")";
            manager.MySqlQueryExecuter(query);
 
            if(App.DataSaveResult == true)
            {
                args.isSignUp = true;
            }
 
            if(args.isSignUp == true)
            {
                MessageBox.Show("회원가입에 성공하셨습니다!");
                tbId.Text = string.Empty;
                tbPw.Text = string.Empty;
            }
            else
            {
                MessageBox.Show("회원가입에 실패하셨습니다.");
            }
        }
 
        #endregion
 
 
 
        #region Login
        
        public class LoginEventArgs : EventArgs
        {
            public bool isSuccess;
        }
 
        private void btnLogin_Click(object sender, RoutedEventArgs e)
        {
            LoginEventArgs args = new LoginEventArgs();
 
            manager.Select("signup_tb"2, tbId.Text, tbPw.Text);
 
            if(App.DataSearchResult == true)
            {
                args.isSuccess = true;
            }
 
            if(args.isSuccess == true)
            {
                MessageBox.Show("로그인에 성공하셨습니다!");
                gdInfo.Visibility = Visibility.Collapsed;
                tbMsg.Visibility = Visibility.Visible;
            }
            else
            {
                MessageBox.Show("로그인에 실패하셨습니다.");
            }
        }
 
        #endregion
    }
}
 
cs

 

먼저 MySQLManager에서 작성한 메서드들을 사용하기 위해서 전역으로 MySQLManager의 인스턴스를 하나 만들어 주세요. 그리고 DB 연결을 위한 Loaded 이벤트를 발생시켜서 이안에 manager.Initialize() 메서드를 호출해 주었습니다. 모든 작업을 수행하기 위해서는 당연히 DB를 먼저 연결을 해야 하기 때문입니다.

 

그리고 회원가입과 로그인을 공통적으로 class를 만들어 EventArgs에 상속시켜두었습니다. 그 이유는 각각 회원가입 성공 유무, 로그인 성공 유무를 바탕으로 화면 전환을 해주기 위해서입니다. 그리고 나머지 Click 이벤트들은 제일 처음 UI 구성을 진행할 때 만들어 둔 이벤트입니다. 먼저 SignUpClick Event부터 보겠습니다.

 

SignUp 버튼의 Click 이벤트

 

Id와 PassWord 폼을 채우고 회원가입 버튼을 누르게 되면 발생하는 이벤트에 대한 내용입니다. 여기서 query는 수동으로 넣어주었는데 이는 좋은 코드가 아닙니다. 다만 이번에는 간단하게 만들어보는 것이기 때문에 그냥 사용하도록 하겠습니다.

 

query를 통해 입력한 Id와 Pw가 VALUES에 추가되고 MySqlQeryExecuter 메서드를 활용하여 명령을 수행합니다. 성공적으로 수행되었다면 isSignUp 변수는 true가 될 것이고, 성공과 동시에 메시지 박스를 통해 결과 여부를 알려준 후 폼의 내용을 지워줍니다. 다음으로 Login 버튼에 대한 내용을 볼까요?

 

Login 버튼의 Click 이벤트

 

회원가입에서의 query는 INSERT였다면 로그인은 DB에서 값을 조회해서 대조를 하기 때문에 Select를 사용합니다. Select() 메서드에서는 Table이름과 컬럼 갯수, 그리고 입력한 Id와 PassWord를 인자로 넘깁니다. 그리고나서 컬럼 갯수에 대한 배열을 만들고 배열의 index에 대하여 또 배열을 만들어 줍니다. 그리고 OpenMySqlConection() 메서드를 통해 연결 후 MySqlDataReader를 통해 값을 읽어옵니다. 그리고 배열의 index에 값을 저장해 줍니다.

 

 

값을 찾아보자.

 

여기서 element의 값들을 돌면서 id가 포함되어있는지 확인하고 pw가 있는지 확인합니다. 만약 값이 들어있을 경우 App.xaml.cs에서 작성했었던 DataSearchResult의 값을 true로 만들어줍니다. 그렇게 되면 성공적으로 로그인을 할 수 있겠죠? 그리고 나서 마지막으로 Collapsed 해두었던 TextBlock의 문구를 나타냄으로써 간단한 프로그램 제작이 끝났습니다. 시연 영상으로 만나볼게요.

 


 

 

시연 영상만 보면 아주 짧고 빨리 넘어가는 것처럼 보이지만 이는 MySQL에 연결하고 값을 저장하고 그 값을 가져와 대조를 한 후 이루어지는 과정입니다. 감사합니다🙌

댓글