- 바코드 생성하기
- javascript 바코드 생성
- 바코드 스캔하기
- javascript 바코드스캔
- ViewBag
- SSD 복사
- 하드 윈도우 복사
- 말줄임표시
- 타임피커
- Mac Oracle
- ASP.Net Core 404
- jquery 바코드
- 404에러페이지
- ViewData
- 맥 오라클설치
- TempData
- django 엑셀불러오기
- asp.net Select
- XSS방어
- 파일업로드 유효성체크
- jquery 바코드생성
- asp.net core Select
- javascript 유효성체크
- XSS PHP
- javascript redirection
- 하드 마이그레이션
- 파일업로드 체크
- asp.net dropdownlist
- php 캐쉬제거
- 강제이동
웹개발자의 기지개
[ASP.NET Core MVC] 두개의 Select문 만들기 (시도, 구군 주소 선택하기) - 비동기식(Async), Entity Framework 이용 본문
[ASP.NET Core MVC] 두개의 Select문 만들기 (시도, 구군 주소 선택하기) - 비동기식(Async), Entity Framework 이용
http://portfolio.wonpaper.net 2022. 12. 14. 00:17[ASP.NET Core MVC] 두개의 Select문 만들기 (시도, 구군 주소 선택하기) - Dapper 이용
Dapper 를 이용한 방식은 앞전 포스팅에서 올려놓았는데,
이번에는 EF 를 이용해서 동일한 방식으로 만들어 보았다.
[ appsettings.json ] - DB 연결자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionString": {
"AppDb": "Server=DESKTOP-ASIDMUS;Database=MyDB2;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"ConnectionStrings": "Server=DESKTOP-ASIDMUS;Database=IdeaApp;Trusted_Connection=True;MultipleActiveResultSets=true"
}
|
cs |
10라인과 11라인의 MyDB2 디비를 연결하여 작업한다.
[ Startup.cs ] - 닷넷3.1 버전으로 예제가 진행함으로 이 파일에서 환경설정한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MyMVCTest1.Models;
using MyMVCTest1.Models.AddressPkg;
using MyMVCTest1.Models.Buyers;
using MyMVCTest1.Models.Context;
using MyMVCTest1.Models.Product;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyMVCTest1
{
public class Startup
{
private IWebHostEnvironment environment;
//private IConfiguration config = null;
public Startup(IWebHostEnvironment environment, IConfiguration configuration)
{
this.environment = environment;
Configuration = configuration;
//this.config = configuration;
}
public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
// 세션추가
services.AddSession(options => {
// 세션 유지 시간
options.IdleTimeout = TimeSpan.FromSeconds(30);
});
services.AddControllersWithViews();
services.AddSingleton<IConfiguration>(Configuration);
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetSection("ConnectionString").GetSection("AppDb").Value));
// AddressSido 종속성 주입
services.AddTransient<IAddressSido, AddressSidoRepository>();
// AddressSido 종속성 주입 (EF) - 비동기방식
services.AddTransient<IAddressSidoEF, AddressSidoRepositoryEF>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
// 세션사용
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
|
cs |
46라인에서 DbContext 를 서비스에 추가한다.
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetSection("ConnectionString").GetSection("AppDb").Value));
52,53라인에서 이번에는 EF 형태로 서비스를 등록하여준다. (종속성주입)
// AddressSido 종속성 주입 (EF) - 비동기방식
services.AddTransient<IAddressSidoEF, AddressSidoRepositoryEF>();
EF를 위해 실제 DbContext 를 만든다.
필자는 별도의 새프로젝트로 MyMVCTest1.Models 클래스 라이브러리를 만들고,
이안에 폴더별로 구분하여 모아놓았다.
[ MyMVCTest1.Models.Context / AppDbContext.cs ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
using Microsoft.EntityFrameworkCore;
using MyMVCTest1.Models.AddressPkg;
using MyMVCTest1.Models.EF;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace MyMVCTest1.Models.Context
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<AddressSido> AddressSidos { get; set; }
}
}
|
cs |
[ MyMVCTest1.Models.AddressPkg / AddressSido.cs ] - 기본 테이블 클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace MyMVCTest1.Models.AddressPkg
{
[Table("zipcode1")]
public class AddressSido
{
[Key]
[Column("no")]
public int Id { get; set; }
public string Si { get; set; }
public string Gu { get; set; }
}
}
|
cs |
9 라인처럼 테이블명을 zipcode1 로 데코레이션해 놓았다.
그리고, 13 라인처럼 클래스에서는 public int Id 이지만 실제 테이블에는 'no' 칼럼명이라 이를 데코레이션 처리해 놓았다.
[ MyMVCTest1.Models.AddressPkg / IAddressSidoEF.cs ] - 인터페이스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace MyMVCTest1.Models.AddressPkg
{
public interface IAddressSidoEF
{
Task<List<string>> GetAllAsync();
Task<List<AddressSido>> GetAllAsync(string si);
Task<AddressSido> GetAsync(string si, string gu);
}
}
|
cs |
[ MyMVCTest1.Models.AddressPkg / AddressSidoRepositoryEF.cs ] - 리포지터리 클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
using Microsoft.EntityFrameworkCore;
using MyMVCTest1.Models.Context;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MyMVCTest1.Models.AddressPkg
{
public class AddressSidoRepositoryEF : IAddressSidoEF
{
private readonly AppDbContext db = null;
public AddressSidoRepositoryEF(AppDbContext db)
{
this.db = db;
}
public async Task<List<string>> GetAllAsync()
{
// select distinct(si) from zipcode1
return await db.AddressSidos.Select(s => s.Si).Distinct().ToListAsync(); // return Task<List<string>>
}
public async Task<List<AddressSido>> GetAllAsync(string si)
{
// select * from zipcode1 where si='서울' --> 강동구, 서초구 ... (gu)
return await (from num in db.AddressSidos.Where(s => s.Si == si) select num).ToListAsync();
}
public async Task<AddressSido> GetAsync(string si, string gu)
{
return await db.AddressSidos.SingleOrDefaultAsync(s => s.Si == si && s.Gu == gu);
}
}
}
|
cs |
15라인 처럼 생성자 종속성 주입을 AppDbContext 를 넣어 db 형태로 어디서든지 이용하면 된다.
본 예제는 async 형태로 비동기 기법으로 코딩해 보았다.
그래서, 관련 메소드 마다. async Task<> 와 await 단어들이 보인다.
그릭고, 20라인의 async Task<List<string>> GetAllAsync() 처럼 List<string> 형태로 string 형임을 주의하자.
zipcode 에서 distinct 하여 시도 부분을 묶어버리면 string List 형태가 되도록했다.
이를 24라인처럼
return await db.AddressSidos.Select(s => s.Si).Distinct().ToListAsync();
LINQ 기법으로 코딩해 보았다.
이번에는 실제 Controller 와 View 파일들을 만들어보자.
[ Controllers / AddressPkgEFController.cs ] - Controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
using Microsoft.AspNetCore.Mvc;
using MyMVCTest1.Models.AddressPkg;
using System.Threading.Tasks;
namespace MyMVCTest1.Controllers
{
public class AddressPkgEFController : Controller
{
private IAddressSidoEF addressSidoRepositoryEF;
public AddressPkgEFController(IAddressSidoEF addressSidoRepositoryEF)
{
this.addressSidoRepositoryEF = addressSidoRepositoryEF;
}
[HttpGet]
public async Task<IActionResult> ListType1(string sido)
{
if (sido == null) {
var sidoList = await addressSidoRepositoryEF.GetAllAsync();
ViewBag.SidoList = sidoList;
} else {
var sidoList = await addressSidoRepositoryEF.GetAllAsync();
var gugunList = await addressSidoRepositoryEF.GetAllAsync(sido);
ViewBag.SidoList = sidoList;
ViewBag.GugunList = gugunList;
}
return View();
}
}
}
|
cs |
16 라인처럼 HttpGet 방식으로 ListType1 확장메소드에서 실제 View 파일에서 sido(시도값) 이 있을때 없을때로
구분하여 마술상자인(?) ViewBag 에 각각 생성하여 넣어 주고 있다.
이 ViewBag 은 실제 ListType1.cshtml 페이지에서 시도와 구군 Select 박스에서 Foreach 형태로 뿌려준다.
[ Views / AddressPkgEF / ListType1.html ] - Vivew 페이지
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
@using MyMVCTest1.Models.AddressPkg
@using Microsoft.AspNetCore.Http
<form name="f" method="post">
<h2>주소 (시도 / 구군)</h2>
<br />
<label for="sido">시도</label>
<select id="sido" name="sido" class="form-control" onchange="sidoChg()">
<option value="">= 시도 =</option>
@foreach (var sido in ViewBag.SidoList)
{
@if (Context.Request.Query["sido"].ToString() == sido)
{
<option value="@sido" selected>@sido</option>
}
else
{
<option value="@sido">@sido</option>
}
}
</select>
<br /><br />
<label for="gugun">구군</label>
<select id="gugun" name="gugun" class="form-control">
@if (ViewBag.GugunList == null)
{
<option value="">= 구군 =</option>
}
else
{
@foreach (var gugun in ViewBag.GugunList)
{
<option value="@gugun.Gu">@gugun.Gu</option>
}
}
</select>
</form>
<script>
function sidoChg() {
var form = document.f;
var sido = form.sido.value;
location.href = "?sido=" + sido;
}
</script>
|
cs |
조은 참고 사이트1 : https://www.learnentityframeworkcore.com/dbset/querying-data
조은 참고 사이트2 : https://www.simplilearn.com/tutorials/asp-dot-net-tutorial/c-hash-linq-distinct
조은 참고 사이트3 :
https://www.codeproject.com/Articles/535374/DistinctBy-in-Linq-Find-Distinct-object-by-Propert