Entity Framework를 사용해 JOIN 쿼리문을 수행하는 방법에 대해 알아봅니다.

 

 

 

0. 소스코드

 

소스코드는 다음 링크에서 확인할 수 있습니다: https://github.com/smoh-dev/EF_Join

 

GitHub - smoh-dev/EF_Join: https://smoh.tistory.com/471

https://smoh.tistory.com/471. Contribute to smoh-dev/EF_Join development by creating an account on GitHub.

github.com

 

 

 

1. DB 준비

 

MySQL을 설치 한 뒤 다음과 같은 쿼리문을 수행해 테이블을 생성합니다.

 

#Create user table
CREATE TABLE `dev_db`.`tbl_user` (
  `key` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(64) NULL,
  PRIMARY KEY (`key`));

#Create order table.
CREATE TABLE `dev_db`.`tbl_order` (
  `key` INT NOT NULL AUTO_INCREMENT,
  `user_key` INT NOT NULL,
  `code` VARCHAR(128) NOT NULL,
  PRIMARY KEY (`key`),
  INDEX `fk_user_key_idx` (`user_key` ASC),
  CONSTRAINT `fk_user_key`
    FOREIGN KEY (`user_key`)
    REFERENCES `dev_db`.`tbl_user` (`key`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

#Insert default data.
INSERT INTO `dev_db`.`tbl_user`(`name`) VALUES ('smoh');
INSERT INTO `dev_db`.`tbl_order`(`user_key`, `code`) VALUES (1, 'my-custom-order-id');

 

 

 

 

2. 프로젝트 생성.

 

편의를 위해 간단한 프로젝트를 생성합니다.

 

 

 

 

 

3. NuGet 패키지 설치.

 

다음 NuGet 패키지를 설치합니다.

 

 

 

 

4. Table Model 생성

 

앞서 생성한 테이블대로 모델을 생성합니다.

 

//TableUser
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace my_test_api.Model
{
    [Table("tbl_user")]
    public class TableUser
    {
        [Key]
        [Column("key")]
        public int Key { get; set; }
        [Column("name")]
        public string Name { get; set; }
    }
}

//TableOrder
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace my_test_api.Model
{
    [Table("tbl_order")]
    public class TableOrder
    {
        [Key]
        [Column("key")]
        public int Key { get; set; }
        [Column("user_key")]
        public int UserKey { get; set; }
        [Column("code")]
        public string Code { get; set; }
    }
}

 

 

 

5. DB Context 생성

 

이제 DB Context를 생성해 서비스에 연결합니다.

 

//DBContext
using Microsoft.EntityFrameworkCore;
using my_test_api.Model;
namespace my_test_api
{
    public class DBContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            var connectionString = "server=localhost; database=dev_db; user=dev; password=devpass";
            options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
        }
        public DbSet<TableUser> User { get; set; }
        public DbSet<TableOrder> Order { get; set; }
    }
}

 

//Program.cs
using my_test_api;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

//Add DBContext
builder.Services.AddSingleton<DBContext>();

var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();

 

 

 

6. 컨트롤러 작성

 

다음 코드와 같이 간단한 컨트롤러를 작성합니다.

 

//UserOrderController.cs
using Microsoft.AspNetCore.Mvc;
using my_test_api.Model;
namespace my_test_api.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserOrderController : ControllerBase
    {
        DBContext dbContext;
        public UserOrderController(DBContext dBContext)
        {
            this.dbContext = dBContext;
        }
        // GET api/<UserOrderController>/1
        [HttpGet("{id}")]
        public string Get(int id)
        {
            var query = (from u in dbContext.Set<TableUser>()
                        join o in dbContext.Set<TableOrder>()
                        on u.Key equals o.UserKey
                        where u.Key == id
                        select new { u, o }).SingleOrDefault();
            string result = $"UserKey: {query.u.Key}, UserName: {query.u.Name}, OrderKey: {query.u.Key}, OrderCode: {query.o.Code}";
            return result;
        }
    }
}

 

내부의 query를 통해 DB Table Join 작업을 수행합니다.

 

 

 

7. 테스트

 

이제 Swagger를 열고 테스트를 진행해 봅시다.

 

 

쿼리가 정상적으로 동작해 데이터가 출력되는 것을 확인할 수 있습니다.

 

 

 

 

 

반응형

 

 

dotNet 6.0 프로젝트에서 EntityFramework를 사용해 MariaDB에 연결하는 방법에 대해 알아봅니다.

 

 

 

1. NuGet 패키지 설치.

 

다음 NuGet 패키지를 설치합니다.

 

 

 

 

2. DB 테이블 생성

 

DB에 접속해 다음 예시와 같이 테이블을 생성합니다.

 

CREATE TABLE `dev_db`.`users` (
  `Key` INT NOT NULL AUTO_INCREMENT,
  `Id` VARCHAR(128) NOT NULL,
  `Name` VARCHAR(64) NOT NULL,
  PRIMARY KEY (`Key`),
  UNIQUE INDEX `Key_UNIQUE` (`Key` ASC) VISIBLE,
  UNIQUE INDEX `Id_UNIQUE` (`Id` ASC) VISIBLE);

 

 

 

3. DBContext 생성

 

다음 예시와 같이 Model과 DbContext를 생성합니다.

 

//Model: User
    public class User
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public User(string id, string name)
        {
            this.Id = id;
            this.Name = name;
        }
    }
//DbContext: UserContext
    public class UserContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            var connectionString = "server=localhost; database=dev_db; user=dev; password=devpass"; 
            options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
        }
    }

 

 

 

4. User 추가

 

다음 예시 코드를 실행해 Users 테이블에 User를 추가합니다.

 

// Insert a new user to users table.
using (var context = new UserContext())
{
    context.Users.Add(new User("testID", "testName"));
    context.SaveChanges();
}

 

 

DB에 정상적으로 데이터가 추가된 것을 확인할 수 있습니다.

 

 

 

 

 

반응형

 

앞선 글

 

Entity Framework Core를 처음 사용하고자 했습니다. MS Docs를 읽으며 자습서를 따라 하는 도중 문득 의문이 생겼습니다. 내가 그동안 알고 있던 패턴은 Repository 패턴인데 이 익숙한 패턴을 그대로 사용할 수는 없을까? 하는 생각이 들었습니다.

 

MS Docs에서는 Repository 패턴과 관련된 부분을 찾을 수 없었습니다. 혹시 이런 고민을 하고 있는 사람이 저뿐 아니라 다른 분도 있는지 구글링을 해 본 결과 다음과 같은 글을 확인할 수 있었습니다.

 

 

 

EF에서 저장소 패턴을 사용하는 것이 좋지 않은 이유

 

왜 Entity Framework 에서 Repository 패턴을 사용하면 안 될까요: Why shouldn't I use the repository pattern with Entity Framework?

 

Why shouldn't I use the repository pattern with Entity Framework?

During a job interview, I was asked to explain why the repository pattern isn't a good pattern to work with ORMs like Entity Framework. Why is this the case?

softwareengineering.stackexchange.com

 

해당 글을 번역해보자면 다음과 같습니다.

 

면접에서 Repository 패턴(이하 저장소 패턴)이 Entity Frmawork(이하 EF)와 같은 ORM과 함께 사용하는데 좋은 패턴이 아닌 이유를 설명하라는 질문을 받았습니다. 왜 그런 걸까요?

 

EF에서 저장소 패턴을 사용하지 않는 가장 큰 이유는 바로 EF가 이미 저장소 패턴을 구현하고 있기 때문입니다. DbContext는 여러분의 작업 단위이고 DbSet은 저장소가 됩니다. 이 위해 저장소 패턴으로 다른 계층을 구현한다면 중복될 뿐 아니라 유지 관리가 더 어려워지게 됩니다.

 

사람들은 디자인 패턴의 목적을 알지 못한 채 패턴을 사용하곤 합니다 저장소 패턴의 목적은 낮은 수준의 데이터베이스 쿼리 로직을 추상화하는 것입니다. 코드에 실제 SQL문을 작성하던 예전에는 저장소 패턴이 코드 베이스 전체에 흩어져 있는 각각의 SQL을 개별 메서드에서 한 곳으로 지역화(Localize)하는 방법 중 하나였습니다. EF와 같은 ORM을 사용하면 이러한 코드 추상화를 대체할 수 있으므로 저장소 패턴이 필요하지 않습니다.

 

그렇다고 ORM위에 추상화를 만드는 것은 나쁜 생각은 아닙니다. 데이터가 EF나 또 다른 Web API에서 오는지 신경 쓰지 않고 애플리케이션에서 사용할 수 있는  API를 구성하는 서비스 패턴을 사용한다고 가정해 봅시다. 애플리케이션에 필요한 데이터를 반환하기 위해 서비스 클래스에 메서드를 추가하기면 하면 되므로 훨씬 간단해집니다. 

 

예를 들어 To-do앱을 만들고 있다면 이번 주에 만기 되고 아직 완료되지 않은 항목을 반환하는 서비스 호출이 있을 수도 있습니다. 앱이 알고 있는 것은 이 정보를 원한다면 해당 메서드를 호출한다는 것입니다. 매서드 내부에서 EF와 상호작용이 진행됩니다. 나중에 상호작용 대상이 변경되더라도 이 메서드 외의 나머지 코드는 문제없이 작동합니다.

 

잠재적으로는 저장소 패턴을 사용하는 것을 주장하는 것처럼 들릴 수 있지만 여기서 주요한 차이점은 서비스가 더 얇은 계층이며 리포지토리가 계속 쿼리 하는 것과 달리 서비스는 완전히 만들어진 데이터를 반환하도록 되어있다는 점입니다.

 

 

 

맺는 글

 

위 글에서 "디자인 패턴의 목적을 알지 못한 채 패턴을 사용하곤 한다"는 글이 크게 와 닿았습니다. 다양한 패턴을 사용하기 위해 알아보곤 했는데 이 패턴을 왜 쓰고 무엇을 위해 사용되는 패턴인지 한번 더 확인해야겠다는 생각이 드는 글이었습니다. 물론 EF를 저장소 패턴과 같이 안 쓰는 이유에 대해서도 명확히 이해하게 되었습니다

 

 

 

 

 

반응형

+ Recent posts