Budowanie API CRUD za pomocą Dappera

Budowanie API CRUD za pomocą Dappera

Dapper jest obecnie uznawany za najpopularniejszy mikro-ORM ze względu na swoją znakomitą wydajność. ORM-y (Object Relational Mappers) znacznie upraszczają tworzenie aplikacji, które wymagają połączeń z bazami danych i trwałości danych, oferując zasoby umożliwiające mapowanie obiektów i generowanie struktury bazy danych za pomocą kilku poleceń. Jednakże tradycyjne ORM-y często nie są zbyt wydajne. Mikro-ORM-y, takie jak Dapper, koncentrują się na wydajności, oferując minimalne zasoby w porównaniu do konwencjonalnych ORM-ów.

Dapper skupia się na podstawowych operacjach CRUD (Create, Read, Update, Delete) i mapowaniu obiektów na dane w tabeli bazy danych.

Zalety Dappera:

  • Wydajność: Dapper jest niezwykle szybki, co czyni go idealnym wyborem dla aplikacji wymagających dużej ilości operacji na danych.
  • Prostota: Dapper posiada prosty i łatwy do nauczenia interfejs API.
  • Elastyczność: Pozwala na pełną kontrolę nad zapytaniami SQL, dając programistom większą swobodę w dostępie do danych.
  • Lekkość: Dapper jest mikro-ORMem, co oznacza, że ma niewielki wpływ na wydajność aplikacji.

Wady Dappera:

  • Ograniczona funkcjonalność: Dapper nie posiada niektórych zaawansowanych funkcji tradycyjnych ORM-ów, takich jak automatyczne generowanie bazy danych.
  • Większa odpowiedzialność programisty: Programista musi napisać więcej kodu w porównaniu do tradycyjnych ORM-ów.

W tym poście zgłębimy szczegóły dotyczące Dappera i pokażemy, jak zaimplementować pełny CRUD w aplikacji .NET za pomocą tego wydajnego mikro-ORM-a.

Co to jest Micro-ORM?

ORM (obiektowo-relacyjne mapowanie) jest technologią służącą do tworzenia obiektów w kodzie klienta, które odwzorowują relacyjną bazę danych, oferując zaawansowane funkcje, takie jak buforowanie obiektów i wykonywanie zapytań. Mikro-ORM zachowuje istotę ORM, ale oferuje mniej funkcji niż pełnoprawne ORM-y.

Mikro-ORM skupia się na podstawowych funkcjach mapowania obiektów na dane w bazie danych. W przeciwieństwie do pełnych ORM-ów, które oferują szereg zaawansowanych funkcji, mikro-ORM-y są skonstruowane z myślą o wydajności i prostocie.

Główne cechy mikro-ORM-ów:

  • Minimalistyczne podejście: Mikro-ORM-y oferują tylko niezbędne funkcje do mapowania obiektów i wykonywania podstawowych operacji CRUD (Create, Read, Update, Delete).
  • Wysoka wydajność: Dzięki ograniczonej liczbie funkcji mikro-ORM-y są zazwyczaj szybsze niż pełne ORM-y.
  • Łatwość użycia: Prostota interfejsu API ułatwia naukę i implementację mikro-ORM-ów.

Kiedy wybrać mikro-ORM?

Mikro-ORM-y są idealnym rozwiązaniem dla projektów, które:

  • Priorytetyzują wydajność: Mikro-ORM-y oferują szybsze operacje na danych i mniejsze obciążenie dla aplikacji.
  • Ceną prostotę: Mikro-ORM-y są łatwe do nauczenia i użycia, co skraca czas rozwoju.
  • Nie wymagają zaawansowanych funkcji: Mikro-ORM-y wystarczają do prostych aplikacji, które nie potrzebują bogatej funkcjonalności ORM-ów.

Przykładowy mikro-ORM:

Dapper to popularny mikro-ORM dla .NET, znany ze swojej szybkości i lekkości. Oferuje proste API do wykonywania podstawowych operacji na danych i mapowania obiektów na tabele bazy danych.

Podsumowując:

Mikro-ORM-y to uproszczona alternatywa dla pełnych ORM-ów, która oferuje wysoką wydajność, prostotę i skupia się na podstawowych funkcjach mapowania obiektów na dane. To optymalne rozwiązanie dla projektów, które stawiają na szybkość i nie wymagają zaawansowanych funkcji ORM-ów.

Co to jest Dapper i dlaczego jest popularny?

Dapper to darmowy mikro-ORM typu open source dla platformy .NET. Został stworzony w 2011 roku przez Marca Gravela i Sama Saffrona w odpowiedzi na problemy z wydajnością Stack Overflow. Sam Saffron opisał historię powstania Dappera w artykule “Jak nauczyłem się przestać się martwić i napisać własny ORM”.

Dapper zyskał popularność ze względu na imponującą wydajność, która okazała się kluczowa dla rozwiązania problemów z wydajnością Stack Overflow – jednej z najczęściej odwiedzanych stron internetowych na świecie. Sukces Dappera wynika z jego prostej konstrukcji i sposobu, w jaki eliminuje złożoność tworzenia zapytań. Dzięki Dapperowi wykonywanie, parametryzacja i mapowanie obiektów na zapytania SQL staje się niezwykle łatwe.

Dapper kontra Entity Framework Core : Wybór odpowiedniego narzędzia

Entity Framework Core (EF Core) to rozbudowany ORM (Obiektowo-Relacyjne Mapowanie) opracowany przez Microsoft. Chociaż oferuje on szeroki zakres funkcji w porównaniu do Dappera, nie oznacza to automatycznie, że jest lepszym rozwiązaniem. Zarówno Dapper, jak i EF Core mają swoje zalety i wady, a wybór odpowiedniego narzędzia zależy od specyfiki projektu.

W niektórych przypadkach połączenie Dappera z EF Core może okazać się optymalnym rozwiązaniem. Chociaż taki zestaw narzędzi wymaga więcej zasobów od aplikacji, pozwala on na tworzenie wysoce wydajnych i funkcjonalnych rozwiązań wykorzystujących zalety obu technologii.

Kluczowe różnice:

  • Funkcjonalność: EF Core oferuje szeroki zakres funkcji, takich jak automatyczne generowanie bazy danych, migracje, buforowanie obiektów i kompleksowe zapytania LINQ. Dapper skupia się na podstawowych operacjach CRUD i mapowaniu obiektów, zapewniając przy tym wysoką wydajność.
  • Wydajność: Dapper jest znany ze swojej szybkości, co czyni go idealnym wyborem dla aplikacji wymagających dużej ilości operacji na danych. EF Core może być mniej wydajny ze względu na bogatą funkcjonalność.
  • Prostota: Dapper posiada prosty i łatwy do nauczenia interfejs API. EF Core może być bardziej skomplikowany ze względu na szeroki zakres funkcji.

Kiedy wybrać Dappera?

  • Priorytetem jest wydajność: Dapper jest idealny dla aplikacji wymagających szybkiego dostępu do danych.
  • Prostota aplikacji: Dapper sprawdza się w prostych projektach, które nie potrzebują zaawansowanych funkcji ORM-ów.
  • Pełna kontrola nad SQL: Dapper daje developerom pełną kontrolę nad zapytaniami SQL.

Kiedy wybrać EF Core?

  • Zaawansowane funkcje: EF Core oferuje szereg zaawansowanych funkcji, takich jak automatyczne generowanie bazy danych i migracje.
  • Kompleksowe zapytania: EF Core wspiera kompleksowe zapytania LINQ, ułatwiając pracę z danymi.
  • Duże projekty: EF Core sprawdza się w dużych projektach wymagających bogatej funkcjonalności ORM-a.

Połączenie Dappera i EF Core:

  • Większe zużycie zasobów: Połączenie obu narzędzi wymaga więcej zasobów od aplikacji.
  • Optymalne wykorzystanie zalet: Pozwala na tworzenie zaawansowanych aplikacji wykorzystujących najlepsze cechy obu technologii.

Wybór między Dapperem a EF Core zależy od specyfiki projektu. Dapper oferuje wysoką wydajność i prostotę, podczas gdy EF Core zapewnia bogatą funkcjonalność i automatyzację. W niektórych przypadkach połączenie obu narzędzi może okazać się najlepszym rozwiązaniem.

Utrwalanie danych za pomocą Dappera

Aby zademonstrować użycie Dappera w aplikacji .NET, utwórzmy minimalne API, które wykona operacje CRUD (Create, Read, Update and Delete) w bazie danych MsSQL.
Dostęp do kodu źródłowego projektu znajdziesz na githubie tutaj.

Tworzenie projektu

Aby więc zbudować projekt w Visual Studio:

  • Utwórz nowy projekt
  • Wybierz interfejs API sieci Web ASP.NET Core
  • Wybierz platformę .NET 8
  • Odznacz „Użyj kontrolerów”
  • Kliknij Utwórz

Zależności projektu

Projekt będzie miał następujące zależności, które można dodać do pliku .csproj:

<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.6" />
<PackageReference Include="Dapper" Version="2.1.35" />

Modelowanie danych za pomocą klas

Aby zapisać dane w bazie danych, musimy najpierw stworzyć klasy modelu, które będą odzwierciedlać strukturę naszych danych. Pomyśl o nich jak o schematach, które definiują, jakie informacje będą przechowywane w bazie danych.

1. Klasa DbContext

Pierwszą klasą, którą utworzymy, jest klasa DbContext. Ta klasa reprezentuje połączenie z bazą danych i zapewnia metody do wykonywania operacji na danych, takich jak dodawanie, usuwanie i modyfikowanie rekordów.

Wyobraź sobie, że klasa DbContext to klucz do Twojej bazy danych. Za pomocą tego klucza możesz uzyskiwać dostęp do danych i zarządzać nimi.

2. Klasa Encji „Kurs”

Następną klasą, którą utworzymy, jest klasa reprezentująca encję „Kurs”. Ta klasa będzie zawierać wszystkie pola, które opisują kurs, takie jak identyfikator kursu, nazwa kursu itd. Pomyśl o klasie „Kurs” jako o szablonie dla wszystkich kursów w Twojej bazie danych.

Każdy kurs będzie reprezentowany przez obiekt tej klasy, który zawiera wszystkie niezbędne informacje o kursie.

Utwórz więc nowy folder o nazwie „Models” i utwórz w nim poniższe klasy:

DbContext

using Microsoft.EntityFrameworkCore;

namespace DapperDb.Models;

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options)
        : base(options)
    {
    }
    public DbSet<Course> Courses { get; set; }
}

Course

namespace DapperDb.Models;

public class Course
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Author { get; set; }
    public decimal Price { get; set; }
    public string? ImageUrl { get; set; }
    public bool IsRecommended { get; set; }
    public bool IsCourseOfTheMonth { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}

Konfiguracja wstrzykiwania zależności dla MyDbContext

Aby włączyć wstrzykiwanie zależności dla klasy MyDbContext, musimy dodać odpowiedni kod do pliku Program.cs. Ten kod informuje frameworka o sposobie łączenia z bazą danych i udostępnia instancje MyDbContext innym komponentom aplikacji.

dlatego w pliku Program.cs dodaj następujący kod:

builder.Services.AddDbContext<MyDbContext>(options =>
  options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

Wyjaśnienie kodu:

  • builder.Services.AddDbContext<MyDbContext>():
    Ten kod mówi frameworkowi, że chcemy korzystać z klasy MyDbContext jako kontekstu bazy danych.
  • options =>:
    Ten operator tworzy anonimową funkcję, która konfiguruje połączenie z bazą danych.
  • options.UseSqlServer(builder.Configuration.GetConnectionString(“DefaultConnection”)):
    Ten kod informuje framework, że chcemy używać połączenia SQL Server z bazą danych, którego nazwa to “DefaultConnection”. Nazwa połączenia jest zdefiniowana w pliku appsettings.json.

Po dodaniu tego kodu framework będzie w stanie automatycznie tworzyć i dostarczać instancje MyDbContext do innych komponentów aplikacji, które ich potrzebują. To ułatwia zarządzanie połączeniami z bazą danych i sprzyja czystości kodu.

Tworzymy klasę repozytorium

Klasa repozytorium to specjalny typ klasy, która pomaga nam zarządzać danymi w bazie danych w sposób uporządkowany i efektywny. Zawiera ona metody do wykonywania operacji CRUD (Create, Read, Update, Delete) na danych.

Tworzenie folderu „Data”

  1. Utwórz nowy folder o nazwie „Data”. Będzie on służył do przechowywania wszystkich klas związanych z dostępem do danych.

Definiowanie klasy repozytorium

  1. W folderze „Data” utwórz nowy plik i zdefiniuj w nim klasę repozytorium. Przykładowy kod może wyglądać następująco:
using Dapper;
using DapperDb.Models;
using Microsoft.Data.SqlClient;
using System.Data;

namespace DapperDb.Data;

public class CourseRepository
{
    private readonly IConfiguration _configuration;
    private readonly IDbConnection _dbConnection;

    public CourseRepository(IConfiguration configuration)
    {
        _configuration = configuration;
        _dbConnection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection"));
    }

    public async Task<List<Course>> GetAll()
    {
        try
        {
            _dbConnection?.Open();

            string query = @"select id, name, author, price, imageUrl, isRecommended, isCourseOfTheMonth, startDate, endDate from course";

            var courses = await _dbConnection.QueryAsync<Course>(query);
            return courses.ToList();
        }
        catch (Exception)
        {
            return new List<Course>();
        }
        finally
        {
            _dbConnection?.Close();
        }
    }

    public async Task<Course?> GetById(string id)
    {
        try
        {
            _dbConnection?.Open();

            string query = $@"select id, name, author, price, imageUrl, isRecommended, isCourseOfTheMonth, startDate, endDate from course where id = '{id}'";

            var course = await _dbConnection.QueryAsync<Course>(query, id);
            return course.FirstOrDefault();
        }
        catch (Exception)
        {
            return null;
        }
        finally
        {
            _dbConnection?.Close();
        }
    }

    public async Task<bool> Create(Course course)
    {
        try
        {
            _dbConnection?.Open();

            string query = @"insert into course(name, author, price, imageUrl, isRecommended, isCourseOfTheMonth, startDate, endDate) 
                             values(@Name, @Author,  @Price, @ImageUrl, @IsRecommended, @IsCourseOfTheMonth, @StartDate, @EndDate)";

            await _dbConnection.ExecuteAsync(query, course);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
        finally
        {
            _dbConnection?.Close();
        }
    }

    public async Task<bool> Update(Course course)
    {
        try
        {
            _dbConnection?.Open();

            string selectQuery = $@"select * from course where id = '{course.Id}'";

            var entity = await _dbConnection.QueryAsync<Course>(selectQuery, course.Id);

            if (entity is null)
                return false;

            string updateQuery = @"update course set name = @Name, author = @Author, price = @Price, imageUrl = @ImageUrl, 
                                   isRecommended = @IsRecommended, isCourseOfTheMonth = @IsCourseOfTheMonth, startDate = @StartDate, endDate = @EndDate 
                                   where id = @Id";

            await _dbConnection.ExecuteAsync(updateQuery, course);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
        finally
        {
            _dbConnection?.Close();
        }
    }

    public async Task<bool> Delete(string id)
    {
        try
        {
            _dbConnection?.Open();

            string selectQuery = $@"select * from course where id = '{id}'";

            var entity = await _dbConnection.QueryAsync<Course>(selectQuery, id);

            if (entity is null)
                return false;

            string query = $@"delete from course where id = '{id}'";

            await _dbConnection.ExecuteAsync(query);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
        finally
        {
            _dbConnection?.Close();
        }
    }
}

Omówienie klasy CourseRepository

Ta klasa, CourseRepository, odpowiada za zarządzanie danymi kursów w Twojej aplikacji. Działa jak pośrednik między Twoim kodem a bazą danych.

Co robi ta klasa?

  • Połączenie z bazą danych: Kiedy tworzysz obiekt CourseRepository, klasa automatycznie nawiązuje połączenie z bazą danych SQL Server. Połączenie to jest przechowywane w zmiennej _dbConnection.
  • Pobieranie kursów: Metody takie jak GetAll i GetById pozwalają Ci pobrać odpowiednio wszystkie kursy lub pojedynczy kurs po jego identyfikatorze.
  • Dodawanie kursów: Metoda Create umożliwia dodanie nowego kursu do bazy danych.
  • Aktualizacja kursów: Metoda Update służy do modyfikowania istniejącego kursu.
  • Usuwanie kursów: Metoda Delete pozwala na usunięcie kursu z bazy danych.

Jak działa ta klasa?

Każda metoda w tej klasie wykorzystuje bibliotekę Dapper do wykonywania zapytań SQL. Dapper pozwala Ci pisać zwykłe zapytania SQL, a następnie mapuje je na obiekty kursu w Twoim kodzie.

  • Ciągi znaków SQL: Zwróć uwagę, że każda metoda zawiera ciąg znaków, który definiuje zapytanie SQL. Na przykład, metoda GetAll używa zapytania select * from course do pobrania wszystkich kursów z tabeli “course” w bazie danych.
  • Parametry: Niektóre metody, takie jak GetById, Update i Delete, przyjmują parametry jako argumenty. Te parametry są następnie wstawiane do zapytania SQL, aby zapewnić bezpieczeństwo i zapobiec atakom typu SQL injection.

Wstrzykiwanie zależności

Musimy także dodać konfigurację klasy repozytorium, aby nastąpiło wstrzyniecie zależności, dlatego w pliku Program.cs dodaj następujący kod:

builder.Services.AddSingleton<CourseRepository>();

Wstrzykiwanie zależności to sposób na przekazywanie obiektu CourseRepository innym częściom Twojej aplikacji, które go potrzebują. Dzięki temu Twój kod jest bardziej elastyczny i łatwiejszy do testowania.

Podsumowanie

Klasa CourseRepository ułatwia Ci interakcję z bazą danych i zarządzanie danymi kursów w Twojej aplikacji. Nie musisz bezpośrednio pisać kodu SQL, a jedynie wywołujesz odpowiednie metody, aby wykonać operacje CRUD (Create, Read, Update, Delete) na kursach.

Tworzymy klasę usług dla kursów

Teraz, gdy mamy już klasę repozytorium, która zarządza danymi kursów w bazie danych, możemy stworzyć klasę usług, która będzie odpowiedzialna za logikę biznesową związaną z kursami.

Co to jest klasa usług?

Pomyśl o klasie usług jako o pośredniku między Twoim kodem a klasą repozytorium. Klasa usług zawiera metody, które wykonują operacje biznesowe związane z kursami, takie jak pobieranie, dodawanie, modyfikowanie i usuwanie kursów. Te metody wykorzystują metody klasy repozytorium do interakcji z bazą danych.

Jak stworzyć klasę usług dla kursów?

  1. Utwórz folder „Usługi”.
  2. W folderze „Usługi” utwórz interfejs ICourseService.
    • Ten interfejs definiuje metody, które klasa usług musi zaimplementować.
  3. W folderze „Usługi” utwórz klasę CourseService.
    • Klasa CourseService implementuje interfejs ICourseService.
    • Klasa zawiera konstruktor, który przyjmuje obiekt CourseRepository jako parametr.
    • Metody w klasie CourseService wywołują odpowiednie metody w klasie CourseRepository do wykonania operacji na kursach.

Przykład kodu

Oto przykładowy kod dla interfejsu i klasy usług:

using DapperDb.Models;

namespace DapperDb.Services;

public interface ICourseService
{
    Task<List<Course>> GetAllCourses();
    Task<Course> GetCourseById(string id);
    Task<bool> CreateCourse(Course course);
    Task<bool> UpdateCourse(Course course);
    Task<bool> DeleteCourse(string id);
}
using DapperDb.Data;
using DapperDb.Models;

namespace DapperDb.Services;

public class CourseService : ICourseService
{
    private readonly CourseRepository _repository;

    public CourseService(CourseRepository repository)
    {
        _repository = repository;
    }

    public async Task<List<Course>> GetAllCourses() =>
        await _repository.GetAll();

    public async Task<Course> GetCourseById(string id) =>
        await _repository.GetById(id);

    public async Task<bool> CreateCourse(Course course) =>
        await _repository.Create(course);

    public async Task<bool> UpdateCourse(Course course) =>
        await _repository.Update(course);

    public async Task<bool> DeleteCourse(string id) =>
        await _repository.Delete(id);
}

Wstrzykiwanie zależności

Aby klasa usług była dostępna w innych częściach Twojej aplikacji, musimy ją zarejestrować w systemie wstrzykiwania zależności. W pliku Program.cs dodaj następujący kod:

builder.Services.AddTransient<ICourseService, CourseService>();

Ten kod informuje system, że klasa CourseService powinna być używana jako implementacja interfejsu ICourseService. Teraz, gdy klasa usług jest zarejestrowana, możesz jej używać w innych klasach Twojej aplikacji.

Podsumowanie

Klasa usług ułatwia Ci organizację kodu i oddzielenie logiki biznesowej od dostępu do danych. Dzięki klasie usług Twój kod jest bardziej czytelny i łatwiejszy do testowania.

Konfiguracja bazy danych dla aplikacji

Wybór bazy danych

W tym przykładzie używamy bazy danych Microsoft SQL Server (MsSQL). Możesz jednak użyć innej bazy danych, ale konieczna będzie zmiana konfiguracji w pliku appsettings.json.

Instalacja MsSQL

Aby korzystać z MsSQL, musisz zainstalować go na swoim komputerze. Istnieje wiele dostępnych narzędzi do instalacji, w zależności od Twojego systemu operacyjnego. Możesz znaleźć instrukcje instalacji na oficjalnej stronie Microsoft SQL Server: https://www.microsoft.com/en-us/sql-server/sql-server-downloads

Tworzenie bazy danych

Po zainstalowaniu MsSQL możesz utworzyć nową bazę danych za pomocą polecenia SQL. W tym przykładzie tworzymy bazę danych o nazwie DapperDB:

create database DapperDB;

Tworzenie tabeli

Następnie musimy utworzyć tabelę w bazie danych, która będzie przechowywać dane o kursach. Użyj poniższego polecenia SQL, aby utworzyć tabelę o nazwie Course:

CREATE TABLE [dbo].[Course] (
    [Id]                 INT           IDENTITY (1, 1) NOT NULL,
    [Name]               NVARCHAR (50) NOT NULL,
    [Author]             NVARCHAR (50) NOT NULL,
    [Price]              DECIMAL (18)  NOT NULL,
    [ImageUrl]           NVARCHAR (50) NULL,
    [IsRecommended]      BIT           NOT NULL,
    [IsCourseOfTheMonth] BIT           NOT NULL,
    [StartDate]          DATETIME      NOT NULL,
    [EndDate]            DATETIME      NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

Konfiguracja połączenia z bazą danych

1. Użycie parametrów połączenia

Możesz zdefiniować parametry połączenia w pliku appsettings.json. Dodaj następujący kod:

  "ConnectionStrings": {
    "DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=DapperDB;Integrated Security=True;Connect Timeout=30;"
  }

W tym przykładzie:

  • Data Source=(localdb)\\MSSQLLocalDB: Określa lokalny serwer SQL Server.
  • Initial Catalog=DapperDB: Nazwa bazy danych utworzonej wcześniej.
  • Integrated Security=True: Używa uwierzytelniania systemu Windows.
  • Connect Timeout=30: Czas oczekiwania na połączenie.

2. Wstrzykiwanie zależności w Program.cs

Możesz użyć wstrzykiwania zależności, aby skonfigurować połączenie z bazą danych w pliku Program.cs. Dodaj następujący kod:

builder.Services.AddDbContext<MyDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

W tym przykładzie:

  • MyDbContext: Nazwa klasy kontekstu bazy danych.
  • UseSqlServer: Określa użycie SQL Server.
  • builder.Configuration.GetConnectionString(“DefaultConnection”): Pobiera parametry połączenia z pliku appsettings.json.

Podsumowanie

Pamiętaj, że konfiguracja bazy danych może się różnić w zależności od używanej bazy danych i narzędzi. Dokumentacja Twojej bazy danych zawiera szczegółowe instrukcje dotyczące konfiguracji. Po skonfigurowaniu połączenia z bazą danych możesz używać repozytorium i klasy usług do zarządzania danymi o kursach w Twojej aplikacji.

Tworzenie punktów końcowych API dla Twojej aplikacji

Teraz utworzymy punkty końcowe API, które umożliwią użytkownikom komunikację z Twoją aplikacją. Pomyśl o punktach końcowych API jako o drzwiach do Twojej aplikacji. Użytkownicy będą wysyłać żądania HTTP (takie jak GET, POST, PUT i DELETE) do tych punktów końcowych, aby pobierać, tworzyć, aktualizować i usuwać dane o kursach.

using DapperDb.Data;
using DapperDb.Models;
using DapperDb.Services;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<CourseRepository>();
builder.Services.AddTransient<ICourseService, CourseService>();

builder.Services.AddDbContext<MyDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

#region Course API

app.MapGet("/Course/Get", async (ICourseService service) =>
{
    var result = await service.GetAllCourses();
    return result.Any() ? Results.Ok(result) : Results.NotFound("No records found");
})
.WithName("GetAllCourses");

app.MapGet("/Course/GetById", async (ICourseService service, string id) =>
{
    var result = await service.GetCourseById(id);
    return result is not null ? Results.Ok(result) : Results.NotFound($"No record found - id: {id}");
})
.WithName("GetCourseById");

app.MapPost("/Course/Create", async (ICourseService service, Course course) =>
{
    bool result = await service.CreateCourse(course);
    return result ? Results.Ok() : Results.BadRequest("Error creating new Course Entity");
})
.WithName("CreateCourse");

app.MapPut("/Course/Update", async (ICourseService service, Course course) =>
{
    bool result = await service.UpdateCourse(course);
    return result ? Results.Ok() : Results.NotFound($"No record found - id: {course.Id}");
})
.WithName("UpdateCourse");

app.MapDelete("/Course/Delete", async (ICourseService service, string id) =>
{
    bool result = await service.DeleteCourse(id);
    return result ? Results.Ok() : Results.NotFound($"No record found - id: {id}");
})
.WithName("DeleteCourse");

#endregion

app.Run();

Należy pamiętać, że w powyższym kodzie tworzymy punkty końcowe wywołujące klasę usługi. Ponieważ korzystamy z szablonu Minimal API, cały kod jest prosty.

Omówienie kodu

Ten kod wykonuje kilka ważnych rzeczy:

  • Dodaje usługi wymagane do obsługi punktów końcowych API.
    • ICourseService: Ta usługa zawiera metody do wykonywania operacji CRUD na kursach.
    • CourseRepository: Ta klasa odpowiada za interakcję z bazą danych i wykonywanie zapytań SQL.
  • Konfiguruje dokumentację Swagger. Swagger to narzędzie, które pomaga użytkownikom Twojego API zrozumieć, jak ono działa.
  • Definiuje punkty końcowe API dla kursów.
    • Każdy punkt końcowy odpowiada jednej operacji CRUD (Create, Read, Update, Delete).
    • Punkty końcowe wykorzystują metody z klasy ICourseService do wykonania żądanej operacji.
    • Punkty końcowe zwracają odpowiednie wyniki w formacie JSON. Na przykład, jeśli użytkownik wykona żądanie GET do punktu końcowego /Course/Get, aplikacja zwróci listę wszystkich kursów w formacie JSON.

Uruchamianie aplikacji

Po dodaniu kodu uruchom aplikację. Teraz możesz używać narzędzia do testowania API, takiego jak Postman, aby wysyłać żądania HTTP do punktów końcowych API i zarządzać danymi o kursach w swojej aplikacji.

Testowanie aplikacji

Aby przetestować aplikację, wystarczy uruchomić projekt i jeśli wszystko się zgadza, w przeglądarce otworzy się okno z interfejsem Swagger. Poniższy obrazek przedstawia funkcję tworzenia i wyszukiwania danych, aby potwierdzić, że aplikacja działa.

Podsumowanie: Dapper – potężne narzędzie do obsługi bazy danych w .NET

Dapper to imponujące narzędzie do interakcji z bazami danych w .NET. Wyróżnia się znakomitą wydajnością w porównaniu do innych mikro-ORMów. W tym artykule zaprezentowano sposób tworzenia aplikacji z wykorzystaniem Dappera i bazy danych MsSQL.

Należy jednak zaznaczyć, że artykuł koncentruje się na prezentacji funkcjonalności Dappera, pomijając pewne szczegóły, jak dodawanie logowania czy walidacja danych. Te elementy stanowią ważną część kompletnej aplikacji i zachęcam do ich implementacji we własnych projektach.

Dapper oferuje wiele możliwości uproszczenia dostępu do danych i usprawnienia działania aplikacji. Zachęcamy do dalszego zgłębiania jego funkcjonalności i wykorzystania go w swoich projektach .NET.

Korzyści płynące z Dappera:

  • Wysoka wydajność: Dapper słynie z szybkiego wykonywania zapytań SQL.
  • Prostota: Użytkowanie Dappera jest intuicyjne i łatwe do nauczenia.
  • Kontrola: Dapper zapewnia pełną kontrolę nad generowanymi zapytaniami SQL.
  • Wszechstronność: Dapper obsługuje różne bazy danych, w tym MySQL, SQL Server i PostgreSQL.

Pamiętaj, że Dapper to tylko narzędzie, a sukces Twojej aplikacji zależy od Twoich umiejętności programistycznych i projektowych.

Dodatkowe zasoby:

Mam nadzieję, że ten artykuł okazał się pomocny i zachęcił Cię do wypróbowania Dappera w swoich projektach .NET!

3 comments

  1. Dapper brzmi świetnie! Szczególnie podoba mi się jego szybkość i prostota. Już od dawna szukałem alternatywy dla tradycyjnych ORM-ów, które często są zbyt ciężkie i skomplikowane. Zdecydowanie wypróbuję Dapper w moim następnym projekcie.

  2. Ciekawy artykuł, dobrze przedstawiający zalety i wady Dappera. Cenę prostotę i wydajność tego narzędzia, ale z drugiej strony jego ograniczona funkcjonalność może być dla niektórych problematyczna.

  3. Dzięki za ten szczegółowy przegląd Dappera! Nie znałem wcześniej tego mikro-ORM-a, ale teraz z pewnością go sprawdzę. Mam nadzieję, że jego elastyczność pozwoli mi na łatwe dostosowanie go do moich potrzeb.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *