- Async Repository 인터 페이스 를 상속 받은 dapper, Er Core , ADO.Net
구현 클래스 생성- 서비스에서 IVideoRepository를 구현한 각 클랙스로 데이터 Read 테스트.
- 아래코드 git주소
using System.Collections.Generic;
using System.Threading.Tasks;
namespace VideoAppCoreModels
{
/// <summary>
/// [3] CRUD API 명세서 정의
/// </summary>
public interface IVideoRepositoryAsync
{
Task<Video> AddVideoAsync(Video model); //입력 : T Add(T model);
Task<List<Video>> GetVideosAsync(); //출력 : List<T> GetAll();
Task<Video> GetVideoByIdAsync(int id); //상세 : T GetById(int id);
Task<Video> UpdateVideoAsync(Video model); //수정 : T Edit(T model);
Task RemoveVideoAsync(int id); //삭제 : T VideoDelete(int id);
}
}
- IVideoRepositoryAsync를 상속받은 ADO.NET을 이용한 DB연결 구현
- 가장 손이 많이감... ADO.NET > dapper > ER CORE로 갈수록 코드량이 확연히 줄어듬.
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;
namespace VideoAppCoreModels
{
/// <summary>
/// [4] 리포지토리 클래스 Ado.Net을 사용 하여 CRUD 구현
/// </summary>
public class VideoRepositoryAdoNetAsync : IVideoRepositoryAsync
{
private readonly string connectionString;
public VideoRepositoryAdoNetAsync(string connectionString)
{
this.connectionString = connectionString;
}
public async Task<Video> AddVideoAsync(Video model)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
//select cast(SCOPE_IDENTITY() As Int)은 add 할때 자동으로 들어간 id값을 가지고 오기 위함.
const string query =
@"insert into Videos(Title, Url,Name, Company, CreateBy) Values(@Title,@Url,@Name,@Company,@CreateBy);
select cast(SCOPE_IDENTITY() As Int);";
SqlCommand cmd = new SqlCommand(query, con) { CommandType = CommandType.Text };
cmd.Parameters.AddWithValue("@Title", model.Title);
cmd.Parameters.AddWithValue("@Url", model.Url);
cmd.Parameters.AddWithValue("@Name", model.Name);
cmd.Parameters.AddWithValue("@Company", model.Company);
cmd.Parameters.AddWithValue("@CreateBy", model.CreateBy);
con.Open();
object result = await cmd.ExecuteScalarAsync();
if (int.TryParse(result.ToString(), out int id))
{
model.Id = id;
}
con.Close();
}
return model;
}
public async Task<Video> GetVideoByIdAsync(int id)
{
Video video = new Video();
using (SqlConnection con = new SqlConnection(this.connectionString))
{
const string query = "select * from Videos where id = {@id}";
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.AddWithValue("@id", id);
con.Open();
/*
* dr.GetInt32(0); 첫번째 컬럼을 가지고 와서 int 형으로 변환
* dr["url"] 컬럼명으로 데이터를 가지고 옴.
*/
SqlDataReader dr = await cmd.ExecuteReaderAsync();
if (dr.Read())
{
video.Id = dr.GetInt32(0);
video.Title = dr["title"].ToString();
video.Url = dr["url"].ToString();
video.Name = dr["name"].ToString();
video.Company = dr["Company"].ToString();
video.CreateBy = dr["CreateBy"].ToString();
video.Created = Convert.ToDateTime(dr["created"]);
}
con.Close();
}
return video;
}
public async Task<List<Video>> GetVideosAsync()
{
List<Video> videos = new List<Video>();
using (SqlConnection con = new SqlConnection(this.connectionString))
{
const string query = "select * from Videos ";
SqlCommand cmd = new SqlCommand(query, con)
{
CommandType = CommandType.Text
};
con.Open();
SqlDataReader dr = await cmd.ExecuteReaderAsync();
while (dr.Read())
{
Video video = new Video();
video.Id = dr.GetInt32(0);
video.Title = dr["title"].ToString();
video.Url = dr["url"].ToString();
video.Name = dr["name"].ToString();
video.Company = dr["Company"].ToString();
video.CreateBy = dr["CreateBy"].ToString();
video.Created = Convert.ToDateTime(dr["created"]);
videos.Add(video);
}
con.Close();
}
return videos;
}
public async Task RemoveVideoAsync(int id)
{
using (SqlConnection con = new SqlConnection(this.connectionString))
{
const string query = "delete Videos where Id = @id";
SqlCommand cmd = new SqlCommand(query, con)
{
CommandType = CommandType.Text
};
cmd.Parameters.AddWithValue("id",id);
con.Open();
await cmd.ExecuteNonQueryAsync();
con.Close();
}
}
public async Task<Video> UpdateVideoAsync(Video model)
{
using (SqlConnection con = new SqlConnection(this.connectionString))
{
const string query = @"update Videos
set
Title = @Title,
Url = @Url,
Name = @Name,
Company = @Company,
ModifiedBy = @ModifiedBy
where Id = @id";
SqlCommand cmd = new SqlCommand(query, con)
{
CommandType = CommandType.Text
};
cmd.Parameters.AddWithValue("@Id", model.Id);
cmd.Parameters.AddWithValue("@Title", model.Title);
cmd.Parameters.AddWithValue("@Url", model.Url);
cmd.Parameters.AddWithValue("@Company", model.Company);
cmd.Parameters.AddWithValue("@ModifiedBy", model.ModifiedBy);
con.Open();
await cmd.ExecuteNonQueryAsync();
con.Close();
}
return model;
}
}
}
- IVideoRepositoryAsync를 상속받은 Dapper을 이용한 DB연결 구현
- Dapper를 사용하려면 누겟패키지에서 Dapper를 설치 해야 합니다.
using Dapper;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;
namespace VideoAppCoreModels
{
public class VideoRepositoryDapperAsync : IVideoRepositoryAsync
{
private readonly SqlConnection db;
public VideoRepositoryDapperAsync(string connectionString)
{
this.db = new SqlConnection( connectionString);
}
public async Task<Video> AddVideoAsync(Video model)
{
const string query =
@"insert into Videos(Title, Url,Name, Company, CreateBy) Values(@Title,@Url,@Name,@Company,@CreateBy);
select cast(SCOPE_IDENTITY() As Int);";
int id = await db.ExecuteScalarAsync<int>(query,model);
model.Id = id;
return model;
}
public async Task<Video> GetVideoByIdAsync(int id)
{
const string query = "select * from Videos where Id = @id";
var video = await db.QueryFirstOrDefaultAsync<Video>(query,new {id}, commandType : System.Data.CommandType.Text);
return video;
}
public async Task<List<Video>> GetVideosAsync()
{
const string query = "select * from Videos";
var videos = await db.QueryAsync<Video>(query);
return videos.ToList();
}
public async Task RemoveVideoAsync(int id)
{
const string query = "delete Videos where Id = @id";
await db.ExecuteAsync(query, new { id }, commandType: System.Data.CommandType.Text);
}
public async Task<Video> UpdateVideoAsync(Video model)
{
const string query = @"update Videos
set
Title = @Title,
Url = @Url,
Name = @Name,
Company = @Company,
ModifiedBy = @ModifiedBy
where Id = @id";
await db.ExecuteAsync(query, model);
return model;
}
}
}
- IVideoRepositoryAsync를 상속받은 ER.CORE를 이용한 DB연결 구현
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace VideoAppCoreModels
{
/// <summary>
/// [4] 리포지토리 클래스 Er Core를 사용 하여 CRUD 구현
/// </summary>
public class VideoRepositoryErCoreAsync : IVideoRepositoryAsync
{
private readonly VideoDbContext context;
public VideoRepositoryErCoreAsync(VideoDbContext context)
{
this.context = context;
}
public async Task<Video> AddVideoAsync(Video model)
{
context.Videos.Add(model);
await context.SaveChangesAsync();
return model;
}
public async Task<Video> GetVideoByIdAsync(int id)
{
return await context.Videos.FindAsync(id);
}
public async Task<List<Video>> GetVideosAsync()
{
return await context.Videos.ToListAsync();
}
public async Task RemoveVideoAsync(int id)
{
var video = await context.Videos.FindAsync(id);
if(video != null)
{
context.Videos.Remove(video);
}
}
public async Task<Video> UpdateVideoAsync(Video model)
{
context.Entry(model).State = EntityState.Modified;
await context.SaveChangesAsync();
return model;
}
}
}
builder.Services.AddSingleton(connectionString);
를 추가해야
ADO.NET,Dapper 사용 가능. 생성자에서String
의 connectionString을 받기 떄문.
Er.Core는 기존에builder.Services.AddDbContext<VideoDbContext>(options => options.UseSqlServer(connectionString));
코드를 추가했기때문에 문제되지 않음.- view화면에서 IVideoRepositoryAsync를 Inject시켜주고 해당 repository를 사용하여 조회 기능 테스트.
- view는 변경을 하지 않고 program.cs에서 서비스에 등록하는 class만 변경해 주면 컨터이너에서 해당하는 repository를 자동으로 주입해 줌.
@page "/Videos/FrmDbContextTest"
@using VideoAppCoreModels;
@inject VideoDbContext videoDbContext
@inject IVideoRepositoryAsync repository
<h3>FrmDbContextTest</h3>
@if(videos is null)
{
<text>...</text>
}
else
{
<ul>
@foreach (var video in videos)
{
<li>@video.Title, @video.Url</li>
}
</ul>
}
@code {
List<Video> videos;
protected override void OnInitialized()
{
// videos = videoDbContext.Videos.ToList();
}
protected override async Task OnInitializedAsync()
{
videos = await repository.GetVideosAsync();
}
}
2.Dapeer
테스트를 해 보면 알겠지만 항상 같은 출력값이 나오며
이미지 상에서 조사식중 repository에 값을 확인해 보면 주입되는 repository가 변경되는것을 알 수 있습니다.
추가로 서비스 수명 관련 내용 추가합니다.
매번 인스턴스를 새로 생성하기 때문에 모든 값은 초기값으로 설정됩니다.
클라이언트 요청당 한번 생성이 되며, 해당 연결이 유지되면 지속적으로 사용합니다.
요청 내에서 상태를 유지하려는 경우 좋습니다.
인스턴스 하나로 지속적으로 재활용합니다.
어플리케이션 전체 상태를 유지해야 하는 경우 싱클톤을 사용하십시오.