[C# – 기초 강좌] 8. Database 사용하기 (Feat. ADO.NET, Entity Framework, Dapper)

C#을 사용하여 데이터베이스(Database)와 상호작용하는 것은 어플리케이션에서 데이터를 저장하고 관리할 수 있는 강력한 방법을 제공합니다.

C#에서 데이터베이스를 사용하는 주요 방법은 ADO.NET, 엔티티 프레임워크(Entity Framework), 그리고 Dapper와 같은 마이크로 ORM 라이브러리를 포함합니다.

이러한 각각의 기술들은 서로 다른 사용 케이스와 선호도에 따라 선택될 수 있습니다.

database image

C# 에서 Database 사용하기 소개

기본 개념

  1. 데이터베이스 연결:
    • 데이터베이스 작업을 시작하기 전에 C# 어플리케이션에서는 데이터베이스 서버와 연결을 설정해야 합니다.
    • 이 연결은 일반적으로 연결 문자열을 사용하여 구성되며, 이 문자열에는 서버의 위치, 데이터베이스 이름, 접근 권한을 위한 사용자 이름과 비밀번호가 포함됩니다.
  2. 명령 실행 (with SQL):
    • 데이터베이스에 연결한 후, SQL 문을 실행하여 데이터를 조회, 추가, 수정, 삭제할 수 있습니다.
    • 이 명령들은 데이터베이스 서버에 의해 처리되고 결과가 반환됩니다.
  3. 데이터 처리:
    • 데이터를 데이터베이스에서 가져오거나 데이터베이스에 보낸 후, 이 데이터를 C# 코드 내에서 객체로 매핑하고 처리하는 과정을 포함합니다.

MySQL 사용 및 준비

본 포스팅에서는 Database로 MySQL을 사용할 예정입니다.

C#에서 MySQL을 사용하기 위해 NuGet 패키지 매니저를 통해 MySQL Connector를 설치합니다.

[Tools] –> [NuGet Pacakage Manager] –> [Manage Nuget Packages for Solution…]

Browse 탭에서 MySql.Data 검색하고 추가

Entity Framework(EF) 을 사용하기 위해서는 Microsoft.EntityFrameworkCorePomelo.EntityFrameworkCore.MySql을 마찬가지로 NuGet 매니저를 통해 설치합니다.

MySQL Logo

ADO.NET

개요

ADO.NET (ActiveX Data Objects for .NET)은 .NET 의 일부로 제공되는 데이터 접근 기술입니다.

이 기술은 다양한 데이터 소스 (주로 관계형 데이터베이스)와의 통신을 위해 설계되었으며, 데이터베이스 작업을 위한 연결, 명령, 데이터 읽기 및 데이터 셋 관리 기능을 제공합니다.

ADO.NET은 연결 지향 아키텍처를 기반으로 하며, 동시에 연결이 끊어진(disconnected) 환경에서도 데이터를 처리할 수 있는 기능을 갖추고 있습니다.

주요 구성 요소:

  1. Connection: 데이터 소스에 대한 연결을 관리합니다.
  2. Command: 데이터 소스에 대해 SQL 문을 실행합니다.
  3. DataReader: 연결 지향 방식으로 데이터를 읽어옵니다.
  4. DataAdapter: 데이터 셋(Data Set)과 데이터 소스(Data Source) 간의 데이터를 채우고 동기화합니다.
  5. DataSet: 데이터의 메모리 내 캐시를 유지하며, 데이터의 관계적 표현을 제공합니다.

예제들은 MySqlAdoNet 이라는 Class를 추가하여 진행하겠습니다.

Query vs NonQuery

QueryNonQuery는 데이터베이스와 상호작용하는 SQL 명령문을 실행하는 두 가지 방법입니다. 각각의 차이점과 사용 용도를 간단하게 설명하겠습니다.

Query는 데이터베이스에서 데이터를 조회하는 데 사용됩니다. 주로 SELECT 문을 실행하여 결과 집합을 반환합니다.

  • 반환값: Query는 데이터베이스에서 데이터를 조회한 결과를 반환합니다. 결과는 보통 데이터 리더(DataReader)나 데이터 집합(DataSet) 형태로 반환됩니다.
  • 예시: SELECT 문을 실행하여 특정 테이블의 데이터를 조회할 때 사용됩니다.
  • MySqlCommand Class method
    • ExecuteReader()

NonQuery는 데이터베이스의 데이터를 변경하거나 구조를 변경하는 명령문을 실행하는 데 사용됩니다. 주로 INSERT, UPDATE, DELETE 문 또는 데이터 정의 언어(DDL) 명령문(CREATE TABLE, ALTER TABLE 등)을 실행할 때 사용됩니다.

  • 반환값: NonQuery는 영향받은 행의 수를 반환합니다. 즉, INSERT, UPDATE, DELETE 문이 영향을 미친 데이터베이스 행의 수를 반환합니다. DDL 명령문을 실행할 때는 보통 반환 값을 사용하지 않습니다.
  • 예시: 테이블에 데이터를 삽입하거나 기존 데이터를 수정 또는 삭제할 때 사용됩니다.
  • MySqlCommand Class method
    • ExecuteNonQuery()

Database 생성

생성자(Constructor)에서 Database가 없으면 Database를 생성하는 코드를 추가하였습니다.

Database가 있으면 연결 string을 _connectionString 변수에 저장합니다.

using MySql.Data.MySqlClient;

namespace UseDatabase.Repositories
{
    public class MySqlAdoNet
    {
        private string _connectionString;

        // dbName: devitworld_db, dbUserName: root, dbPassword: devitworld!!
        public MySqlAdoNet(string dbName, string dbUserName, string dbPassword)
        {
            // Initial connection string without specifying a database
            string initialConnectionString = $"server=localhost;user={dbUserName};password={dbPassword};";

            // Check if the database exists, if not, create it
            using (var connection = new MySqlConnection(initialConnectionString))
            {
                try
                {
                    connection.Open();
                    var createDbCommand = new MySqlCommand($"CREATE DATABASE IF NOT EXISTS `{dbName}`;", connection);
                    createDbCommand.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    throw new Exception("An error occurred while creating the database.", ex);
                }
            }

            _connectionString = $"server=localhost;database={dbName};user={dbUserName};password={dbPassword};";
        }
}

Database 연결

_connectionString 에 저장한 string과 MySqlConnection을 이용하여, Database에 연결할 수 있습니다.

        // connection test
        public void TestConnection()
        {
           // _connectionString = $"server=localhost;database={dbName};user={dbUserName};password={dbPassword};";
            using (MySqlConnection connection = new MySqlConnection(_connectionString))
            {
                try
                {
                    connection.Open();

                    Console.WriteLine("Connection is successful.");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Connection is failed.");
                    Console.WriteLine(ex.Message);
                }

            }
        }

Table 생성

다음과 같이 CREATE SQL 문을 활용하여 Table을 생성할 수 있습니다.

        public void CreateUserTable()
        {
            string query = $"CREATE TABLE IF NOT EXISTS USER (ID INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(50), AGE INT, EMAIL VARCHAR(50));";

            using (MySqlConnection connection = new MySqlConnection(_connectionString))
            {
                connection.Open();

                using (MySqlCommand command = new MySqlCommand(query, connection))
                {
                    command.ExecuteNonQuery();
                }
            }

            Console.WriteLine("USER table created successfully.");
        }

CROUD

다음은 Ado.Net을 이용하여 MySQL 데이터베이스에서 CRUD(Create, Read, Update, Delete) 작업을 수행할 수 있고, 예제는 다음과 같습니다.

Create

SQL의 Insert 문과 MySqlCommandExecuteNonQuery() Method을 활용하여 Data를 생성합니다.

        public void InsertUser(string name, int age, string email)
        {
            string query = $"INSERT INTO USER (NAME, AGE, EMAIL) VALUES ('{name}', {age}, '{email}');";

            using (MySqlConnection connection = new MySqlConnection(_connectionString))
            {
                connection.Open();

                using (MySqlCommand command = new MySqlCommand(query, connection))
                {
                    command.ExecuteNonQuery();
                }
            }

            Console.WriteLine("USER inserted successfully.");
        }
Read

SQL의 Select 문과 MySqlCommandExecuteReader() Method를 이용해 Data를 조회합니다.

        public void ReadAllUsers()
        {
            string query = $"SELECT * FROM USER;";

            using (MySqlConnection connection = new MySqlConnection(_connectionString))
            {
                connection.Open();

                using (MySqlCommand command = new MySqlCommand(query, connection))
                {
                    using (MySqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            Console.WriteLine($"ID: {reader.GetInt32(0)}, NAME: {reader.GetString(1)}, AGE: {reader.GetInt32(2)}, EMAIL: {reader.GetString(3)}");
                        }
                    }
                }
            }
        }
Update

SQL의 Update 문과 MySqlCommandExecuteNonQuery() Method을 활용하여 Data를 생성합니다.

        public void UpdateUser(int id, string name, int age, string email)
        {
            string query = $"UPDATE"
                + $" USER"
                + $" SET"
                + $" NAME = '{name}',"
                + $" AGE = {age},"
                + $" EMAIL = '{email}'"
                + $" WHERE"
                + $" ID = {id};";

            using (MySqlConnection connection = new MySqlConnection(_connectionString))
            {
                connection.Open();

                using (MySqlCommand command = new MySqlCommand(query, connection))
                {
                    command.ExecuteNonQuery();
                }
            }

            Console.WriteLine("USER updated successfully.");

        }
Delete

SQL의 Delete 문과 MySqlCommandExecuteNonQuery() Method을 활용하여 Data를 생성합니다.

        public void DeleteUser(int id)
        {
            string query = $"DELETE FROM USER WHERE ID = {id};";

            using (MySqlConnection connection = new MySqlConnection(_connectionString))
            {
                connection.Open();

                using (MySqlCommand command = new MySqlCommand(query, connection))
                {
                    command.ExecuteNonQuery();
                }
            }

            Console.WriteLine("USER deleted successfully.");
        }

Test

다음과 같이 Main에 앞서 추가한 MySqlAdoNet Class를 활용하여 테스트 할 수 있습니다.

namespace UseDatabase
{
    class Program
    {
        static void Main(string[] args)
        {
            MySqlAdoNet mySqlAdoNet = new MySqlAdoNet("devitworld_db", "root", "Devitworld!!!!");

            mySqlAdoNet.TestConnection();
            mySqlAdoNet.CreateUserTable();

            mySqlAdoNet.InsertUser("devitworld", 36, "insfamworld@naver.com");
            mySqlAdoNet.InsertUser("creamboy", 32, "creamboy1@naver.com");

            mySqlAdoNet.ReadAllUsers();

            mySqlAdoNet.UpdateUser(1, "devitworld", 37, "devitworld@google.com");

            mySqlAdoNet.DeleteUser(mySqlAdoNet.GetUserId("creamboy"));


            Console.WriteLine("Finish the Database Tutorial !!");
        }
    }
}

Entity Framework

개요

Entity Framework (EF)는 Microsoft에 의해 개발된 객체 관계 매핑 (ORM) 프레임워크로, 데이터베이스 테이블을 .NET의 클래스로 매핑하여 개발자가 데이터베이스를 객체지향적으로 다룰 수 있도록 돕습니다.

EF를 사용하면 SQL 쿼리를 직접 작성하지 않고도 데이터베이스 작업을 할 수 있으며, 코드의 가독성과 유지 보수성이 향상됩니다.

Entity Framework의 주요 특징:

  1. 코드 중심 접근법(Code First): 데이터베이스 스키마를 .NET 클래스에서 정의한 후 EF가 이를 바탕으로 데이터베이스를 생성하고 관리합니다.
  2. 데이터베이스 중심 접근법(Database First): 기존의 데이터베이스를 기반으로 모델을 생성하고, 이 모델을 사용하여 데이터베이스와 상호작용합니다.
  3. 모델 중심 접근법(Model First): 개념적 모델을 먼저 설계하고 이를 바탕으로 데이터베이스 스키마와 코드를 생성합니다.
  4. LINQ(Language Integrated Query): 데이터베이스 쿼리를 .NET 언어의 일부처럼 표현할 수 있어 쿼리 작성이 쉽고 간편합니다.

주요 구성 요소

  • DbContext: 데이터베이스와의 세션을 관리하고, 데이터베이스 작업을 수행하는 주요 클래스입니다.
  • Entity: 데이터베이스의 테이블과 매핑되는 클래스입니다.
  • DbSet: 특정 엔터티 유형의 컬렉션을 나타내며, 데이터베이스 작업을 수행할 수 있는 메서드를 제공합니다.

모델 정의

Database에 사용할 모델을 정의합니다.

namespace UseDatabase.Model
{
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Email { get; set; }
    }
}

Database 연결

_connectionString 에 저장한 string과 OnConfiguring을 이용하여, Database에 연결할 수 있습니다.

OnConfiguring 메서드는 DbContext 클래스의 메서드 중 하나로, Entity Framework Core에서 데이터베이스 컨텍스트가 어떻게 설정되고 구성되는지를 정의합니다.

이 메서드는 주로 데이터베이스 연결 문자열과 옵션을 설정하는 데 사용됩니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using UseDatabase.Model;
using Microsoft.EntityFrameworkCore;

namespace UseDatabase.Repositories
{
    // Example class for Entity Framework with MySQL
    public class MySqlEntityFramework : DbContext
    {
        public DbSet<User> User { get; set; }

        private readonly string _connectionString;

        public MySqlEntityFramework(string dbName, string dbUserName, string dbPassword)
        {
            _connectionString = $"server=localhost;database={dbName};user={dbUserName};password={dbPassword};";
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseMySql(_connectionString, new MySqlServerVersion(new Version(8, 0, 36)));
        }
}

Table 생성

ntity Framework Core를 사용하면 기본적으로 모델 클래스의 이름과 같은 테이블을 자동으로 생성해줍니다.

이 기능은 Entity Framework Core의 Code First 접근 방식의 일부로, 데이터베이스 스키마가 코드에서 정의된 모델 클래스를 기반으로 자동으로 생성됩니다.

허나 다음과 같이 OnModelCreating()을 override 하여 필드에 추가 옵션을 제공할 수 있습니다.

        // Create Table
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>(entity =>
            {
                entity.ToTable("User"); // 테이블 이름 설정

                entity.HasKey(e => e.Id); // 기본 키 설정

                entity.Property(e => e.Name)
                      .IsRequired() // 필수 필드
                      .HasMaxLength(50); // 최대 길이

                entity.Property(e => e.Email)
                      .HasMaxLength(100); // 최대 길이

                entity.Property(e => e.Age)
                      .IsRequired();
            });

            Console.WriteLine("Table Created !!");
        }

CROUD

다음은 EntityFramework을 이용하여 MySQL 데이터베이스에서 CRUD(Create, Read, Update, Delete) 작업을 수행할 수 있고, 예제는 다음과 같습니다.

Create
        public void CreateUser(string name, int age, string email)
        {
            User user = new User
            {
                Name = name,
                Age = age,
                Email = email
            };

            User.Add(user);
            SaveChanges();
        }
Read
        public List<User> GetUsers()
        {
            return User.ToList();
        }
Update

SQL의 Update 문과 MySqlCommandExecuteNonQuery() Method을 활용하여 Data를 생성합니다.

        public void UpdateUser(int id, string name, int age, string email)
        {
            User user = User.Find(id);
            if (user != null)
            {
                user.Name = name;
                user.Age = age;
                user.Email = email;
                SaveChanges();
            }
        }
Delete

SQL의 Delete 문과 MySqlCommandExecuteNonQuery() Method을 활용하여 Data를 생성합니다.

        // 4. Delete
        public void DeleteUser(int id)
        {
            User user = User.Find(id);
            if (user != null)
            {
                User.Remove(user);
                SaveChanges();
            }
        }

Test

다음과 같이 Main에 앞서 추가한 MySqlEntityFramework Class를 활용하여 테스트 할 수 있습니다.

namespace UseDatabase
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var mySqlEntityFramework = new MySqlEntityFramework("devitworld_db", "root", "Devitworld!!!!"))
            {
                mySqlEntityFramework.Database.EnsureCreated();

                mySqlEntityFramework.CreateUser("devitworld", 36, "insfamworld@naver.com");
                mySqlEntityFramework.CreateUser("creamboy", 32, "creamboy1@naver.com");

                var users = mySqlEntityFramework.GetUsers();
                foreach (var user in users)
                {
                    Console.WriteLine($"Id: {user.Id}, Name: {user.Name}, Age: {user.Age}, Email: {user.Email}");
                }

                mySqlEntityFramework.UpdateUser(1, "devitworld", 37, "devitworld@google.com");

                mySqlEntityFramework.DeleteUser(mySqlEntityFramework.GetUserId("creamboy"));
            }

            Console.WriteLine("Finish Entity Framework Examples !!");
        }
    }
}

Dapper

개요

Dapper는 .NET 환경에서 사용할 수 있는 경량의 객체 관계 매핑 (ORM) 라이브러리입니다.

Stack Overflow 팀에 의해 개발되었으며, 그들의 필요에 따라 고성능을 중시하는 구조로 설계되었습니다.

Dapper는 ADO.NET 기술을 기반으로 하면서도, 개발자가 SQL 쿼리를 직접 작성할 수 있는 유연성을 제공하며, 이 쿼리 결과를 객체로 쉽게 매핑할 수 있도록 돕습니다.

Dapper는 많은 개발자들에게 성능이 중요한 애플리케이션에서 널리 사용되고 있습니다.

Dapper의 주요 특징:

  1. 성능: Dapper는 매우 빠른 실행 속도를 제공합니다. 이는 내부적으로 데이터베이스 쿼리 결과를 객체로 매핑할 때 최적화된 처리가 이루어지기 때문입니다.
  2. 간결성: SQL 쿼리를 직접 작성하므로, 복잡한 쿼리나 특정 데이터베이스 기능을 사용하는데 있어 제한이 없습니다.
  3. 확장성: Dapper는 확장 메서드를 통해 기능을 제공하므로, 개발자는 필요한 기능을 선택적으로 사용할 수 있습니다.
  4. 간편한 설정: Dapper는 별도의 설정 파일이나 복잡한 코드 구성 없이 사용할 수 있으며, 단 몇 줄의 코드로 시작할 수 있습니다.

참고 링크

Leave a Comment