ASP.NET Core 8.0 MVC를 사용한 CRUD 구현: Branches 테이블 (VisualAcademy 프로젝트)

  • 10 minutes to read

이 가이드는 Branches 테이블에 대해 ASP.NET Core 8.0 MVC에서 CRUD(Create, Read, Update, Delete) 기능을 구현하는 방법을 안내합니다. 프로젝트는 VisualAcademy라는 이름으로 진행되며, 모델, 리포지토리, 서비스 계층을 포함하고, Web APIjQuery를 사용해 동적 CRUD를 구현합니다. CreateEditBootstrap 5 모달을 사용하여 팝업 형태로 데이터를 입력하고 수정합니다.


1. SQL Server 테이블 생성

VisualAcademy.SqlServer 프로젝트가 있으면 열고, 없으면 생성한 후에 다음 테이블을 추가하세요.

Branches라는 이름의 테이블을 SQL Server에서 생성합니다. 이 테이블에는 지점의 정보를 저장하기 위한 구조를 포함하며, 고유 식별자(Id), 지점 이름, 위치, 연락처, 설립일, 활성 상태를 관리합니다.

CREATE TABLE Branches (
    Id INT IDENTITY(1,1) PRIMARY KEY,  -- 자동 증가하는 고유 ID
    BranchName NVARCHAR(100),          -- 지점 이름
    Location NVARCHAR(255),            -- 지점 위치 (주소 또는 지역)
    ContactNumber NVARCHAR(20),        -- 지점 연락처 번호
    EstablishedDate DATE,              -- 지점 설립일
    IsActive BIT                       -- 지점 활성 상태 (1: Active, 0: Inactive)
);

설명:

  • Id: 각 지점을 고유하게 식별하는 INT형 기본 키입니다. IDENTITY(1,1)로 설정하여 자동 증가하도록 합니다.
  • BranchName: 지점의 이름을 저장하는 NVARCHAR(100) 필드입니다.
  • Location: 지점의 위치를 저장하는 NVARCHAR(255) 필드입니다.
  • ContactNumber: 지점의 연락처 정보를 저장하는 NVARCHAR(20) 필드입니다.
  • EstablishedDate: 지점 설립일을 기록하는 DATE 필드입니다.
  • IsActive: 지점의 활성화 여부를 저장하는 BIT 필드로, 1은 활성 상태, 0은 비활성 상태를 나타냅니다.

이 테이블은 Branches 데이터를 관리하기 위한 기본 구조를 제공합니다.


2. ASP.NET Core MVC 프로젝트 설정

VisualAcademy 프로젝트가 있으면 열고, 그렇지 않으면 새롭게 만드세요.

Step 1: 프로젝트 생성

  1. Visual Studio를 실행하고, 파일(File) > 새로 만들기(New) > 프로젝트(Project)로 이동합니다.
  2. ASP.NET Core Web App (Model-View-Controller) 템플릿을 선택하고, 프로젝트 이름을 VisualAcademy로 지정한 후, .NET 8.0을 사용합니다.

Step 2: Entity Framework Core 설치

  1. 패키지 관리 콘솔을 열고, 다음 명령어를 입력하여 Entity Framework CoreSQL Server 관련 패키지를 설치합니다.
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools
  1. appsettings.json 파일에 데이터베이스 연결 문자열을 추가합니다.
"ConnectionStrings": {
  "DefaultConnection": "Server=.;Database=VisualAcademyDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}

Step 3: Program.cs 설정

Entity Framework Core를 사용하기 위해 **Dependency Injection(DI)**를 설정합니다.

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

// Register DbContext
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// Register repository and service for DI
builder.Services.AddScoped<IBranchRepository, BranchRepository>();
builder.Services.AddScoped<BranchService>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}

app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Branches}/{action=Index}/{id?}");

app.Run();

이렇게 하면 Entity Framework Core를 사용하여 데이터베이스와 상호작용할 수 있도록 설정되고, Branches 컨트롤러가 기본적으로 라우팅됩니다.


3. Model, Repository, Service 클래스 생성

Step 1: Branches 모델 클래스

Models 폴더에 Branch.cs 파일을 생성하고 다음 코드를 작성합니다.

public class Branch
{
    public int Id { get; set; }               // 자동 증가하는 고유 ID
    public string BranchName { get; set; }    // 지점 이름
    public string Location { get; set; }      // 지점 위치
    public string ContactNumber { get; set; } // 지점 연락처
    public DateTime EstablishedDate { get; set; } // 지점 설립일
    public bool IsActive { get; set; }        // 지점 활성 상태
}

Step 2: ApplicationDbContext 설정

Data 폴더에 ApplicationDbContext.cs 파일을 생성하고 다음 코드를 작성합니다.

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

    public DbSet<Branch> Branches { get; set; }
}

Step 3: Repository 인터페이스 및 클래스

Repositories 폴더에 IBranchRepository.cs 인터페이스를 생성합니다.

public interface IBranchRepository
{
    Task<IEnumerable<Branch>> GetAllBranches();
    Task<Branch> GetBranchById(int id);
    Task AddBranch(Branch branch);
    Task UpdateBranch(Branch branch);
    Task DeleteBranch(int id);
}

BranchRepository.cs 파일을 생성하고 IBranchRepository 인터페이스를 구현합니다.

public class BranchRepository : IBranchRepository
{
    private readonly ApplicationDbContext _context;

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

    public async Task<IEnumerable<Branch>> GetAllBranches()
    {
        return await _context.Branches.ToListAsync();
    }

    public async Task<Branch> GetBranchById(int id)
    {
        return await _context.Branches.FindAsync(id);
    }

    public async Task AddBranch(Branch branch)
    {
        _context.Branches.Add(branch);
        await _context.SaveChangesAsync();
    }

    public async Task UpdateBranch(Branch branch)
    {
        _context.Branches.Update(branch);
        await _context.SaveChangesAsync();
    }

    public async Task DeleteBranch(int id)
    {
        var branch = await _context.Branches.FindAsync(id);
        if (branch != null)
        {
            _context.Branches.Remove(branch);
            await _context.SaveChangesAsync();
        }
    }
}

Step 4: Branch 서비스 클래스

Services 폴더에 BranchService.cs 파일을 생성하고 다음 코드를 작성합니다.

public class BranchService
{
    private readonly IBranchRepository _repository;

    public BranchService(IBranchRepository repository)
    {
        _repository = repository;
    }

    public async Task<IEnumerable<Branch>> GetAllBranches()
    {
        return await _repository.GetAllBranches();
    }

    public async Task<Branch> GetBranchById(int id)
    {
        return await _repository.GetBranchById(id);
    }

    public async Task AddBranch(Branch branch)
    {
        await _repository.AddBranch(branch);
    }

    public async Task UpdateBranch(Branch branch)
    {
        await _repository.UpdateBranch(branch);
    }

    public async Task DeleteBranch(int id)
    {
        await _repository.DeleteBranch(id);
    }
}

4. MVC 컨트롤러 생성

Step 1: Branches MVC Controller

Controllers 폴더에 BranchesController.cs를 생성하고 다음과 같이 CRUD 액션을 정의합니다.

public class BranchesController : Controller
{
    private readonly BranchService _service;

    public BranchesController(BranchService service)
    {
        _service = service;
    }

    // Index 액션: 지점 목록을 보여주는 페이지
    public async Task<IActionResult> Index()
    {
        var branches = await _service.GetAllBranches();
        return View(branches);
    }
}

5. Web API 컨트롤러 생성

Step 1: BranchesServicesController

Controllers 폴더에 BranchesServicesController.cs 파일을 생성하고, Web API를 이용한 CRUD 작업을 위한 컨트롤러를 작성합니다.

[Route("api/branches")]
[ApiController]
public class BranchesServicesController : ControllerBase
{
    private readonly BranchService _service;

    public BranchesServicesController(BranchService service)
    {
        _service = service;
    }

    // Get all branches
    [HttpGet]
    public async Task<IActionResult> GetAllBranches()
    {
        var branches = await _service.GetAllBranches();
        return Ok(branches);
    }

    // Create a new branch
    [HttpPost]
    public async Task<IActionResult> CreateBranch([FromBody] Branch branch)
    {
        if (ModelState.IsValid)
        {
            await _service.AddBranch(branch);
            return Ok();
        }
        return BadRequest();
    }

    // Get a branch by id
    [HttpGet("{id}")]
    public async Task<IActionResult> GetBranchById(int id)
    {
        var branch = await _service.GetBranchById(id);
        if (branch == null)
        {
            return NotFound();
        }
        return Ok(branch);
    }

    // Edit a branch
    [HttpPut("{id}")]
    public async Task<IActionResult> EditBranch(int id, [FromBody] Branch branch)
    {
        if (id != branch.Id || !ModelState.IsValid)
        {
            return BadRequest();
        }
        await _service.UpdateBranch(branch);
        return Ok();
    }

    // Delete a branch
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteBranch(int id)
    {
        await _service.DeleteBranch(id);
        return Ok();
    }
}

6. jQuery와 Bootstrap 5 모달을 사용한 CSHTML 페이지

Step 1: Index.cshtml 설정

Views/Branches/Index.cshtml 파일을 생성하고 다음과 같이 CreateEdit 모달을 사용한 페이지를 작성합니다.

@model IEnumerable<Branch>

@{
    ViewData["Title"] = "Branches Management";
}

<h2>Branches Management</h2>

<!-- Create Button -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createBranchModal">Add Branch</button>

<table class="table table-striped">
    <thead>
        <tr>
            <th>Branch Name</th>
            <th>Location</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody id="branchesTable">
        @foreach (var branch in Model)
        {
            <tr>
                <td>@branch.BranchName</td>
                <td>@branch.Location</td>
                <td>
                    <button class="btn btn-sm btn-primary editBranch" data-id="@branch.Id">Edit</button>
                    <button class="btn btn-sm btn-danger deleteBranch" data-id="@branch.Id">Delete</button>
                </td>
            </tr>
        }
    </tbody>
</table>

<!-- Create Modal -->
<div class="modal fade" id="createBranchModal" tabindex="-1" aria-labelledby="createBranchModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="createBranchModalLabel">Create Branch</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <form id="createBranchForm">
          <div class="mb-3">
            <label for="branchName" class="form-label">Branch Name</label>
            <input type="text" class="form-control" id="branchName">
          </div>
          <div class="mb-3">
            <label for="location" class="form-label">Location</label>
            <input type="text" class="form-control" id="location">
          </div>
          <div class="mb-3">
            <label for="contactNumber" class="form-label">Contact Number</label>
            <input type="text" class="form-control" id="contactNumber">
          </div>
          <button type="button" class="btn btn-primary" id="saveBranch">Save</button>
        </form>
      </div>
    </div>
  </div>
</div>

<!-- Edit Modal -->
<div class="modal fade" id="editBranchModal" tabindex="-1" aria-labelledby="editBranchModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="editBranchModalLabel">Edit Branch</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <form id="editBranchForm">
          <input type="hidden" id="editBranchId">
          <div class="mb-3">
            <label for="editBranchName" class="form-label">Branch Name</label>
            <input type="text" class="form-control" id="editBranchName">
          </div>
          <div class="mb-3">
            <label for="editLocation" class="form-label">Location</label>
            <input type="text" class="form-control" id="editLocation">
          </div>
          <div class="mb-3">
            <label for="editContactNumber" class="form-label">Contact Number</label>
            <input type="text" class="form-control" id="editContactNumber">
          </div>
          <button type="button" class="btn btn-primary" id="updateBranch">Update</button>
        </form>
      </div>
    </div>
  </div>
</div>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
    $(document).ready(function() {
        // Load all branches
        function loadBranches() {
            $.get('/api/branches', function(data) {
                $('#branchesTable').empty();
                $.each(data, function(i, branch) {
                    $('#branchesTable').append(
                        `<tr>
                            <td>${branch.branchName}</td>
                            <td>${branch.location}</td>
                            <td>
                                <button class="btn btn-sm btn-primary editBranch" data-id="${branch.id}">Edit</button>
                                <button class="btn btn-sm btn-danger deleteBranch" data-id="${branch.id}">Delete</button>
                            </td>
                        </tr>`
                    );
                });
            });
        }

        // Create new branch
        $('#saveBranch').click(function() {
            let branch = {
                BranchName: $('#branchName').val(),
                Location: $('#location').val(),
                ContactNumber: $('#contactNumber').val(),
                IsActive: true
            };

            $.ajax({
                url: '/api/branches',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify(branch),
                success: function() {
                    $('#createBranchForm')[0].reset();      // 폼 재설정
                    $('#createBranchModal').modal('hide');  // 모달 닫기
                    $('body').removeClass('modal-open');    // 모달이 열렸을 때 body에 추가된 클래스 제거
                    $('.modal-backdrop').remove();          // modal-backdrop 제거
                    loadBranches();
                }
            });
        });

        // Load branch for editing
        $(document).on('click', '.editBranch', function() {
            let id = $(this).data('id');

            $.get(`/api/branches/${id}`, function(data) {
                $('#editBranchId').val(data.id);
                $('#editBranchName').val(data.branchName);
                $('#editLocation').val(data.location);
                $('#editContactNumber').val(data.contactNumber);
                $('#editBranchModal').modal('show');
            });
        });

        // Update branch
        $('#updateBranch').click(function() {
            let branch = {
                Id: $('#editBranchId').val(),
                BranchName: $('#editBranchName').val(),
                Location: $('#editLocation').val(),
                ContactNumber: $('#editContactNumber').val(),
                IsActive: true
            };

            $.ajax({
                url: `/api/branches/${branch.Id}`,
                type: 'PUT',
                contentType: 'application/json',
                data: JSON.stringify(branch),
                success: function() {
                    $('#editBranchModal').modal('hide');
                    loadBranches();
                }
            });
        });

        // Delete branch
        $(document).on('click', '.deleteBranch', function() {
            let id = $(this).data('id');

            if (confirm('Are you sure to delete this branch?')) {
                $.ajax({
                    url: `/api/branches/${id}`,
                    type: 'DELETE',
                    success: function() {
                        loadBranches();
                    }
                });
            }
        });

        // 초기 로딩 시 모든 브랜치 데이터를 로드
        loadBranches();
    });
</script>

7. 마무리

  1. Web API를 통해 데이터 CRUD 작업을 수행하고, jQueryBootstrap 5를 사용하여 페이지에서 동적으로 Create, Edit, Delete 작업을 모달 창으로 구현합니다.
  2. 데이터베이스 마이그레이션을 통해 데이터베이스를 설정하고 CRUD 기능을 테스트합니다.
Add-Migration InitBranches
Update-Database

이로써 Branches 테이블에 대한 CRUD 기능을 구현할 수 있으며, Bootstrap 5 모달을 사용하여 사용자가 친숙한 UI에서 지점을 관리할 수 있습니다.

VisualAcademy Docs의 모든 콘텐츠, 이미지, 동영상의 저작권은 박용준에게 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 전재와 복제를 금합니다. 사이트의 콘텐츠를 복제하여 블로그, 웹사이트 등에 게시할 수 없습니다. 단, 링크와 SNS 공유, Youtube 동영상 공유는 허용합니다. www.VisualAcademy.com
박용준 강사의 모든 동영상 강의는 데브렉에서 독점으로 제공됩니다. www.devlec.com