공부/인프런 - Rookiss

Part 6-6-2. Blazor 미니 프로젝트 : Blazor RankingApp #2

셩잇님 2024. 10. 1. 14:12
반응형

 

 

🥪 Blazor 미니 프로젝트

 

 지난 시간에는 Blazor에서 미니 프로젝트인 RankingApp을 만들기 위해 새로운 프로젝트와 데이터베이스를 생성하고 이를 연결해주었다. 이번 시간은 이전에 만들었던 RankingApp 프로젝트에 게임 결과 및 데이터 저장, 조회 등 보다 다양한 기능을 추가 개발하는 시간을 가져보도록 한다. 

 


 

🌅 RankingApp #2 모델링

 

 랭킹 시스템을 만들기 위해 어떤 게임의 결과물을 저장하고, 이를 읽어오는 예제를 만들도록 하자. 이를 직접 모델링하는 실습을 한다고 생각하면 된다. 먼저 Data 폴더 밑으로 Models와 Services 폴더를 만들어주도록 하자. Models 폴더 밑으로는 GameResult C# 스크립트 파일을 만들어준다.

 

 해당 스크립트는 게임 결과 데이터를 저장할 것인데, 어떤 데이터가 필요한지 곰곰히 생각해보도록 하자. 

 

namespace RankingApp.Data.Models
{
    public class GameResult
    {
        public int Id { get; set; }
        public int UserId { get; set; }
        public string UserName { get; set; }
        public int Score { get; set; }
        public DateTime Date { get; set; }
    }
}

 

 일전에 설명한 것과 같이 ORM 기술을 사용하지 않았다면 SQL Server 개체 탐색기에 돌아가 하나하나 이를 만들어주어야 했다. 다만, Entity Framework를 사용하면 이럴 필요 없이 자동으로 이를 처리할 수 있다. 이제 DB와 코드를 연결해주는 기능을 만들자. ApplicationDbContext 함수로 돌아가도록 하자.

 

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using RankingApp.Data.Models;

namespace RankingApp.Data
{
    public class ApplicationDbContext : IdentityDbContext
	{
		public DbSet<GameResult> GameResults { get; set; }

		public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
			: base(options)
		{
		}
	}
}

 

 방금 우리가 만들어준 GameResult를 DbSet이라는 자료형을 통해 들어고있어야 한다. 이 후, get/set을 통해 자유롭게 접근할 수 있도록 설정해준다. 이 부분은 우리가 DB에서 GameResult를 사용한다고 가정을 하는 것이다. 따라서 나중에 서버를 띄우게 된다면 이 부분도 자동으로 DB에 똑같이 모델링이 되어 갱신이 된다.

 

 다음으로는 구-Startup, 현-Program 스크립트로 돌아가 서비스를 등록해주도록 하자. 다만 우리는 현재 아이덴티티를 사용하고 있으므로 현재 당장은 추가해주어야 할 것이 없다. 마지막으로 여기까지 작성한 프로그램이 정상적으로 동작하는지 확인하기 위해 실행하기 전 패키지 관리자 콘솔을 통해 데이터를 갱신해주도록 하자.

 

 

 도구 - Nuget 패키지 관리자 - 패키지 관리자 콘솔을 클릭하면 PM > 으로 시작하는 콘솔창을 볼 수 있다. PM은 패키지 매니저의 약자이고 이를 통해 이제 관리를 해주어야 한다. 맨 처음으로는 add-migration RankingService를 실행하여 생성하고자 하는 파일 명으로 마이그레이션을 진행해주어야 한다. 

 

 

 빌드가 성공적으로 진행되면 Migrations 폴더 내부에 RankingService 스크립트가 새로 생긴 것을 볼 수 있다. 패키지 매니저에서 우리가 모델링한 이 GameResult를 파악하고 스크립트를 만들어 준 것이다. 해당 스크립트를 열어보도록 하자.

 

 

 스크립트를 열어보면 ID, UserId, UserName, Score, Data 등 우리가 생성한 데이터들이 테이블로 만들어 지기 위해 스크립트로 변환 된 것을 볼 수 있다. 또한 Id 같은 경우 테이블의 PrimaryKey로 사용하기 위해 활용되는 것 까지 볼 수 있다. 

 

 이 스크립트에서 흥미로운 것은 Up과 Down 이라는 함수가 있는데 Down 같은 경우 DropTable을 통해 GameResult 테이블을 없애고 있다. 이는 버전 컨트롤 때문에 위와 같이 관리되고 있는 것을 볼 수 있다. 

 

 예를 들어 우리가 4.0 버전부터는 GameResult 데이터가 들어가는데, 3.0 버전으로 롤백을 한다고 할 경우 3.0 버전에는 GameResult 테이블이 존재하면 안되기 때문에 이런식으로 DB에서 특정 테이블을 삭제하여 처리하는 것을 알 수 있다.

 

 여기까지 살펴보았으면 우리의 데이터베이스를 갱신해주기 위해 패키지 관리자 콘솔로 돌아가 'update-database' 명령어를 입력하여 데이터베이스를 갱신하자. 갱신이 모두 완료되면 정상적으로 처리가 되었는지 확인하기 위해 SQL 서버 개체 탐색기로 돌아가, RankingDB 데이터베이스를 새로고침 해보자. 새로고침 한다면 GameResults가 생긴 것을 볼 수 있고 해당 데이터베이스의 열 데이터로 우리가 생성한 'GameResults' 들의 컬럼들이 모두 들어가있는 것을 볼 수 있다.

 

 


 

 이어서 CRUD중 Read를 테스트하기 위해 dbo.GameResults 테이블 우클릭 데이터 보기를 클릭하여 임의의 데이터를 넣어주로고 하자. 나와 같은 경우 아래와 같이 데이터를 넣어주었다. 여기서 입력을 처리하면 실제로 데이터베이스에 데이터가 추가된다.

 

 

 이제 만들어진 데이터를 페이지에서 조회하고 확인하기 위해서는 결국 DB에 접근할 수 있는 어떤 서비스를 운영을 해야된다. 따라서 이 서비스를 만들어주기 위해 Services 폴더 밑으로 RankingService 스크립트를 새롭게 만들어주도록 한다. 내용은 아래와 같이 작성한다.

 

using RankingApp.Data.Models;

namespace RankingApp.Data.Services
{
    public class RankingService
	{
		ApplicationDbContext _context;

        public RankingService(ApplicationDbContext context)
        {
            _context = context;
        }

        public Task<List<GameResult>> GetGameResultsAsync()
		{
			// DB에서 데이터를 가져온다.
			List<GameResult> results = _context.GameResults
									.OrderByDescending(item => item.Score)
									.ToList();
			return Task.FromResult(results);
		}
	}
}

 

 일전에 DB와 클라이언트를 연결시켜주는 스크립트가 ApplicationDbContext 였으므로 ApplicationDbContext를 _context로 선언 후 생성자로 이를 매핑시켜준다. 이 후 GetGameResultsAsync 함수를 통해 DB에서 데이터를 가져온다. 이 때 Orderby 등 다양한 조건을 통해 데이터를 정렬하여 가져올 수 있다. 이 서비스도 새롭게 만들어 주었기 때문에 Program 스크립트로 돌아가 서비스를 등록해주도록 하자.

 

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
using RankingApp.Areas.Identity;
using RankingApp.Data;
using RankingApp.Data.Services;

namespace RankingApp
{
	public class Program
	{
		public static void Main(string[] args)
		{
			var builder = WebApplication.CreateBuilder(args);

			...
            
			// RankingService 사용을 위한 등록
			builder.Services.AddScoped<RankingService>();

			...

			app.Run();
		}
	}
}

 

 이렇게 작성하면 실질적으로 RankingService 라는 서비스 자체도 실행할 수 있는 환경이 세팅된 것이다. 마지막으로 Pages 폴더로 돌아가 Ranking 레이저 컴포넌트를 만들어주자. 컴포넌트를 생성하고 안의 내용을 작성하는 일은 여태까지 학습하면서 계속 진행해왔던 부분이기 때문에 크게 어렵지 않다.

 

@page "/ranking"
@using RankingApp.Data.Models
@using RankingApp.Data.Services

@inject RankingService RankingService

<h3>Ranking</h3>

@if (_gameResults == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>UsersName</th>
                <th>Score</th>
                <th>Date</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var gameResult in _gameResults)
            {
                <tr>
                    <td>@gameResult.UserName</td>
                    <td>@gameResult.Score</td>
                    <td>@gameResult.Date.ToString()</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
	List<GameResult> _gameResults;

	protected override async Task OnInitializedAsync()
	{
		_gameResults = await RankingService.GetGameResultsAsync();
	}
}

 

 페이지가 실행될 때 자동으로 호출되는 OnInitializedAsync을 통해 _gameResults를 RankingService.GetGameResultsAsync()에서 가져오도록 한다. 이 후 해당 데이터를 table을 통해 나타내주도록 하자. 마지막으로 navMenu에서도 Ranking Page를 보여주기 위해 다음과 같이 처리한다.

 

...

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="ranking">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Ranking
            </NavLink>
        </div>
    </nav>
</div>

@code {
    ...
}

 

 이 후, 프로그램을 실행해보면 우리가 넣어준 데이터가 잘 정렬되어 보이는 것을 확인할 수 있다.

 

 

 

반응형