poniedziałek, 23 stycznia 2023

Użycie Sqlite w aplikacji ASP.NET Core API wraz z Entity Framework Core

 W tym poście pokaże, jak łatwo podpiąć się pod bazę Sqlite z projektu ASP.NET Core API. Sqlite nie wymaga instalowania oprogramowania serwera baz danych. Więcej na temat tego kiedy używać Sqlite można przeczytać na oficjalnej stronie.

1. Pierwszym krokiem aby użyć Sqlite wraz z Entity Framework Core jest instalacja odpowiednich nugetów (paczek). Najłatwiej to zrobić za pomocą managera Nuget dostępnego w Visual Studio. Klikamy prawym klawiszem myszy na projekt i następnie wybieramy opcję Manage NuGet Packages...:


Instalujemy następujące paczki:

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Sqlite
  • Microsoft.EntityFrameworkCore.Tools


2. Następny krokiem jest dodanie ConnectionString do ustawień aplikacji. W pliku appsettings.json dodajemy wpis:

  "ConnectionStrings": {
    "DatabaseConnection": "Data Source=books.db"
  }

Pierwszy element to nazwa połączenia, drugi to właściwy ConnectionString. Plik konfiguracyjny będzie wyglądać tak po tej zmianie:


3. Jako, że mamy podejście Code First (czyli najpierw piszemy kod a na jego podstawie generujemy bazę danych) - tworzymy klasę modelu. Przykładowo klasa Book:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace BookStoreApi.Models;

public class Book
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    public string Author { get; set; }

    public int PublishYear { get; set; }

    public DateTime CreateDate { get; set; }
}

Na pole Id oraz Name nałożone są dodatkowe atrybuty:

  • Key - identyfikuje pole, które będzie kluczem głównym dla tabeli
  • DatabaseGeneratedOption.Identity - podczas tworzenia wiersza w bazie, baza danych automatycznie wygeneruje jego wartość (w tym przypadku klucz jest typu int więc będzie to kolejna wartość sekwencji)
  • Required - identyfikuje kolumnę, która musi zostać wypełniona aby wiersz został dodany do tabeli

Możliwych atrybutów oczywiście jest znacznie więcej. Dla potrzeby tego przykładu nie będzie użytych więcej. 


4. Tworzymy klasę odpowiedzialną za połączenie z bazą danych, tzw. DbCotext

using BookStoreApi.Models;
using Microsoft.EntityFrameworkCore;

namespace BookStoreApi.Data;

public class BookStoreDbContext : DbContext
{
    public DbSet<Book> Books { get; set; }

    public BookStoreDbContext(DbContextOptions<BookStoreDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Book>().HasData(
            new()
            {
                Id = 1,
                Name =
                    "C#: 3 books in 1 - The Ultimate Beginner, Intermediate & Advanced Guides to Master C# Programming Quickly with No Experience",
                Author = "Mark Reed",
                PublishYear = 2022,
                CreateDate = new DateTime(2023, 1, 1)
            },
            new()
            {
                Id = 2, Name = "C++ For Dummies 7th Edition", Author = "Stephen R. Davis", PublishYear = 2014,
                CreateDate = new DateTime(2023, 1, 2)
            },
            new()
            {
                Id = 3,
                Name = "How to Make a Video Game All By Yourself: 10 steps, just you and a computer",
                Author = "Matt Hackett",
                PublishYear = 2022,
                CreateDate = new DateTime(2023, 1, 3)
            });
    }
}

Metoda OnModelCreating nie jest obowiązkowa w implementacji. Pozwala zainicjować początkowe dane w bazie, co może nam się przydać do testów, jak i również możemy za jej pomocą wprowadzić dane słownikowe.  


5. Kolejnym etapem jest rejestracja DBContext w kontenerze DI (Dependency Injection). Rejestracji dokonujemy w pliku Program.cs:

// Add services to the container.

builder.Services.AddDbContext<BookStoreDbContext>(option =>
    option.UseSqlite(builder.Configuration.GetConnectionString("DatabaseConnection")));


6. Stworzymy teraz przykładową akcję pobierająca książki z bazy danych. 

[ApiController]
[Route("api/[controller]")]
public class BookStoreController : ControllerBase
{
    private readonly BookStoreDbContext _bookStoreDbContext;

    public BookStoreController(BookStoreDbContext bookStoreDbContext)
    {
        _bookStoreDbContext = bookStoreDbContext;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<BookDto>>> GetBooks()
    {
        return Ok(await _bookStoreDbContext.Books.ToListAsync());
    }
}


7. Od strony kodu, mamy już wszystko co jest potrzebne. Kolejne kroki stworzą naszą bazę danych. Otwieramy Package Manager Console (View -> Other Windows -> Package Manager Console) 



8. W konsoli wprowadzamy komendę add-migration migration_name przykładowo:

add-migration CreateBookDatabase


Jeżeli komenda zakończy się sukcesem powinniśmy zobaczyć nowy katalog w naszym projekcie nazwany Migrations


9. Teraz przejdziemy do właściwego utworzenia bazy danych. Po stworzeniu migracji, musimy zaaplikować zmiany do bazy danych (niezależnie czy jest to Sqlite czy inny silnik bazodanowy). Służy do tego komenda update-database:



10. Wszystko! Możemy uruchomić projekt i zobaczyć w akcji jak działa połączenie z naszą bazą danych:



Brak komentarzy:

Prześlij komentarz