- Video페이지 ER.Core를 이용한 CRUD구현 및 view페이지 생성.
- Edit, Details, Delete 페이지는 /Video/각 페이지/{id}로 라우팅을 설정하고
이동시 id를 넘겨주고 각페이지에서는 id를 기준으로 row를 검색해서 작업 진행.- 소스코드 github경로
- Video테이블의 데이터를 List로 보여줌.
화면
코드(Index.razor)
@page "/Videos"
@page "/Videos/Index"
@inject IVideoRepositoryAsync repository
<h3>상세페이지</h3>
<div>
<a href="/Videos/Create" class="btn btn-primary">Create</a>
</div>
@if (videos == null)
{
<p>Loading...</p>
}
else if (videos.Count == 0)
{
<p>Nodata...</p>
}
else
{
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>URL</th>
<th> </th>
</tr>
</thead>
<tbody>
@foreach (var video in videos)
{
<tr>
<td>@video.Id</td>
<td>@video.Title</td>
<td><a href="@video.Url">@video.Url</a> </td>
<td><a href="/Videos/Details/@video.Id">Details</a></td>
<td><a href="/Videos/Edit/@video.Id">Edit</a></td>
<td><a href="/Videos/Delete/@video.Id">Delete</a></td>
</tr>
}
</tbody>
</table>
}
@code {
List<Video> videos = new List<Video>();
protected override async Task OnInitializedAsync()
{
videos = await repository.GetVideosAsync();
}
}
- 아래 이미지처럼 Created,Modified가 null 허용 및 default값으로 GetDate()를 넣게 되어 있는데 ER core의 문제인지는 모르겠으나 두개의 컬럼에 date값을 넣어 주지 않으면 에러가 발생함.
VideoDbContext.cs에 아래 코드를 추가해 주면 create시 아래와 같이 두개 컬럼에 default값을 지정해서 넣어줄 수 있음.
protected override void OnModelCreating(ModelBuilder modelBuilder) { //[!] vidoes 테이블의 created,modified 열을 자동으로 GetDate() 제약 조건을 부여 함. modelBuilder.Entity<Video>().Property(x => x.Created).HasDefaultValueSql("GetDate()"); modelBuilder.Entity<Video>().Property(x => x.Modified).HasDefaultValueSql("GetDate()"); }
데이터 베이스 스키마
날짜 컬럼에 값을 넣어 주지 않으면 아래와 같은 에러 발생.
입력전
create
create후
url 선택시 url경로가 https://
혹은 http://
를 붙여주지 않으면 아래와 같이
localhost
즉 blazor 페이지에서 라우팅 하게됨. 전체 경로를 넣어줘야 함.
해당 url은 edit 페이지에서 수정 예정.
5.코드( Create.razor)
@page "/Videos/Create"
@inject IVideoRepositoryAsync repository
@inject NavigationManager navigationManager
<h3>Create</h3>
<from>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label for="Title" class="control-label">Title</label>
<input type="text" @bind="@video.Title" class="form-control" />
</div>
<div class="form-group">
<label for="Url" class="control-label">Url</label>
<input type="text" @bind="@video.Url" class="form-control" />
</div>
<div class="form-group">
<label for="Name" class="control-label">Name</label>
<input type="text" @bind="@video.Name" class="form-control" />
</div>
<div class="form-group">
<label for="Company" class="control-label">Company</label>
<input type="text" @bind="@video.Company" class="form-control" />
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<input type="button" id="btnSave" value="Save" @onclick="CreateEvent" />
<input type="button" id="OnCancelEvent" value="Cancel" @onclick="OnCancelEvent" />
</div>
</div>
</from>
@code {
Video video = new Video();
protected async Task CreateEvent()
{
await repository.AddVideoAsync(video);
navigationManager.NavigateTo("/Videos");
}
protected void OnCancelEvent()
{
navigationManager.NavigateTo("/Videos/Index");
}
}
//Install-Package Microsoft.EntityFrameworkCore.SqlServer
//Install-Package System.Configuration.ConfigurationManager
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text;
namespace VideoAppCoreModels
{
public class VideoDbContext : DbContext
{
public VideoDbContext(DbContextOptions<VideoDbContext> options)
: base(options)
{
//공식과 같은코드
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// 닷넷 프레임워크 기반에서 호출되는 코드 영역:
// App.Config 또는 Web.Config의 연결 문자열 사용
if(!optionsBuilder.IsConfigured)
{
string connectionString = ConfigurationManager.ConnectionStrings[
"DefaultConnection"].ConnectionString;
optionsBuilder.UseSqlServer(connectionString);
}
}
/// <summary>
/// 비디오앱
/// </summary>
public DbSet<Video> Videos { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//[!] vidoes 테이블의 created,modified 열을 자동으로 GetDate() 제약 조건을 부여 함.
modelBuilder.Entity<Video>().Property(x => x.Created).HasDefaultValueSql("GetDate()");
modelBuilder.Entity<Video>().Property(x => x.Modified).HasDefaultValueSql("GetDate()");
}
}
}
- url에서 Id값을 받아 해당 row를 Db에서 검색후 수정 기능 구현.
- 위에서 잘못 기재된 url 수정 구현.
- Edit 버튼: 수정 커밋, Delete 버튼 : delete 페이지로 이동, Cancel: index페이지(List 페이지)로 이동.
수정전
수정페이지
데이터 수정 후 edit버튼을 누르면 js기능인 confirm을 띄어 수정 확인을 받고 확인 버튼을 누르면 데이터 수정후 list페이지로 이동.
수정 후
code(Edit.razor)
@page "/Videos/Edit/{id}"
@inject IVideoRepositoryAsync repository
@inject IJSRuntime js
@inject NavigationManager nav
<h3>Edit</h3>
<from>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label>ID</label><br />
@video.Id
<hr />
</div>
<div class="form-group">
<label>TITLE</label><br />
<input type="text" @bind="@video.Title" />
<hr />
</div>
<div class="form-group">
<label>URL</label><br />
<input type="text" @bind="@video.Url" />
<hr />
</div>
<div class="form-group">
<label>NAME</label><br />
<input type="text" @bind="@video.Name" />
<hr />
</div>
<div class="form-group">
<label>CREATED</label><br />
@video.Created
<hr />
</div>
<div>
<input type="button" id="OnEditEvent" @onclick="OnEditEvent" value="Edit" />
<input type="button" id="OnGotoDelete" @onclick="OnGotoDelete" value="Delete" />
<input type="button" id="OnCancelEvent" @onclick="OnCancelEvent" value="Cancel" />
</div>
</div>
</div>
</from>
@code {
Video video = new Video();
int id = 0;
[Parameter]
public string Id { get; set; }
protected override async Task OnInitializedAsync()
{
id = int.Parse(Id);
video = await repository.GetVideoByIdAsync(id);
}
protected async Task OnEditEvent()
{
bool is_check = await js.InvokeAsync<bool>("confirm", "정말 수정 하시겠습니까??");
if (is_check)
{
await repository.UpdateVideoAsync(video);
nav.NavigateTo("/Videos/Index");
}
else
{
await js.InvokeAsync<object>("alert", "취소 되었습니다.");
}
}
protected void OnGotoDelete()
{
nav.NavigateTo($"/Videos/Delete/{Id}");
}
protected void OnCancelEvent()
{
nav.NavigateTo("/Videos/Index");
}
}
- url에서 Id값을 받아 해당 row를 Db에서 검색후 해당 row 삭제 기능.
- 아이디가 7인 row 삭제 예정.
- Delete 버튼: row삭제 커밋, Edit 버튼 : Edit 페이지로 이동, Cancel: index페이지(List 페이지)로 이동.
삭제전
삭제페이지
@page "/Videos/Delete/{id}"
@inject IVideoRepositoryAsync repository
@inject IJSRuntime js
@inject NavigationManager nav
<h3>Delete</h3>
<from>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label>ID</label><br />
@video.Id
<hr />
</div>
<div class="form-group">
<label>TITLE</label><br />
@video.Title
<hr />
</div>
<div class="form-group">
<label>URL</label><br />
@video.Url
<hr />
</div>
<div class="form-group">
<label>NAME</label><br />
@video.Name
<hr />
</div>
<div class="form-group">
<label>CREATED</label><br />
@video.Created
<hr />
</div>
<div>
<input type="button" id="OnDeleteEvent" @onclick="OnDeleteEvent" value="Delete" />
<input type="button" id="OnDeleteEvent" @onclick="OnGotoEdit" value="Edit" />
<input type="button" id="OnCancelEvent" @onclick="OnCancelEvent" value="Cancel" />
</div>
</div>
</div>
</from>
@code {
Video video = new Video();
int id = 0;
[Parameter]
public string Id { get; set; }
protected override async Task OnInitializedAsync()
{
id = int.Parse(Id);
video = await repository.GetVideoByIdAsync(id);
}
protected async Task OnDeleteEvent()
{
bool is_check = await js.InvokeAsync<bool>("confirm", "정말 삭제 하시겠습니까??");
if (is_check)
{
await repository.RemoveVideoAsync(id);
nav.NavigateTo("/Videos/Index");
}
else
{
await js.InvokeAsync<object>("alert", "취소 되었습니다.");
}
}
protected void OnGotoEdit()
{
nav.NavigateTo($"/Videos/Edit/{Id}");
}
protected void OnCancelEvent()
{
nav.NavigateTo("/Videos/Index");
}
}
- url에서 Id값을 받아 해당 row를 Db에서 검색후 해당 row 상세 내역 조회.
- Delete 버튼: delete페이지로 이동, Edit 버튼 : Edit 페이지로 이동, Cancel: index페이지(List 페이지)로 이동.
Details페이지
code(Details.razor)
@page "/Videos/Details/{id}"
@inject IVideoRepositoryAsync repository
@inject IJSRuntime js
<h3>Details</h3>
<from>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label>ID</label><br />
@video.Id
<hr />
</div>
<div class="form-group">
<label>TITLE</label><br />
@video.Title
<hr />
</div>
<div class="form-group">
<label>URL</label><br />
@video.Url
<hr />
</div>
<div class="form-group">
<label>NAME</label><br />
@video.Name
<hr />
</div>
<div class="form-group">
<label>CREATED</label><br />
@video.Created
<hr />
</div>
<div>
<a href="/Videos/Edit/@video.Id">Edit</a>
<a href="/Videos/Delete/@video.Id">Delete</a>
<a href="/Videos/">List</a>
</div>
</div>
</div>
</from>
@code {
Video video = new Video();
int id = 0;
[Parameter]
public string Id { get; set; }
protected override async Task OnInitializedAsync()
{
id = int.Parse(Id);
video = await repository.GetVideoByIdAsync(id);
}
// protected override async Task OnAfterRenderAsync(bool firstRender)
// {
// await InvokeAsync(StateHasChanged);
// }
}