Fullstack - ASP.NET Entwicklung mit DotNet Core und Vue.js - Teil 3 - Einbinden PostgreSQL als Datenbank

Einleitung

Nachdem die Basis für die Entwicklung steht und auch unser Source Code jetzt in der Sourcevewaltung bereit steht, kann mit der Einbindung der Datenbank begonnen werden.

Dieser Artikel ist eine Serie von Artikeln, die den Aufbau einer Fullstack Applikation unter DotNet Core und Vue.js beschreiben.

Bisher sind folgende Artikel erschienen:

  • Fullstack - ASP.NET Entwicklung mit DotNet Core und Vue.js - Erste Schritte Link
  • Fullstack - ASP.NET Entwicklung mit DotNet Core und Vue.js - Teil 2 Link
  • Fullstack - ASP.NET Entwicklung mit DotNet Core und Vue.js - Teil 3 - Einbinden PostgreSQL als Datenbank Link
  • Fullstack - ASP.NET Entwicklung mit DotNet Core und Vue.js - Teil 4 - Erweiterung um ein Repository Pattern und Service Layer Link
  • Fullstack - ASP.NET Entwicklung mit DotNet Core und Vue.js - Teil 5 - Erste Schritte mit Vue.js und Typescript Link
  • Fullstack - ASP.NET Entwicklung mit DotNet Core und Vue.js - Teil 6 - Erweiterung um Vuex und Axios Link

Einbinden des Entity Frameworks

Um Effizient mit Datenbanken arbeiten zu können, bietet DotNet Core das sogenannte Entity Framework an. Dieses kann recht einfach dem Projekt hinzugfügt werden als neues Package:

dotnet add package Microsoft.EntityFrameworkCore.SqlServer  

Für das Design der Packete wird folgendes Paket benötigt:

dotnet add package Microsoft.EntityFrameworkCore.Design  

Über die folgende Website von Microsoft kann man sich die unterstützen Provider ansehen, die das Entity Framework Core unterstützt: https://docs.microsoft.com/de-de/ef/core/providers/

In unseren Fall möchten wir mit einer Postgres SQL Datenbank arbeiten und fügen diese Pakte daher auch noch hinzu:

dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL  

Hinweis: Auf der Webseite https://www.nuget.org/ können alle Pakete die für ihre Entwicklung relevant sind rechachiert werden.

Die neuen Pakete wurden automatisch dem csporj File hinzugefügt:

Damit auch die Kommandozeilenbefehle des Entity Frameworks bereitstehen, müssen noch die Entity Framework Tools für DotNet hinzugefügt werden:

Anschließend könnten mit den folgenden Befehl die Pakete aktualisiert werden und anschließend neu gebaut:

dotnet restore  
dotnet build  

Ist alles korrekt verlaufen, steht der neue Befehlt "dotnet ef" als Kommand Line Tool zur Verfügung:

Erstellen der ersten Tabellen und Datenmodel mit Code First Ansatz

Das Entity Framework unterstützt den sogenannten Code-First Ansatz, neben anderen Ansätzen.

Bei Code First, wird das Model in C# definiert und anschließend werden automatisch die dazu gehörenden Tabellen erzeugt.

Ein weiterer Vorteil von Code First ist, dass Tabellenänderungen auch über sogenannte "Migrations" mitgeschrieben werden, die weitgehend automatisch erzeugt werden.

Zunächst ist ein neues Verzeichnis "Models" zu erstellen und dort das Model und der Datenbank Context. Als Ziel wollen wir zunächst Daten aus einer Tabelle "Wheather" lesen und auf den Bildschirm darstellen.

Es wird ein Verzeichnis "Models" und zwei Dateien "Wheather.cs" und "WheaterContext.cs" benötigt:

In "Wheater.cs" ist folgende einfache Datenstruktur abzulegen:

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

namespace DotNetVueBlog.Models  
{
    public class Wheather {
        public int ID { get; set; }

        public DateTime DateFormatted { get; set; }
        public int TemperatureC { get; set; }
        public string Summary { get; set; }
    }

}

Und im WheatherContext nur dieses Datenmodel hinzuzufügen:

using Microsoft.EntityFrameworkCore;

namespace DotNetVueBlog.Models  
{
    public class WheatherContext : DbContext
    {
        public WheatherContext(DbContextOptions<WheatherContext> options) : base(options)
        {
        }

        public DbSet<Wheather> Wheather{ get; set; }
    }
}

In der "Startup.cs" muss nun noch der Applikation gesagt werden, wie der Context einzubinden ist. Dies erfolgt über "DependencyInjection", die in DotNet Core bereits eingebaut ist. (In einen anderen Artikel werde ich dies genauer beschreiben)

services.AddDbContext<WheatherContext>(options =>  
   options.UseNpgsql(Environment.GetEnvironmentVariable("WheatherDB")));

Achtung: Hier wird dann schon deutlich, dass wir mit "UseNpgsql" eine Postgres SQL Datenbank verwenden. Sollte eine andere Datenbank verwendet werden, ist hier eine andere Injection notwendig. Beispielsweise "UseSqlServer" bei Microsoft SQL Server.

Mit Environment.GetEnvironmentVariable("WheatherDB") übergeben wir eine Environment Variable das Entity Framework. Ich mache das, damit ich später flexibel die Verbindung zum Postgres SQL Server ändern kann und ein produktives Deployment mit ggf. IP Verbindung oder Docker Verbindung entsprechend konfigurieren kann.

Installation des Postgres SQL Server und HeidiSQL als Client

Als nächstes muss auf dem lokalen Rechner "Postgres SQL" installiert werden. Als Client verwende ich gerne HeidiSQL.

Unter Windows ist der Download von folgender Seite durchzuführen: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads

Nachdem die Datei heruntergeladen ist, muss der übliche Installationsprozess durchgeklickt werden. Wichtig ist dabei vor allem, dass Sie sich ihr Passwort merken, dass Sie hier vergeben.

Anschließend können Sie HeidiSQL installieren:

https://www.heidisql.com/

Und anschließend starten. In Heidi können Sie ihre lokale Verbindung, wie folgt aufbauen. Wichtig ist, dass Sie das Passwort hier angeben, dass Sie bei der vorherigen Installation verwendet haben. Der lokale PC kann dirket über die IP-Adresse 127.0.0.1 angesprochen werden, der Default User ist "postgres":

Hat alles funktioniert, sollte Heidi nun den Inhalt des SQL Servers anzeigen:

Konfiguration für die Postgres SQL Verbindung

Die Verbindungsparameter sind für Postgres in folgenden Format anzugeben:

Host=localhost;Database=mydatabase;Username=myuser;Password=mypassword  

In unseren Beispiel wäre also die Umgebungsvariable "WheatherDB" mit den folgenden Parametern zu versorgen:

Damit der Environment-Parameter auch gezogen wird, müssen Sie "Visual Studio Code" anschließend neu starten. Und können anschließend prüfen, ob die Environment-Parameter gesetzt ist:

Initialisieren der Datenbank

Nun können wir endlich die Datenbank erzeugen. Als ersten Schritt muss die "Migration" initialisiert werden:

dotnet ef migrations add InitialCreate  

Anschließend ist ein neues Verzeichnis "Migrations" erstellt worden und entsprechender Migration Code zum erzeugen der Datenbank:

Anschließend kann mit folgenden Befehl die Datenbank aktualisiert und die Migrations eingespielt werden:

dotnet ef database update  

Verbindet man sich nun mit der Postgres in Heidi, ist es wichtig, dass man die neue Datenbank "WheatherDB" mit auswählt:

Anschließend sieht man unter "public" zwei Tabellen:

In "_EFMigrationHistory" verwaltet das EntityFramework für uns die bereits eingespielten Migrations und ermittelt über diese Tabelle automatisch, wenn wir Änderungen machen, was fehlt und spielt diese beim Befehlt "dotnet ef database update" ein.

Die "Wheather" Tabelle ist aktuell natürlich noch leer, da wir keine Daten hinterlegt haben.

Hinzufügen einer Spalte

Um das praktische Element des Entity Frameworks zu verdeutlichen, füge ich nun eine weitere neue Spalte in unser Datenmodel hinzu:

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

namespace DotNetVueBlog.Models  
{
    public class Wheather {
        public int ID { get; set; }

        public DateTime DateFormatted { get; set; }
        public int TemperatureC { get; set; }
        public string Summary { get; set; }

        public bool IsActive { get; set; }
    }

}

Anschließend sagen wir, dass wir für diese Änderung eine neue Migration benötigen:

dotnet ef migrations add ActiveFieldForWheather  

Anschließend wurde die notwendige Tabellenänderung als Migration File angelegt:

Damit man nicht jedesmal "dotnet ef database update" eintippen muss (was insbesondere nach einen Deployment auf einen anderen Server schwierigkeiten machen kann, bzw. dort zu beachten wäre), kann man im Startup.cs folgendes Einfügen:

Seeden von Spieldaten

Damit man sich nicht immer die Mühe machen muss, dass die Tabellen Beispieldaten enthalten, kann man ein Seed für Spieldaten hinzufügen.

Hierzu ist einfach in Startup für "Development" eine Methode Seed aufzurufen:

Und natürlich muss der Context noch die entsprechende Seed-Methode bekommen:

        public void EnsureSeedData()
        {
            var context = this;

            // Nur wenn die Tabelle leer ist
            if (!context.Wheather.Any()) { 
                   context.Wheather.Add(
                        new Wheather() {
                            DateFormatted = Convert.ToDateTime("2018-03-01"),
                            TemperatureC = 5,
                            Summary = "Kalt"
                        });
                    context.Wheather.Add(
                        new Wheather() {
                            DateFormatted = Convert.ToDateTime("2018-03-08"),
                            TemperatureC = 10,
                            Summary = "Kühl"
                        });
                    context.Wheather.Add(
                        new Wheather() {
                            DateFormatted = Convert.ToDateTime("2018-03-15"),
                            TemperatureC = 15,
                            Summary = "Warm"
                        });
                    context.Wheather.Add(
                        new Wheather() {
                            DateFormatted = Convert.ToDateTime("2018-03-23"),
                            TemperatureC = 20,
                            Summary = "Schön"
                        });

                    context.SaveChanges();
            }
        }

Das Linq verwendet wird, muss noch dieses hinzugefügt werden:

using System.Linq;  

Anschließend muss im Debug Modus unsere Anwendung gestartet werden und anschließend sind die Werte in der Datenbank zu finden:

Einbinden in den SampleDataController

Als letzten Schritt wollen wir natürlich die Werte auch im Browser angezeigt bekommen. Eigentlich sollte man hier noch das "Repository" Pattern anwenden, aber um den Rahmen nicht unnötig zu sprengen werden wir hier kurz ein paar wenige Anpassungen durchführen, um zu testen, ob tatsächlich alles funktionert:

Für den SampleDataController.cs muss zunächst folgende Anbindung an die Models erfolgen:

using DotNetVueBlog.Models;  

Anschließend muss der Creator eine Injection unseres Registrierten Context erhalten:

public SampleDataController(WheatherContext context)  
{
     _context = context;                
}

Anschließend muss die Methode "WheatherForecasts" angepasst werden:

        public IEnumerable<WeatherForecast> WeatherForecasts(string ort)
        {
           if (!String.IsNullOrEmpty(ort) && ort.Equals("Munich", StringComparison.InvariantCultureIgnoreCase)) {

               return _context.Wheather.Select(x => new WeatherForecast
               {
                   DateFormatted = x.DateFormatted.ToString("dd.MM.yyyy")                 ,
                   TemperatureC = x.TemperatureC,
                   Summary = x.Summary
               }).ToList();

           }

            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                DateFormatted = DateTime.Now.AddDays(index).ToString("d"),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            });
        }

Anschließend kann die Applikation gestartet werden und sollte nun die Werte aus der Datenbank anzeigen:

Zusammenfassung

Ich hoffe mit diesen Artikel umfangreich vermittelt zu haben, wie man mit Entity Framework Core eine PostgreSQL Datenbank erfolgreich anbindet. Die Daten aus der Datenbank können nun erfolgreich dargestellt werden.

Es fehlt natürlich das "Repository Pattern", dass als Layer zwischen den Controller und den Context gezogen werden sollte. In einen meiner nächsten Artikel werde ich diesen Schritt beschreiben.

Die aktuelle Version nach allen Änderungen ist als Tag v0.0.1 in GitHub hinterlegt: https://github.com/smoki99/DotNetVueBlog/releases/tag/v0.0.1

Ich wünsche viel Erfolg!