Monthly Archives: July 2020

Scalanie migracji w Entity Framework Core 5

Podczas pracy z szybko rozwijającym się projektem zmiany zachodzą szybko nie tylko w kodzie projektu, ale także w schemacie bazy danych. Dzieje się tak zwłaszcza podczas pracy nad mikroserwisem od samego początku, kiedy często zmienia się jego przeznaczenie.

Jak działają migracje w EF Core 5

W migracjach Entity Framework Core 5 dodajemy migrację jako zmiany pomiędzy naszą klasą DbContext a istniejącą [nazwa DbContext] ModelSnapshot. Podczas generowania nowej migracji narzędzie CLI wygeneruje tylko różnice między tymi dwoma bytami i umieści je w dwóch metodach: Up i Down. W pierwszej nastąpi zmiana dotycząca zastosowania migracji, aw drugiej usunięcia migracji.

Po zastosowaniu migracji jej nazwa jest zapisywana w tabeli __EFMigrationsHistory.

Scalanie wielu migracji

Powiedzmy, że po wielokrotnej zmianie schematu na wczesnych etapach nasz projekt jest teraz stabilny. Mamy kilka migracji, które można by połączyć w jedną, która raz stworzyłaby model, bez wielu małych aktualizacji.

Scalanie kiedy możemy wszystko usunąć

Najłatwiejszym sposobem scalenia wszystkich migracji byłoby usunięcie wszystkiego! A dokładnie mam na myśli taki proces:

  • usuń katalog Migrations ze wszystkimi migracjami
  • wyczyść tabelę __EFMigrationHistory
  • usuń wszystkie tabele i inne obiekty bazy danych, które zostały dodane podczas migracji
  • utwórz nową migrację ze wszystkimi zmianami

Jest to drastyczny sposób scalania migracji, ponieważ utracimy wszystkie dane. Jest to jednak bardzo proste i może w niektórych przypadkach spełniać swoją rolę.

Scalanie, kiedy chcemy zachować dane

Kiedy chcemy zachować dane, nie możemy usunąć wszystkich już utworzonych obiektów bazy danych, ale możemy scalić pliki migracji w naszym kodzie. Zobaczmy, jak można to zrobić.

  • Usuń wszystkie skrypty migracji z folderu Migrations
  • Dodaj nową migrację za pomocą polecenia dotnet ef migrations add MergedMigration
  • Skopiuj cały plik i wyczyść obie metody Up i Down
  • Zaktualizuj bazę danych i zastosuj migrację MergedMigration za pomocą polecenia dotnet ef database update
  • Następnie zamień zawartość pliku MergedMigration na wcześniej wygenerowany kod

W rezultacie będziesz mieć tylko jeden plik migracji. W moim przykładzie tabela __EFMigrationHistory wygląda następująco.

A teraz w Visual Studio widzę tylko jedną migrację.

Zawiera ona zmiany ze wszystkich moich poprzednich migracji, które zostały scalone.

Zadziałało!

Wskazówka! Możesz również nazwać scaloną migrację tak jak pierwszą, która została już zastosowana, aby nie trzeba było aktualizować bazy danych i dodawać jej do tabeli __EFMigrationHistory.

Nie zadziała za każdym razem

Migracje możemy łatwo łączyć, gdy są stosowane tylko do kontrolowanej przez nas bazy danych. Ponadto ten proces nie będzie działać w środowiskach, w których nie zastosowano wszystkich scalonych migracji. Proces jest łatwy, ale są pewne rzeczy, które należy zwrócić uwagę.

Z drugiej strony, czy musimy zachować wszystkie migracje, nawet jeśli wiemy, że nigdy więcej ich nie uruchomimy? Nie sądzę. W tym miejscu byłoby wspaniale połączyć stare migracje, ale zostawić te najnowsze. Można to osiągnąć w bardzo podobny sposób.

  • Przywróć ostatnie N migracji lokalnie, jedna po drugiej i przenieś je gdzieś
  • Przywróć stan projektu w miejscu pasującym do migracji (git checkout w odpowiednim miejscu w historii)
  • Scal wszystkie istniejące migracje
  • Przywróć stan projekt do najnowszej wersji
  • Dodawaj po kolei zapisane najnowsze migracje

W takim przypadku zachowamy najnowsze migracje i utworzymy dużą migrację początkową, która byłaby zgodna z Twoim projektem. Jeśli wystąpi przypadek, w którym wszystkie migracje będą musiały zostać zastosowane do bazy danych, schemat bazy danych nie zostanie uszkodzony.

Podsumowanie

Scalanie migracji w Entity Framework Core 5 jest możliwe i mogę powiedzieć, że jest to zaskakująco łatwe. Obejmuje jednak proces automatycznego generowania i musisz sprawdzić, czy migracja scalona działa dokładnie tak samo, jak wszystkie migracje stosowane pojedynczo. Co więcej, istnieje więcej niż jeden sposób łączenia migracji i musisz wybrać ten, który jest dla Ciebie najbardziej odpowiedni.

Cały kod zamieszczony tutaj jest dostępny na moim GitHubie, więc możesz go pobrać i bawić się nim. Spójrz również na ten post, jak go uruchomić: PrimeHotel – jak uruchomić projekt.

Dzięki za czytanie i do zobaczenia ponownie 🙂

Merging migrations in Entity Framework Core 5

When working with a fast-evolving project changes happen rapidly not only to the project’s code but also to the database schema. It happens especially when working on a micro-service from the start when its purpose shifts.

How EF Core 5 migrations work

In Entity Framework Core 5 migrations we are adding a migration as a delta changes between our DbContext class and existing [DbContext name]ModelSnapshot. When generating new migration a CLI Tool will generate only the differences between those two and put them in two methods: Up and Down. In the first one, there will be a change to apply the migration and in the second one, to remove the migration.

After the migration is applied, its name is noted in the __EFMigrationsHistory table.

Merging multiple migrations 

Let’s say that after changing a schema multiple times in the early stages our project is now stable. We have a bunch of migrations that could be merged into one, that would create a model once, without many small updates. 

When we can remove everything

The easiest way to merge all migrations would be removing everything! What I mean is:

  • remove Migrations directory with all migrations
  • clear __EFMigrationHistory table
  • remove all tables and other database objects that were added via migrations
  • create new migration with all changes

This is a drastic way of merging migrations because we will lose all the data. However, it’s super simple and it might work in some cases.

When we need to preserve data

This means that we cannot remove all already created database objects, but we can merge migration files in our code. Let’s see how that can be done.

  1. Delete all migration scripts from Migrations folder
  2. Add a new migration with command dotnet ef migrations add MergedMigration
  3. Copy the entire file and clear both Up and Down methods
  4. Update the database and apply MergedMigration migration with command dotnet ef database update
  5. After that, replace the content of the MergedMigration file with earlier generated code

As a result, you will have only one migration file. In my example the __EFMigrationHistory table looks like this.

And now in the Visual Studio, I can see only on migration.

That contains changes from all my previous migrations merged together.

It worked!

Tip! You can also name you merged migration as the first one, that was already applied so that you wouldn’t have to update the database and add it to the __EFMigrationHistory table. 

It will not work in every case

We can easily merge migrations when they are applied only to the database that we control. I addition, it will not work for environments that don’t have all merged migrations applied. The process is easy, but there are certain things that need to be taken into account.

On the other hand, do we need to keep all migrations, even when we know that we won’t run them ever again? I don’t think so. At this point, it would be great to merge old migrations but leave the newest ones. It could be accomplished with a very similar process.

  1. Revert last N migrations locally, one by one, and move them somewhere
  2. Check out the project in the place matching the migrations
  3. Merge all existing migrations
  4. Check out the project in the newest state
  5. Add saved newest migrations, one by one

In this case, we will keep the newest migrations and create a big initial migration, that would be consistent with your project. If there will be a case, where all migrations would need to be applied to a database, the database schema wouldn’t be broken.

Summary

Merging migrations in Entity Framework Core 5 is possible and I can say it’s surprisingly easy. However, it involves an automatic generation process and you need to check if merged migration does exactly the same thing as all migrations applied one by one. Moreover, there is more than one way to merge migrations and you need to choose the one that is best for you.

All code posted here is available at my GitHub, so you can download it and play with it. Take a look also at this post on how to run it: PrimeHotel – how to run this project.

Thanks for reading and hopefully see you again 🙂

Dodanie migracji w Entity Framework Core 5 do projektu w .NET 5

Migracje bazy danych pomagają programiście w utrzymywaniu aktualności schematu bazy danych z kodem. Jest to podstawowy mechanizm, który utrzymuje zmiany w kodzie i stosuje je w bazie danych. Migracje Entity Framework Core 5 są przeznaczone do śledzenia klasy DbContext i generowania migracji podczas jej aktualizacji.

Instalowanie narzędzi

Aby dodać migracje EF Core, musisz mieć już skonfigurowane Entity Framework Core w projekcie. Możesz sprawdzić, jak przejść przez ten proces w tym poście: PrimeHotel – dodanie Entity Framework Core 5 w .NET 5

Najłatwiejszym sposobem dodawania migracji i zarządzania nimi jest użycie narzędzi .NET Core CLI, które powinieneś mieć już zainstalowane. Wpisz poniższe polecenie, aby to sprawdzić:

dotnet tool install --global dotnet-ef

Możesz także zaktualizować narzędzie po zainstalowaniu używając komendy:

Dodanie migracji

Dodanie pierwszej migracji nie różni się zbytnio od dodawania kolejnych. Musisz otworzyć okno terminala w lokalizacji projektu i wykonać polecenie:

dotnet ef migrations add InitialCreate

Kiedy to polecenie zostanie wykonane pomyślnie, wygeneruje katalog Migrations. Plik InitialCreate to indywidualna migracja w celu dopasowania do DbContext. PrimeDbContextModelSnapshot reprezentuje bieżący stan modelu. Jest dodawany do projektu podczas tworzenia pierwszej migracji i aktualizowany przy każdej kolejnej migracji. Umożliwia platformie migracji obliczenie zmian wymaganych w celu zaktualizowania bazy danych do modelu.

W pliku InitialCreate znajdziesz dwie metody: w Up i Down. Będą one reprezentować zmiany, kiedy migracja zostanie zastosowana i kiedy zostanie wycofana.

Wygenerowana migracja pozostanie taka, jaka jest. Nie jest to plik generowany automatycznie, który zostanie zaktualizowany w dalszej części procesu. Ta migracja została wygenerowana, abyś mógł rzucić okiem i sprawdzić, czy robi to, co powinna. Migrację możesz modyfikować zgodnie ze swoimi potrzebami, zatem nic nie stoi na przeszkodzie, aby wprowadzić własne ulepszenia.

Dodanie drugiej i kolejnych migracji nie będzie się właściwie niczym różniło od powyższego procesu. Wystarczy użyć polecenia dotnet migrations add <name> i zostanie wygenerowany odpowiedni plik.

Uruchamianie migracji ręcznie

W tym momencie możesz uruchomić migracje Entity Framework Core 5 i zaktualizować schemat bazy danych. Możesz to zrobić za pomocą następującego polecenia:

dotnet ef database update

Migracje bazy danych zostaną zastosowane, a wszystkie wykonane migracje zostaną odnotowane w tabeli __EFMigrationsHistory. Oto listing tej tabeli po kilku migracjach.

Uruchamianie migracji automatycznie

Byłoby wspaniale, gdyby nasze zmiany zostały sprawdzone i zastosowane przy każdym uruchomieniu projektu. Zobaczmy, jak możemy to osiągnąć. Przede wszystkim przejdźmy do pliku Startup.cs i utwórzmy metodę.

    private void UpgradeDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetService<PrimeDbContext>();
            if (context != null && context.Database != null)
            {
                context.Database.Migrate();
            }
        }
    }

Ta metoda używa wbudowanego mechanizmu Dependency Injection, aby pobrać wystąpienie naszego PrimeDbContext i użyć go do uruchomienia migracji bazy danych. Tylko te, które nie zostały jeszcze zastosowane, zostaną uruchomione.

Następnie, w metodzie Configure, dodaj na końcu.

    UpgradeDatabase(app);

Dzięki tej konfiguracji mechanizmu aplikacja zaktualizuje używaną bazę danych, niezależnie od tego, czy jest uruchamiana lokalnie, czy też jest wdrażana i uruchamiana na serwerze produkcyjnym.

Podsumowanie

Migracje bazy danych ułatwiają aktualizowanie schematu bazy danych zgodnie ze zmianami kodu. Dodanie migracji Entity Framework Core 5 jest naturalnym krokiem, gdy masz Entity Framework Core. Wszystkie operacje można wykonać za pomocą narzędzi .NET Core CLI i bardzo prostych poleceń. Pamiętaj, że zawsze możesz edytować migracje przed ich zastosowaniem.

Cały kod opublikowany w tym poście jest dostępny na moim GitHub, więc możesz go dowolnie ściągać i modyfikować. Zerknij także na post jak uruchomić projekt PrimeHotel: PrimeHotel – jak uruchomić projekt

Dzięki za przeczytanie i powodzenia! 🙂

Adding Entity Framework Core 5 migrations to .NET 5 project

Database migrations help a developer to keep database schema up-to-date with the code. It is a core mechanism, that keeps changes in code and applies them in the database. Entity Framework Core 5 migrations are designed to keep track of DbContext class and generate migrations when you update it.

Installing the tools

To add EF Core migrations, you need to have Entity Framework Core already set up in your project. You can check how to go through that process in this post: PrimeHotel – adding Entity Framework Core 5 in .NET

The easiest way to add and manage migrations is to use .NET Core CLI tools, which you should have already installed. Type this command to check it out:

dotnet tool install --global dotnet-ef

You can also update the tool, once installed:

Adding a migration

Adding first migration doesn’t differ much from adding the next ones. You need to open a terminal window in the location of the project and execute the command:

dotnet ef migrations add InitialCreate

When this command executes successfully, it will generate a Migrations directory. InitialCreate file represents individual migration to match the DbContext. PrimeDbContextModelSnapshot represents the current state of the model. It is added to the project when the first migration is created and updated with each subsequent migration. It enables the migrations framework to calculate the changes required to bring the database up to date with the model.

In the InitialCreate file you will find two methods: Up and Down. Those will represent the changes when migration will be applied and when it would be rolled back.

Generated migration will stay the way it is. It’s not an auto-generated file that will be updated later in the process. This migration was generated for you to have a look and check if it does what it should. You can modify the migration according to your needs, nothing stops you from making some improvements.

Adding second and next migrations is a very similar process to the one presented above. You just need to use the command dotnet migrations add <name> add next migration will be generated.

Applying migrations manually

At this point, you can run your Entity Framework Core 5 migrations and update the database schema. You can do this via the following command:

dotnet ef database update

Database migrations will be applied and all executed migrations will be noted in the __EFMigrationsHistory. Here is the listing of this table after a couple of migrations.

Applying migrations automatically

It would be great if our changes were checked and applied on every project run. Let’s see how we can accomplish that. First of all, let’s go to Startup.cs file and create a method. 

    private void UpgradeDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetService<PrimeDbContext>();
            if (context != null && context.Database != null)
            {
                context.Database.Migrate();
            }
        }
    }

This method will use built-in Dependency Injection mechanism to fetch an instance of our PrimeDbContext and use it to run database migrations. Only ones that were not applied yet will be run.

Now, in the Configure method add a line at the bottom.

    UpgradeDatabase(app);

With this mechanism set-up, the application will update the database it’s using, whether it is run locally, or deployed and run on a production server. 

Summary

Database migrations will help you keep database schema updated accordingly to the code changes. Adding an Entity Framework Core 5 migrations is a natural step when you have Entity Framework Core in place. All operations can be accomplished with .NET Core CLI tools and very simple commands. Remember that you can always edit migrations before applying them.

All code posted here is available at my GitHub, so you can download it freely. Take a look also at this post on how to run it: PrimeHotel – how to run this project.

Thanks for reading and good luck 🙂

Dodanie Entity Framework Core 5 do istniejącej bazy danych

Entity Framework Core 5 to lekki i łatwy w użyciu ORM, który pozwala korzystać z bazy danych bez pisania jakichkolwiek poleceń SQL. Wbudowane mechanizmy będą tłumaczyć zapytania LINQ dotyczące klas encji na zapytania SQL i zwracać zamapowane obiekty.

Zerknij też na post dotyczący dodawania EF Core z migracjami do pustej bazy danych: PrimeHotel – dodanie Entity Framework Core 5 w .NET 5

Dodanie Entity Framework Core 5 jest bardzo proste, jeśli masz pustą bazę danych, ale czy jest to takie łatwe podczas pracy z bazą danych, która posiada już swoją strukturę? Czy musimy to wszystko mapować, czy możemy po prostu pracować z częścią bazy danych, która nas interesuje? Zacznijmy od początku.

Czego potrzebujemy

Aby pracować z EF Core 5, musimy zainstalować pakiety NuGet:

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.SqlServer

Ostatni pakiet zdradza nam, że będziemy pracować z bazą danych MS SQL Server. Teraz połączmy się z naszą bazą danych i zobaczmy, jak to wygląda.

Do pracy z bazą danych używam Azure Data Studio, które jest lekkim i szybkim narzędziem, które może wykonywać większość podstawowych operacji na bazach danych. Jest znacznie szybszy niż SQL Server Management Studio i do większości mojej pracy używam właśnie tego pierwszego.

Dodamy EF Core dla bazy danych aspnetcore, która wygląda następująco.

Dodanie klasy DbContext

Następną rzeczą, którą musimy zrobić, jest utworzenie klasy DbContext. Moglibyśmy stworzyć ją ręcznie i wszystko wpisać ręcznie. Jednak .NET Core ma narzędzia do tworzenia i generowania ich automatycznie.

Proces ten nazywa się inżynierią wsteczną i jest to tworzenie szkieletów klas encji i klasy DbContext w oparciu o schemat bazy danych. Aby wykonać tę operację, użyjemy narzędzia .NET CLI, które musisz zainstalować, jeśli jeszcze tego nie zrobiłeś. Wpisz poniższe polecenie, aby to sprawdzić:

dotnet tool install --global dotnet-ef

Możesz także zaktualizować narzędzie po jego zainstalowaniu:

Proces tworzenia szkieletu wymaga connection stringa do przekazania. Moglibyśmy go przekazać w poleceniu, ale możemy też wykonać to zadanie w bardziej elegancki sposób, podając tylko jego nazwę.

Przejdźmy do pliku appsettings.json i skonfigurujmy connection string dla naszej nowej bazy danych.

Dodałem connection string o nazwie aspnetcore w sekcji ConnectionStrings.

Polecenie, którego będziemy używać, jest bardzo proste, uruchom je w katalogu swojego projektu:

dotnet ef dbcontext scaffold Name=aspnetcore Microsoft.EntityFrameworkCore.SqlServer

Powyższe polecenie doda aspnetcoreDbContext i wszystkie encje reprezentujące bazę danych.

Efekt jest zadowalający, jednak byłoby wygodniej mieć większą kontrolę nad tym procesem.

Dostosuj proces do swoich potrzeb

Na szczęście jest więcej parametrów, których możemy użyć. Przyjrzyjmy się niektórym z nich:

  • --table może służyć do dołączania określonych tabel
  • --use-database-names zachowa oryginalne nazwy baz danych tak bardzo, jak to możliwe. Jednak nieprawidłowe identyfikatory .NET nadal zostaną zmienione
  • --context może służyć do nadania wygenerowanemu kontekstowi DbContext własnej nazwy
  • --context-dir służy do tworzenia szkieletu klasy DbContext w określonym katalogu
  • --output-dir służy do tworzenia klas jednostek w określonym katalogu
  • --force nadpisze istniejącą klasę DbContext i klasy encji

Zmodyfikowałem moje polecenie, aby wyglądało tak:

dotnet ef dbcontext scaffold Name=aspnetcore --table Profiles --table Events
  --context AspNetCoreDbContext --context-dir AspNetCoreModels 
  --output-dir AspNetCoreModels Microsoft.EntityFrameworkCore.SqlServer

Zobaczmy, jakie klasy zostały wygenerowane.

Zwróć uwagę, że zostały wygenerowane tylko tabele Events i Profiles, klasa DbContext ma nazwę AspNetCoreCotext i wszystko zostało wygenerowane w katalogu AspNetCoreModels. O to chodziło!

Ograniczenia

Inżynieria wsteczna wykonuje ogromną pracę polegającą na tworzeniu szkieletów klas encji, więc nie musimy pisać jej samodzielnie. Istnieją jednak pewne ograniczenia tego procesu:

  • nie wszystko na temat modelu jest przedstawione w schemacie bazy danych. Na przykład hierarchie dziedziczenia, typy własne i tabele dzielone nie zostaną odtworzone
  • ponadto dokumentacja EF Core twierdzi, że istnieją pewne typy kolumn, które nie zostaną uwzględnione w modelu
  • typy dopuszczające wartość null nie zostaną zamapowane jako dopuszczające wartość null. Na przykład kolumny typu string, które mogą mieć wartość null, nie będą mapowane jako typ string?. Taką zmianę trzeba dodać samodzielnie.

Więcej o tym możesz przeczytać w tym artykule Microsoft-u.

Aktualizowanie modelu

Zawsze, gdy coś się zmieni w bazie danych, będziesz musiał zaktualizować swój model. Większość zmian będzie trywialnych, takich jak dodanie kolumny do tabeli, zmiana nazwy tabeli lub zmiana typu kolumn. Te zmiany można szybko wprowadzić w klasach encji własnoręcznie.

Jeśli jednak nie masz pewności, jak mapować zmiany, zawsze możesz ponownie wygenerować cały DbContext ze wszystkimi klasami encji. Aby to zrobić, użyj parametru --force w poleceniu scaffold. Należy jednak pamiętać, że wszystkie zmiany wprowadzone ręcznie zostaną nadpisane. Obecnie nie ma możliwości aktualizacji modelu ze schematu bazy danych i zachowania ręcznych zmian.

Aktualizowanie bazy danych

Tworzenie szkieletu DbContext to tylko sposób na generowanie klas pasujących do bazy danych. Oznacza to, że możesz dodać migracje nawet do istniejącej bazy danych.

Najpierw musisz dodać AspNetCoreDbContext do kontenera DI. Przejdź do pliku Startup.cs i w metodzie ConfigureServices dodaj następujący wiersz.

    services.AddDbContext<AspNetCoreDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("aspnetcore")));

Teraz możesz dodać migracje do drugiej bazy danych. Dobrą praktyką jest rozdzielenie modeli i migracji dla każdej bazy danych. Wykonaj to polecenie:

dotnet ef migrations add InitialCreate --context AspNetCoreDbContext --output-dir Migrations/AspNetCore

Spójrzmy co zostało wygenerowane:

Warto zwrócić uwagę na jedną rzecz. Entity Framework Core wygenerował początkową migrację ze wszystkimi zmianami, które są obecnie w AspNetCoreDbContext. Może być konieczne wyczyszczenie wszystkich zmian w tej migracji, ponieważ te tabele już istnieją.

Podsumowanie

Podczas dodawania Entity Framework Core 5 do istniejącej bazy danych dobrym pomysłem jest stworzenie szkieletu klas jednostek i kontekstu za pomocą dedykowanego narzędzia .NET CLI. Na szczęście istnieje kilka parametrów, które możesz użyć, aby zbudować dokładnie to, czego potrzebujesz i tak jak tego potrzebujesz.

Migracje EF Core 5 można dodać później, aby zapewnić aktualność bazy danych za pomocą kodu. Jedną z rzeczy, o których należy pamiętać, jest to, że ponowne zaktualizowanie DbContext z bazy danych spowoduje nadpisanie wszystkich zmian, które zostały wprowadzone ręcznie. Z tego powodu tworzenie szkieletów DbContext jest raczje operacją jednorazową.

Cały zamieszczony tutaj kod został zademonstrowany na przykładzie projektu PrimeHotel, który jest dostępny na moim GitHubie, więc możesz go bezpłatnie pobrać i na nim eksperymentować. Spójrz również na ten post, jak uruchomić ten projekt: PrimeHotel – jak uruchomić projekt.

Mam nadzieję, że podobał Ci się ten post. Pozdrawiam! 🙂

Adding an Entity Framework Core 5 to an existing database

Entity Framework Core 5 is a light and easy to use ORM, that let you use the database without writing any SQL commands. Built-in mechanisms will translate your LINQ queries on your entity classes to SQL queries and return mapped objects.

Here is an article about adding EF Core with migrations to an empty database: PrimeHotel – adding Entity Framework Core 5 in .NET

Adding an Entity Framework Core 5 is super simple if you have an empty database, but is it that easy when working with a database that has some data inside? Do we need to map it all, or can we just work with a part of the database that interests us? Let’s start from the beginning.

Let’s see what we need

To work with EF Core 5 we need to install NuGet packages:

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.SqlServer

The last one reveals that we will work with the MS SQL Server database. Now let’s connect to our database and see how it looks like.

I’m using an Azure Data Studio, which is a lightweight and fast tool that can perform most of the basic operations of databases. It’s much faster than SQL Server Management Studio and now for most of my work, I just use the first one.

We will add EF Core for aspnetcore database, which looks like this.

We need a DbContext

The next thing we need to do is to create our DbContext. We could create it by hand and type everything manually. However, .NET Core has tools to scaffold that and generate it for us.

The process is called reverse engineering and it is scaffolding entity type classes and a DbContext class based on a database schema. To perform this operation we will use the .NET CLI tool, that you would have to install if you haven’t done it already. Type this command to check it out:

dotnet tool install --global dotnet-ef

You can also update the tool, once installed:

The scaffolding process needs a connection string to pass. We could pass it in our command, but we can also accomplish this task in a more elegant way by passing only its name.

Let’s go to the appsettings.json file and set up a connection string for our new database.

I’ve added a connection string with the name aspnetcore in ConnectionStrings section. 

The command that we are going to use is very simple, run it in your project directory:

dotnet ef dbcontext scaffold Name=aspnetcore Microsoft.EntityFrameworkCore.SqlServer

This command will add aspnetcoreDbContext and all entities representing your database.

However, it would be nice to have some more control over the process.

Customize the process to your needs

Thankfully, there are more parameters that we can use. Let’s take a look at some of them:

  • --table can be used to include specific tables
  • --use-database-names option will preserve the original database names as much as possible. However, invalid .NET identifiers will still be fixed
  • --context can be used to give generated DbContext your own name
  • --context-dir can be used to scaffold the DbContext class to a specific directory
  • --output-dir can be used to scaffold entity classes to a specific directory
  • --force will override the existing DbContext class and entity classes

I’m going to modify my command, so it will look like this:

dotnet ef dbcontext scaffold Name=aspnetcore --table Profiles --table Events
  --context AspNetCoreDbContext --context-dir AspNetCoreModels 
  --output-dir AspNetCoreModels Microsoft.EntityFrameworkCore.SqlServer

Let’s see what classes were generated.

Notice that only tables Events and Profiles were generated, DbContext class is named AspNetCoreCotext and all was generated in AspNetCoreModels directory. Awesome! 

The limitations

Reverse engineering does a tremendous job of scaffolding entity classes so that we don’t need to write it on our own. However, there are some limitations to this process:

  • not everything about the model is presented in the database schema. For example inheritance hierarchies, owned types and table splitting will not be reverse-engineered
  • also, EF Core documentation claims, that there are some column types that will not be included in the model
  • nullable types will not be mapped as nullable. For example, string columns that can be null, will not be scaffolded as string? type. You will have to edit it yourself

More of that you can read in this Microsoft article.

Updating the model

Whenever something changes in the database, you would need to update your model. Most of the changes will be trivial, like adding a column to the table, renaming a table name, or change columns type. Those changes can be quickly applied in the entity classes manually. 

However, if you’re not sure how to map your changes, you can always regenerate the whole DbContext with all entity classes. To do this, use --force parameter in the scaffold command. Note, however, that all changes done manually, will be overwritten. Currently, there is no option to update model from database schema and preserve manual changes.

Updating the database

Scaffolding a DbContext is just a way to generate classes, that match the database. This means that you can add migrations even to an existing database.

First, you would need to add AspNetCoreDbContext to your DI container. Go to the Startup.cs file and in ConfigureServices add the following line.

    services.AddDbContext<AspNetCoreDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("aspnetcore")));

Now you can add migrations to the second database. It’s a good practice to keep models and migrations separate for every database. Execute this command:

dotnet ef migrations add InitialCreate --context AspNetCoreDbContext --output-dir Migrations/AspNetCore

Here is what was generated:

There’s one thing worth noticing. Entity Framework Core generated initial migration with all changes that are currently in the AspNetCoreDbContext. You might need to clear all changes in that migration because those tables already exist.

Summary

When adding an Entity Framework Core 5 to an existing database, a good idea is to scaffold entity classes and context with a dedicated .NET CLI tool. You have a handful of parameters that you can provide and scaffold exactly what you need and how you need it.

You can add EF Core 5 migrations later on for keeping your database up to date with your code. One thing that you should keep in mind is that updating DbContext from the database again will override all changes that you did manually. Because of this, scaffolding DbContext is more of a one-time thing.

All code posted here was applied to a PrimeHotel project, that is available at my GitHub, so you can download it freely and experiment. Take a look also at this post on how to run it: PrimeHotel – how to run this project.

Hope you liked the post, cheers!

 

 

PrimeHotel – dodanie Entity Framework Core 5 w .NET 5

Przyjrzyjmy się, jak wprowadzić Entity Framework Core 5 w projekcie ASP.NET Core w .NET 5. Zaczniemy od pustej bazy danych, w której mamy pełne pole do popisu i możemy dodawać tabele tak, jak chcemy.

W tym poście będziemy pracować z projektem PrimeHotel, który stworzyłem do celów edukacyjnych. Wszystko to jest dostępne w moim GitHub, więc możesz go pobrać bezpłatnie. Zobacz także ten post, aby dowiedzieć się jak uruchomić ten projekt: PrimeHotel – jak uruchomić projekt.

Czym jest Entity Framework Core

Entity Framework Core 5 to lekka, rozszerzalna, otwarta i wieloplatformowa wersja popularnej technologii dostępu do danych Entity Framework. EF Core jest obiektowym mapperem (O/RM), umożliwia programistom pracę z bazą danych przy użyciu obiektów .NET i eliminuje potrzebę korzystania z większości kodu dostępu do danych, który zwykle muszą pisać. Oznacza to koniec pisania komend w SQL. Sprawdza się doskonale w większości przypadków, jednak gdy trzeba pracować z dużą ilością danych, prawdopodobnie lepiej będzie napisać własne polecenia SQL.

Dodanie Entity Framework Core

Dodawanie EF Core 5 do projektu ASP.NET Core jest bardzo proste. Zacznij od instalacji pakietów NuGet:

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.SqlServer

Po zakończeniu dodaj PrimeDbContext do folderu Models, który wyglądałby następująco:

    public class PrimeDbContext : DbContext
    {
        public PrimeDbContext(DbContextOptions<PrimeDbContext> options)
            : base(options)
        {
        }

        public virtual DbSet<Room> Rooms { get; set; }
    }

Teraz musimy dodać klasę Room, która reprezentowałaby encję pokoju, z tabeli Rooms.

    public class Room
    {
        public int Id { get; set; }

        public int Number { get; set; }

        public string Description { get; set; }

        public DateTime LastBooked { get; set; }

        public int Level { get; set; }

        public RoomType RoomType { get; set; }

        public int NumberOfPlacesToSleep { get; set; }
    }

    public enum RoomType
    {
        Standard,
        Suite
    }

Teraz zajmiemy się częścią konfiguracyjną. Użyjmy pustej bazy danych, która jest hostowana przez nas lokalnie. Najłatwiejszym sposobem jest zainstalowanie SQL Server w wersji Express i skonfigurowanie jej lokalnie. Możesz jednak skonfigurować serwer bazy danych w kontenerze docker. Sprawdź mój post, jak to zrobić: Set up a SQL Server in a docker container.

W pliku appsettings.json musimy wpisać nasz connection string. Powinien on wyglądać podobnie jak tutaj:

A teraz przejdźmy do pliku Startup.cs, gdzie musimy skonfigurować EF Core, aby używał naszego connection stringa. W metodzie ConfigureServices dodaj następujący wiersz:

    // Entity Framework
    services.AddDbContext<PrimeDbContext>(options =>
         options.UseSqlServer(Configuration.GetConnectionString("HotelDB")));

Zauważ, że użyłem nazwy HotelDB, która jest nazwą mojego connection stringa z pliku appsettings.json. To ważne, żeby te dwie wartości do siebie pasowały.

Wykonaliśmy już większość kluczowych rzeczy, ale potrzebujemy czegoś, co stworzyłoby tabele w bazie danych z naszego PrimeDbContext. Do tej pory mamy tylko jedną, ale nadszedł właściwy czas na wprowadzenie mechanizmów migracji.

Dodanie migracji w EF Core

Migracje w EF Core bazy danch pozwalają wprowadzać zmiany w bazie danych tak, aby była ona aktualna z kodem aplikacji, które ją używa. Jest to bardzo istotny mechanizm, ponieważ zmiany w strukturze bazy danych wprowadzane są dość często, nawet przez wielu programistów, więc potrzebujemy uniwersalnego mechanizmu, żeby te zmiany śledzić i wprowadzać. 

Dodawanie pierwszej migracji niewiele różni się od dodawania kolejnych. Musisz otworzyć okno terminala w lokalizacji projektu i wykonać polecenie:

dotnet ef migrations add InitMigration

Po pomyślnym wykonaniu tego polecenia zostanie wygenerowany plik migracji, w którym można sprawdzić, jakie zmiany zostaną zastosowane.

W tym pliku znajdziesz dwie metody: Up i Down. Reprezentują zmiany, kiedy migracja zostanie zastosowana i kiedy zostanie wycofana.

    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Rooms",
                columns: table => new
                {
                    Id = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Number = table.Column<int>(nullable: false),
                    Description = table.Column<string>(nullable: true),
                    LastBooked = table.Column<DateTime>(nullable: false),
                    Level = table.Column<int>(nullable: false),
                    RoomType = table.Column<int>(nullable: false),
                    NumberOfPlacesToSleep = table.Column<int>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Rooms", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Rooms");
        }
    }

Ostatnią rzeczą do zrobienia jest uruchomienie aktualizacji bazy danych. Byłoby wspaniale, gdyby nasze zmiany były sprawdzane i stosowane przy każdym uruchomieniu projektu. Zobaczmy zatem, jak możemy to osiągnąć. Przede wszystkim przejdźmy do pliku Startup.cs i utwórzmy metodę.

    private void UpgradeDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetService<PrimeDbContext>();
            if (context != null && context.Database != null)
            {
                context.Database.Migrate();
            }
        }
    }

Ta metoda wykorzysta wbudowany mechanizm wstrzykiwania zależności do pobrania instancji naszego PrimeDbContext i użycia jej do uruchomienia migracji bazy danych. Uruchomione zostaną tylko te, które nie zostały jeszcze zastosowane.

Pozostaje jeszcze jedna linia do dodania w metodzieConfigure, na samym dole.

    UpgradeDatabase(app);

Jeśli spojrzymy na bazę danych, zobaczymy, jakie migracje zostały zastosowane. Tabela __EFMigrationsHistory zostanie utworzona automatycznie przez Entity Framework Core.

Używanie EF Core 5

Gdy mamy już wszystko na miejscu, odpowiednią konfigurację i migracje baz danych, możemy zacząć korzystać z mechanizmu O/RM.

Wszystkie operacje na tabelach w EF Core muszą przejść przez PrimeDbContext. Korzystanie z niego jest bardzo proste, gdy zarejestrujemy go w klasie Startup.cs, będzie on dostępny w dowolnej klasie do wstrzyknięcia i użycia. Spójrz na ten przykład prostych operacji CRUD w RoomController.

    [ApiController]
    [Route("[controller]")]
    public class RoomController : ControllerBase
    {
        private readonly PrimeDbContext primeDbContext;

        public RoomController(PrimeDbContext _primeDbContext)
        {
            primeDbContext = _primeDbContext;
        }

        [HttpGet]
        public async Task<IEnumerable<Room>> Get()
        {
            return await primeDbContext.Rooms.ToListAsync();
        }

        [HttpGet("{id}")]
        public async Task<IActionResult> Get(int id)
        {
            var room = await primeDbContext.Rooms.FindAsync(id);
            if (room == null)
            {
                return NotFound();
            }

            return Ok(room);
        }

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] Room room)
        {
            var createdRoom = await primeDbContext.Rooms.AddAsync(room);
            await primeDbContext.SaveChangesAsync();

            return Ok(createdRoom.Entity);
        }

        [HttpPut]
        public async Task<IActionResult> Put([FromBody] Room room)
        {
            var existingRoom = await primeDbContext.Rooms.FindAsync(room.Id);
            if (existingRoom == null)
            {
                return NotFound();
            }

            existingRoom.Number = room.Number;
            existingRoom.Description = room.Description;
            existingRoom.LastBooked = room.LastBooked;
            existingRoom.Level = room.Level;
            existingRoom.RoomType = room.RoomType;
            existingRoom.NumberOfPlacesToSleep = room.NumberOfPlacesToSleep;

            var updatedRoom = primeDbContext.Update(existingRoom);
            await primeDbContext.SaveChangesAsync();
            return Ok(updatedRoom.Entity);
        }

        [HttpDelete("{id}")]
        public async Task<IActionResult> Delete(int id)
        {
            var existingRoom = await primeDbContext.Rooms.FindAsync(id);
            if (existingRoom == null)
            {
                return NotFound();
            }

            var removedRoom = primeDbContext.Rooms.Remove(existingRoom);
            await primeDbContext.SaveChangesAsync();

            return Ok(removedRoom.Entity);
        }
    }

Zauważ, że w EF Core każda metoda ma wersję asynchroniczną. Wykorzystanie asynchroniczności jest dobrym pomysłem. W ten sposób Twój kod będzie szybszy i może być uruchamiany wydajniej z wieloma innymi żądaniami równolegle.

Ważne rzeczy, o których należy pamiętać:

  • możemy wyszukiwać kolekcje encji w sposób, w jaki chcemy z LINQ, używając Where, Select i innych metod, które na koniec wygenerują SQL ze wszystkich tych warunków
  • Jeśli tylko filtrujesz encje do wyświetlenia, możesz użyć AsNoTracking() w celu poprawy wydajności
  • Wywołanie bazy danych zostanie wykonane dopiero wtedy, gdy kod, który piszemy, wymaga wyników. Dzieje się tak na przykład, gdy używamy ToListAsync
  • Wszystkie zmiany, które wprowadzamy, należy zapisać za pomocą SaveChangesAsync, aby je zapisać w bazie danych

To tylko kilka punktów, o których należy pamiętać, ale jest jeszcze wiele rzeczy dziejących się pod spodem, o których warto wiedzieć. To wprowadzenie wystarczy jednak na początek i jest więcej niż wystarczające, aby samodzielnie zacząć pracę z Entity Framework Core.

Podsumowanie

Schludnie i wygodnie! Entity Framework Core jest idealny do prawie każdego prostego użycia bazy danych. Jestem pewien, że uznasz jego możliwości za przydatne i intuicyjne.

Cały kod opublikowany w tym poście jest dostępny na moim GitHub, więc możesz go dowolnie ściągać i modyfikować. Zerknij także na post jak uruchomić projekt PrimeHotel: PrimeHotel – jak uruchomić projekt

Dzięki za przeczytanie, daj mi znać, jeśli podoba Ci się ten post 🙂

PrimeHotel – adding Entity Framework Core 5 in .NET

Let’s have a look at how to introduce Entity Framework Core 5 in ASP.NET Core project in .NET 5. We will start from an empty database, where we have a clean slate and can add tables the way we want.

In this post we will work with the PrimeHotel project, that was created for learning purposes. It’s all available at my GitHub, so you can download it freely. Take a look also at this post on how to run it: PrimeHotel – how to run this project.

What is Entity Framework Core

Entity Framework Core 5 is a lightweight, extensible, open-source, and cross-platform version of the popular Entity Framework data access technology. EF Core is an object-relational mapper (O/RM), enables developers to work with a database using .NET objects, and eliminating the need for most of the data-access code they usually need to write. This means no more SQLs. It proves to be great for most of the scenarios, however, when you need to work with big amounts of data, you might be better off with writing SQLs.

Adding an Entity Framework Core

Adding EF Core to an ASP.NET Core project is super easy. Start with installing NuGet packages:

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.SqlServer

Once it’s all done, add a PrimeDbContext in the Models folder, that would look like this:

    public class PrimeDbContext : DbContext
    {
        public PrimeDbContext(DbContextOptions<PrimeDbContext> options)
            : base(options)
        {
        }

        public virtual DbSet<Room> Rooms { get; set; }
    }

Now we need to add a Room class, that would represent an entity of a room, from Rooms table.

    public class Room
    {
        public int Id { get; set; }

        public int Number { get; set; }

        public string Description { get; set; }

        public DateTime LastBooked { get; set; }

        public int Level { get; set; }

        public RoomType RoomType { get; set; }

        public int NumberOfPlacesToSleep { get; set; }
    }

    public enum RoomType
    {
        Standard,
        Suite
    }

Now let’s handle the configuration part. Let’s use an empty database, that is hosted by us locally. The easiest approach is to install SQL Server Express edition and setup it locally. However, you can set up your database server in the docker container. Check my post on how to do it: Set up a SQL Server in a docker container.

In appsettings.json file we need to set our connection string. It should look similar to this:

Now let’s go to the Startup.cs file, where we need to configure EF Core to use our connection string. In ConfigureServices method, add this line:

    // Entity Framework
    services.AddDbContext<PrimeDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("HotelDB")));

Notice that I used a HotelDB name, that is a name of my connection string in the appsettings.json file.

We have most of the crucial things done, but we need something, that would create tables in DB from our PrimeDbContext. So far we got only one, but it’s the right time to introduce migration mechanisms.

Adding EF Core migrations

Migrations in the EF Core database allow you to make changes to the database so that it is in line with the code of the application that uses it. This is a very important mechanism because changes in the structure of the database are introduced quite often, even by many programmers, so we need a universal mechanism to track and introduce these changes.

Adding first migration doesn’t differ much from adding the next ones. You need to open a terminal window in the location of the project and execute the command:

dotnet ef migrations add InitialCreate

When this command executes successfully, it will generate a migration file, where you can check what changes will be applied.

In this file you will find two methods: Up and Down. Those will represent the changes when migration will be applied and when it would be rolled back.

    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Rooms",
                columns: table => new
                {
                    Id = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Number = table.Column<int>(nullable: false),
                    Description = table.Column<string>(nullable: true),
                    LastBooked = table.Column<DateTime>(nullable: false),
                    Level = table.Column<int>(nullable: false),
                    RoomType = table.Column<int>(nullable: false),
                    NumberOfPlacesToSleep = table.Column<int>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Rooms", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Rooms");
        }
    }

The last thing left to do is to trigger updating the database. It would be great if our changes were checked and applied on every project run. Let’s see how we can accomplish that. First of all, let’s go to Startup.cs file and create a method. 

    private void UpgradeDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetService<PrimeDbContext>();
            if (context != null && context.Database != null)
            {
                context.Database.Migrate();
            }
        }
    }

This method will use built-in Dependency Injection mechanism to fetch an instance of our PrimeDbContext and use it to run database migrations. Only ones that were not applied yet will be run.

Now, in the Configure method add a line at the bottom.

    UpgradeDatabase(app);

If we take a look into the database, we will see what migrations were applied. __EFMigrationsHistory table is created automatically by Entity Framework Core.

Using EF Core 5

Once we have everything in place, we have a proper configuration and database migrations, we can start benefit from having an O/RM mechanism.

All operations on tables in EF Core needs to go through PrimeDbContext. Using it is super simple, once we registered it in Startup.cs class, it will be available in any class for us to use. Take a look at this example of simple CRUD operations in the RoomController.

    [ApiController]
    [Route("[controller]")]
    public class RoomController : ControllerBase
    {
        private readonly PrimeDbContext primeDbContext;

        public RoomController(PrimeDbContext _primeDbContext)
        {
            primeDbContext = _primeDbContext;
        }

        [HttpGet]
        public async Task<IEnumerable<Room>> Get()
        {
            return await primeDbContext.Rooms.ToListAsync();
        }

        [HttpGet("{id}")]
        public async Task<IActionResult> Get(int id)
        {
            var room = await primeDbContext.Rooms.FindAsync(id);
            if (room == null)
            {
                return NotFound();
            }

            return Ok(room);
        }

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] Room room)
        {
            var createdRoom = await primeDbContext.Rooms.AddAsync(room);
            await primeDbContext.SaveChangesAsync();

            return Ok(createdRoom.Entity);
        }

        [HttpPut]
        public async Task<IActionResult> Put([FromBody] Room room)
        {
            var existingRoom = await primeDbContext.Rooms.FindAsync(room.Id);
            if (existingRoom == null)
            {
                return NotFound();
            }

            existingRoom.Number = room.Number;
            existingRoom.Description = room.Description;
            existingRoom.LastBooked = room.LastBooked;
            existingRoom.Level = room.Level;
            existingRoom.RoomType = room.RoomType;
            existingRoom.NumberOfPlacesToSleep = room.NumberOfPlacesToSleep;

            var updatedRoom = primeDbContext.Update(existingRoom);
            await primeDbContext.SaveChangesAsync();
            return Ok(updatedRoom.Entity);
        }

        [HttpDelete("{id}")]
        public async Task<IActionResult> Delete(int id)
        {
            var existingRoom = await primeDbContext.Rooms.FindAsync(id);
            if (existingRoom == null)
            {
                return NotFound();
            }

            var removedRoom = primeDbContext.Rooms.Remove(existingRoom);
            await primeDbContext.SaveChangesAsync();

            return Ok(removedRoom.Entity);
        }
    }

Notice that in EF Core there is an asynchronous version of every method. Taking advantage of this is a good idea. This way your code will be faster and could be run more efficiently with many other requests in parallel.

Important things to have in mind:

  • we can query entities collections the way we want with LINQ using Where, Select and other methods and that will generate SQL out of all those conditions
  • If you’re just querying entities, you can use AsNoTracking() to improve performance
  • A call to the database will be performed when the code we write needs the results. This is for example where we use ToListAsync
  • All changes that we make needs to be saved with SaveChangesAsync to be applied

Those are only a few points to have in mind, but there us much more that is going underneath to be aware of. However, this is good for a start, and it more than enough to play with Entity Framework Core on your own.

Summary

Nice and clean! Entity Framework Core is perfect for almost every simple database usage. I’m sure you’ll find it useful and intuitive.

All code posted here is available at my GitHub, so you can download it freely. Take a look also at this post on how to run it: PrimeHotel – how to run this project.

Thanks for reading, let me know if you liked this post 🙂

PrimeHotel – przekazywanie parametrów do akcji – zadania

To jest post z zadaniami do zrobienia, jeśli chcesz sprawdzić swoją wiedzę na temat ASP.NET Core w .NET 5. Ten wpis dotyczy przekazywania parametrów do akcji kontrolera, co jest niezwykle ważne do opanowania podczas tworzenia mikro-serwisów.

Nie musisz zaczynać od zera, możesz bazować na projekcie PrimeHotel, stworzonym specjalnie do celów edukacyjnych. Możesz pobrać go na mojej stronie GitHub. Zobacz także post dotyczący tego projektu: PrimeHotel – jak uruchomić projekt

Pełny artykuł na temat przekazywania parametrów do akcji w ASP.NET Core w .NET 5 można znaleźć tutaj: ASP.NET Core w .NET 5 – przekazywanie parametrów do akcji

Zadanie 1

Trudność: łatwa

Kontekst

Dowiedz się, jak pisać operacje CRUD. Powiedzmy, że chcielibyśmy obsługiwać faktury – dodaj wszystkie metody, które pozwolą na obsługę faktur.

Co musi być zrobione

  • utwórz nową klasę o nazwie Invoice
  • utwórz metody Add, Get, Update oraz Delete do obsługi faktur
  • lista faktur może być zakodowana na stałe w klasie kontrolera
  • dodaj opcjonalne filtrowanie w metodzie Get z parametrami ciągu zapytania

Wskazówka

Spójrz na WeatherForecastController i jak tam obsługujemy prognozy pogody.

Zadanie 2

Trudność: średnia

Kontekst

Dowiedz się, jak przekazać tablicę w ciągu zapytania. Ten sposób może być przydatny, gdy chcesz przekazać kolekcję obiektów, ale musisz użyć do tego ciągu zapytania

Co musi być zrobione

  • utwórz metodę GET
  • metoda musi zaakceptować tablicę liczb całkowitych z ciągu zapytania
  • jak wywołałbyś tę metodę i przekazał parametry?

Gdzie zamieszczać odpowiedzi?

Po prostu napisz komentarz do tego posta, spojrzę.

Lub, jeśli masz na to ochotę, zgłoś pull request do repozytorium PrimeHotel.

Powodzenia! 🙂