연습 - Blazor 구성 요소에서 데이터 액세스

완료됨

앱의 현재 하드 코딩된 피자는 데이터베이스로 바꿔야 합니다. Microsoft Entity Framework를 사용하여 데이터 원본에 대한 연결을 추가할 수 있습니다. 이 앱에서는 SQLite 데이터베이스를 사용하여 피자를 저장합니다.

이 연습에서는 데이터베이스 기능을 지원하는 패키지를 추가하고, 클래스를 백 엔드 데이터베이스에 연결하고, 도우미 클래스를 추가하여 회사의 피자에 대한 데이터를 미리 로드합니다.

데이터베이스 액세스를 지원하는 패키지 추가

  1. 앱이 계속 실행 중인 경우 중지합니다.

  2. Visual Studio Code에서 터미널>새 터미널을 선택합니다.

  3. 새 터미널에서 위치를 BlazingPizza 디렉터리로 설정합니다.

    cd BlazingPizza
    
  4. 다음 명령을 실행하여 Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.SqliteSystem.Net.Http.Json 패키지를 추가합니다.

    dotnet add package Microsoft.EntityFrameworkCore --version 9.0.0
    dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 9.0.0
    dotnet add package System.Net.Http.Json --version 9.0.0
    

    다음 명령은 BlazingPizza.csproj 파일에 패키지 참조를 추가합니다.

      <ItemGroup>
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0-*" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-*" />
        <PackageReference Include="System.Net.Http.Json" Version="9.0.0-*" />
      </ItemGroup>
    

데이터베이스 컨텍스트 추가

  1. Visual Studio Code에서 BlazingPizza 폴더에 새 폴더를 만듭니다. 데이터 이름을 지정합니다.

  2. 데이터 폴더에서 PizzaStoreContext.cs이라는 새 파일을 만듭니다.

  3. 새 파일에서 클래스에 대해 다음 코드를 입력합니다.

    using Microsoft.EntityFrameworkCore;
    
    namespace BlazingPizza.Data;
    
    public class PizzaStoreContext : DbContext
    {
        public PizzaStoreContext(DbContextOptions options) : base(options)
        {
        }
    
        public DbSet<PizzaSpecial> Specials { get; set; }
    }    
    

    이 클래스는 데이터베이스 서비스를 등록하는 데 사용할 수 있는 데이터베이스 컨텍스트를 만듭니다. 컨텍스트를 사용하면 데이터베이스에 액세스하는 컨트롤러를 가질 수도 있습니다.

  4. Ctrl+S를 사용하여 변경 내용을 저장합니다.

컨트롤러 추가

  1. BlazingPizza 폴더에 새 폴더를 만듭니다. 이름을 'Controllers'로 하세요.

  2. Controllers 폴더에 새 파일을 만듭니다. 이름을 SpecialsController.cs로 지정하세요.

  3. 클래스에 대해 다음 코드를 입력합니다.

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using BlazingPizza.Data;
    
    namespace BlazingPizza.Controllers;
    
    [Route("specials")]
    [ApiController]
    public class SpecialsController : Controller
    {
        private readonly PizzaStoreContext _db;
    
        public SpecialsController(PizzaStoreContext db)
        {
            _db = db;
        }
    
        [HttpGet]
        public async Task<ActionResult<List<PizzaSpecial>>> GetSpecials()
        {
            return (await _db.Specials.ToListAsync()).OrderByDescending(s => s.BasePrice).ToList();
        }
    }
    

    이 클래스는 데이터베이스에서 피자 스페셜을 쿼리하고 URL에서 JSON으로 반환할 수 있는 컨트롤러를 (http://localhost:5000/specials) 만듭니다.

  4. 변경 내용을 저장합니다.

데이터베이스에 데이터 로드

앱은 기존 SQLite 데이터베이스가 있는지 확인하고 미리 만든 피자가 있는 데이터베이스를 만듭니다.

  1. 데이터 디렉터리에 새 파일을 만듭니다. SeedData.cs로 이름을 지정하세요.

  2. 클래스에 대해 다음 코드를 입력합니다.

    namespace BlazingPizza.Data;
    
    public static class SeedData
    {
        public static void Initialize(PizzaStoreContext db)
        {
            var specials = new PizzaSpecial[]
            {
                new PizzaSpecial()
                {
                    Name = "Basic Cheese Pizza",
                    Description = "It's cheesy and delicious. Why wouldn't you want one?",
                    BasePrice = 9.99m,
                    ImageUrl = "img/pizzas/cheese.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 2,
                    Name = "The Baconatorizor",
                    Description = "It has EVERY kind of bacon",
                    BasePrice = 11.99m,
                    ImageUrl = "img/pizzas/bacon.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 3,
                    Name = "Classic pepperoni",
                    Description = "It's the pizza you grew up with, but Blazing hot!",
                    BasePrice = 10.50m,
                    ImageUrl = "img/pizzas/pepperoni.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 4,
                    Name = "Buffalo chicken",
                    Description = "Spicy chicken, hot sauce and bleu cheese, guaranteed to warm you up",
                    BasePrice = 12.75m,
                    ImageUrl = "img/pizzas/meaty.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 5,
                    Name = "Mushroom Lovers",
                    Description = "It has mushrooms. Isn't that obvious?",
                    BasePrice = 11.00m,
                    ImageUrl = "img/pizzas/mushroom.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 7,
                    Name = "Veggie Delight",
                    Description = "It's like salad, but on a pizza",
                    BasePrice = 11.50m,
                    ImageUrl = "img/pizzas/salad.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 8,
                    Name = "Margherita",
                    Description = "Traditional Italian pizza with tomatoes and basil",
                    BasePrice = 9.99m,
                    ImageUrl = "img/pizzas/margherita.jpg",
                },
            };
            db.Specials.AddRange(specials);
            db.SaveChanges();
        }
    }
    

    클래스는 전달된 데이터베이스 컨텍스트를 사용하고 배열에 일부 PizzaSpecial 개체를 만든 다음 저장합니다.

  3. 파일 탐색기에서 Program.cs 선택합니다.

  4. 맨 위에 새 PizzaStoreContext참조를 추가합니다.

    using BlazingPizza.Data;
    

    이 문을 사용하면 앱에서 새 서비스를 사용할 수 있습니다.

  5. 메서드 위에 이 세그먼트를 삽입합니다 app.Run(); .

    // Initialize the database
    var scopeFactory = app.Services.GetRequiredService<IServiceScopeFactory>();
    using (var scope = scopeFactory.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<PizzaStoreContext>();
        if (db.Database.EnsureCreated())
        {
            SeedData.Initialize(db);
        }
    }
    
    app.Run();
    

    이 변경으로 인해 데이터베이스 범위 PizzaStoreContext가 만들어집니다. 데이터베이스가 아직 만들어지지 않은 경우 정적 클래스를 SeedData 호출하여 데이터베이스를 만듭니다.

  6. 현재 앱은 아직 초기화되지 않았기 때문에 PizzaStoreContext 작동하지 않습니다. Program.cs 파일에서 현재 서비스(시작하는 builder.Services.줄) 아래에 다음 코드를 추가합니다.

      builder.Services.AddHttpClient();
      builder.Services.AddSqlite<PizzaStoreContext>("Data Source=pizza.db");
    
    

    이 코드는 두 서비스를 등록합니다. 첫 번째 AddHttpClient 문을 사용하면 앱이 HTTP 명령에 액세스할 수 있습니다. 앱은 HttpClient를 사용하여 피자 스페셜용 JSON을 가져옵니다. 두 번째 문은 새 PizzaStoreContext 문을 등록하고 SQLite 데이터베이스의 파일 이름을 제공합니다.

데이터베이스를 사용하여 피자 표시

이제 Index.razor 페이지에서 하드 코딩된 피자를 바꿀 수 있습니다.

  1. 파일 탐색기에서 페이지를 확장한 다음 Index.razor를 선택합니다.

  2. 기존 OnInitialized() 메서드를 다음으로 바꿉다.

    protected override async Task OnInitializedAsync()
    {
        specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
    }
    

    Note

    이 코드는 OnInitialized()OnInitializedAsync()으로 대체합니다. 이제 특수 항목이 앱에서 JSON으로 비동기적으로 반환됩니다.

  3. 해결해야 하는 몇 가지 오류가 있습니다. @inject 지시문 아래에 @page 문을 추가합니다.

    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
  4. 모든 변경 내용을 저장한 다음 F5 키를 선택하거나 실행을 선택합니다. 그런 다음 , 디버깅 시작을 선택합니다.

    앱을 실행할 때 런타임 오류가 발생합니다. JsonReader가 예외를 발생시켰습니다.

  5. 앱에서는 (http://localhost:5000/specials)에서 JSON을 생성하고 있어야 합니다. 해당 URL로 이동합니다.

    앱은 이 요청을 라우팅하는 방법을 모릅니다. Blazor 라우팅의 모듈에서 라우팅에 대해 알아봅니다. 이제 오류를 해결해 보겠습니다.

  6. Shift + F5를 선택하거나 디버깅 중지를 선택합니다.

  7. 파일 탐색기에서 Program.cs 선택합니다.

  8. 파일 가운데에서 시작하는 app.줄 뒤 이 엔드포인트를 추가합니다.

    app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    

    이제 코드는 다음과 같습니다.

    ...
    app.MapRazorPages();
    app.MapBlazorHub();
    app.MapFallbackToPage("/_Host");
    app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    ...
    
  9. F5 키를 선택하거나 실행을 선택합니다. 그런 다음 , 디버깅 시작을 선택합니다.

    이제 앱이 작동하지만 JSON이 올바르게 생성되고 있는지 확인해 보겠습니다.

  10. 다음을 확인하려면 (http://localhost:5000/specials)로 이동하세요.

    피자에 대한 JSON을 보여 주는 브라우저를 보여 주는 스크린샷

    JSON에는 특수 피자 컨트롤러에 지정된 대로 내림차순으로 나열된 피자가 있습니다.

    더욱 타오르는 피자를 보여주는 스크린샷.