Kurse:Entity Framework Core: Unterschied zwischen den Versionen

Aus ahrensburg.city
Zur Navigation springen Zur Suche springen
Die Seite wurde neu angelegt: „= Entity Framework Core (EF Core) Spickzettel = == Was ist EF Core? == * EF Core ist ein moderner, leichter und erweiterbarer Object-Relational Mapper (ORM) für .NET. * Erlaubt die Arbeit mit Datenbankdaten als .NET-Objekte (Entities), anstatt mit SQL-Queries. == Grundkonzepte == * '''Entities''': C#-Klassen, die Datenbanktabellen repräsentieren. * '''DbContext''': Brücke zwischen Entities und Datenbank. * '''DbSet<TEntity>''': Sammlung einer Entitä…“
 
Keine Bearbeitungszusammenfassung
 
Zeile 1: Zeile 1:
= Entity Framework Core (EF Core) Spickzettel =
== EF Core Cheatsheet (Deutsch) ==


== Was ist EF Core? ==
=== DbContext & DbSet ===
* EF Core ist ein moderner, leichter und erweiterbarer Object-Relational Mapper (ORM) für .NET.
* Erlaubt die Arbeit mit Datenbankdaten als .NET-Objekte (Entities), anstatt mit SQL-Queries.
 
== Grundkonzepte ==
* '''Entities''': C#-Klassen, die Datenbanktabellen repräsentieren.
* '''DbContext''': Brücke zwischen Entities und Datenbank.
* '''DbSet<TEntity>''': Sammlung einer Entität (Tabelle).
 
== Beispiel: Entities und DbContext ==
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
public class Country
{
    public int CountryID { get; set; }
    public string CountryName { get; set; }
    public ICollection<Person> Persons { get; set; }
}
public class Person
{
    public int PersonID { get; set; }
    public string PersonName { get; set; }
    public int CountryID { get; set; }
    public Country Country { get; set; }
}
public class PersonsDbContext : DbContext
public class PersonsDbContext : DbContext
{
{
    public DbSet<Person> Persons { get; set; }
     public DbSet<Country> Countries { get; set; }
     public DbSet<Country> Countries { get; set; }
    public DbSet<Person> Persons { get; set; }
 
     protected override void OnModelCreating(ModelBuilder modelBuilder)
     protected override void OnModelCreating(ModelBuilder modelBuilder)
     {
     {
Zeile 38: Zeile 16:
</syntaxhighlight>
</syntaxhighlight>


== Wichtige NuGet-Pakete ==
=== Verbindungskette (appsettings.json) ===
* <code>Microsoft.EntityFrameworkCore</code>
<syntaxhighlight lang="json">
* <code>Microsoft.EntityFrameworkCore.SqlServer</code> (oder Sqlite, Npgsql etc.)
{
* <code>Microsoft.EntityFrameworkCore.Tools</code>
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=PersonsDatabase;Integrated Security=True"
  }
}
</syntaxhighlight>


== Verbindung zur Datenbank ==
=== DI Registrierung (Program.cs) ===
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
// In Program.cs oder Startup.cs
builder.Services.AddDbContext<PersonsDbContext>(options =>
builder.Services.AddDbContext<PersonsDbContext>(options =>
     options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
     options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
</syntaxhighlight>
</syntaxhighlight>


''appsettings.json'':
=== LINQ-Abfrage mit Navigation ===
<syntaxhighlight lang="json">
<syntaxhighlight lang="csharp">
{
var peopleFromUSA = _dbContext.Persons
  "ConnectionStrings": {
    .Include(p => p.Country)
     "DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=PersonsDatabase;Integrated Security=True;"
    .Where(p => p.Country.CountryName == "USA")
  }
     .ToList();
}
</syntaxhighlight>
 
=== Seed Data mit JSON-Dateien ===
<syntaxhighlight lang="csharp">
var countries = JsonSerializer.Deserialize<List<Country>>(File.ReadAllText("countries.json"));
modelBuilder.Entity<Country>().HasData(countries);
</syntaxhighlight>
</syntaxhighlight>


== Datenbank initialisieren (Seeding) ==
=== Fluent API Beispiel ===
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<Person>()
{
    .Property(p => p.TIN)
    modelBuilder.Entity<Country>().HasData(
    .HasColumnName("TaxID")
        new Country { CountryID = 1, CountryName = "Deutschland" }
     .HasColumnType("varchar(8)")
    );
    .HasDefaultValue("ABC12345");
     modelBuilder.Entity<Person>().HasData(
        new Person { PersonID = 1, PersonName = "Max Mustermann", CountryID = 1 }
    );
}
</syntaxhighlight>
</syntaxhighlight>


== Code First Migration ==
=== Migrationen (Konsole) ===
# Migration erstellen:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
dotnet ef migrations add InitialCreate
dotnet ef migrations add InitialCreate
</syntaxhighlight>
# Migration anwenden:
<syntaxhighlight lang="bash">
dotnet ef database update
dotnet ef database update
</syntaxhighlight>
</syntaxhighlight>


== CRUD-Operationen mit EF Core ==
=== Stored Procedure (Aufruf) ===
* '''Create''': 
  <syntaxhighlight lang="csharp">
var person = new Person { PersonName = "Anna" };
context.Persons.Add(person);
context.SaveChanges();
  </syntaxhighlight>
* '''Read''': 
  <syntaxhighlight lang="csharp">
var people = context.Persons.ToList();
var one = context.Persons.FirstOrDefault(p => p.PersonID == 1);
  </syntaxhighlight>
* '''Update''': 
  <syntaxhighlight lang="csharp">
var person = context.Persons.Find(1);
person.PersonName = "Maria";
context.SaveChanges();
  </syntaxhighlight>
* '''Delete''': 
  <syntaxhighlight lang="csharp">
var person = context.Persons.Find(1);
context.Persons.Remove(person);
context.SaveChanges();
  </syntaxhighlight>
 
== Beziehungen (Relationships) ==
* '''One-to-Many''': Ein Land hat viele Personen, eine Person gehört zu einem Land.
* '''Foreign Key''' wird automatisch erkannt (CountryID in Person).
* Mit Navigation Properties arbeiten.
 
== LINQ-Abfragen ==
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
var deutsche = context.Persons.Where(p => p.Country.CountryName == "Deutschland").ToList();
public List<Person> GetPersons() =>
    Persons.FromSqlRaw("EXEC dbo.GetAllPersons").ToList();
</syntaxhighlight>
</syntaxhighlight>


== Eager Loading mit Include ==
=== Create (Controller POST) ===
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
var personsWithCountry = context.Persons.Include(p => p.Country).ToList();
[HttpPost]
</syntaxhighlight>
public async Task<IActionResult> Create(PersonAddRequest request)
{
    if (ModelState.IsValid)
    {
        await _personsService.AddPerson(request);
        return RedirectToAction("Index");
    }


== Fluent API (Erweiterte Konfiguration) ==
     ViewBag.Countries = await _countriesService.GetAllCountries();
<syntaxhighlight lang="csharp">
     return View(request);
modelBuilder.Entity<Person>()
}
     .Property(p => p.PersonName)
    .IsRequired()
     .HasMaxLength(100);
</syntaxhighlight>
</syntaxhighlight>


== Stored Procedures verwenden ==
=== PDF mit Rotativa ===
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
// Select
public async Task<IActionResult> PersonsPDF()
var result = context.Persons.FromSqlRaw("EXEC GetAllPersons").ToList();
{
// Insert
    var persons = await _personsService.GetAllPersons();
context.Database.ExecuteSqlRaw("EXEC InsertPerson @Name", new SqlParameter("@Name", "Max"));
    return new ViewAsPdf("PersonsPDF", persons)
    {
        PageOrientation = Orientation.Landscape,
        PageMargins = { Top = 20, Bottom = 20, Left = 20, Right = 20 }
    };
}
</syntaxhighlight>
</syntaxhighlight>


== Dateien generieren (PDF/CSV) ==
=== CSV mit CsvHelper ===
* '''PDF (z.B. mit Rotativa):'''
<syntaxhighlight lang="csharp">
return new ViewAsPdf("PersonsPDF", personsList);
</syntaxhighlight>
* '''CSV (mit CsvHelper):'''
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
using (var writer = new StreamWriter("file.csv"))
public async Task<MemoryStream> GetPersonsCSV()
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
{
     csv.WriteRecords(personsList);
    var stream = new MemoryStream();
    using var writer = new StreamWriter(stream, leaveOpen: true);
    using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
   
    var persons = await _dbContext.Persons.Include(p => p.Country).ToListAsync();
     csv.WriteRecords(persons);
    writer.Flush();
    stream.Position = 0;
    return stream;
}
}
</syntaxhighlight>
</syntaxhighlight>


== Best Practices ==
=== Beziehungskonfiguration (Fluent API) ===
* Asynchrone Methoden verwenden: <code>await context.SaveChangesAsync()</code>
<syntaxhighlight lang="csharp">
* Migrationen immer ins Source Control aufnehmen
modelBuilder.Entity<Person>()
* Validierung auf Model- und View-Ebene
    .HasOne(p => p.Country)
* Repository-Pattern für größere Projekte
    .WithMany(c => c.Persons)
 
    .HasForeignKey(p => p.CountryID);
== Interviewfragen-Vorbereitung ==
</syntaxhighlight>
* Was ist ein ORM? Wie funktioniert EF Core?
* Unterschied zwischen Code First und Database First?
* Wie werden Beziehungen zwischen Tabellen definiert?
* Wozu dient die Migration?
* Wie funktioniert Change Tracking?
 
== Häufige Fehler ==
* Vergessen: SaveChanges() oder SaveChangesAsync()
* Falsche/fehlende Navigation Properties
* Verbindungskette falsch/fehlt
* Nicht alle Migrations ausgeführt
 
----
''Tipp:'' Für weitere Beispiele siehe offizielle EF Core Dokumentation: https://learn.microsoft.com/de-de/ef/core/

Aktuelle Version vom 29. Juni 2025, 21:46 Uhr

EF Core Cheatsheet (Deutsch)

DbContext & DbSet

public class PersonsDbContext : DbContext
{
    public DbSet<Person> Persons { get; set; }
    public DbSet<Country> Countries { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Country>().ToTable("Countries");
        modelBuilder.Entity<Person>().ToTable("Persons");
    }
}

Verbindungskette (appsettings.json)

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

DI Registrierung (Program.cs)

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

LINQ-Abfrage mit Navigation

var peopleFromUSA = _dbContext.Persons
    .Include(p => p.Country)
    .Where(p => p.Country.CountryName == "USA")
    .ToList();

Seed Data mit JSON-Dateien

var countries = JsonSerializer.Deserialize<List<Country>>(File.ReadAllText("countries.json"));
modelBuilder.Entity<Country>().HasData(countries);

Fluent API Beispiel

modelBuilder.Entity<Person>()
    .Property(p => p.TIN)
    .HasColumnName("TaxID")
    .HasColumnType("varchar(8)")
    .HasDefaultValue("ABC12345");

Migrationen (Konsole)

dotnet ef migrations add InitialCreate
dotnet ef database update

Stored Procedure (Aufruf)

public List<Person> GetPersons() =>
    Persons.FromSqlRaw("EXEC dbo.GetAllPersons").ToList();

Create (Controller POST)

[HttpPost]
public async Task<IActionResult> Create(PersonAddRequest request)
{
    if (ModelState.IsValid)
    {
        await _personsService.AddPerson(request);
        return RedirectToAction("Index");
    }

    ViewBag.Countries = await _countriesService.GetAllCountries();
    return View(request);
}

PDF mit Rotativa

public async Task<IActionResult> PersonsPDF()
{
    var persons = await _personsService.GetAllPersons();
    return new ViewAsPdf("PersonsPDF", persons)
    {
        PageOrientation = Orientation.Landscape,
        PageMargins = { Top = 20, Bottom = 20, Left = 20, Right = 20 }
    };
}

CSV mit CsvHelper

public async Task<MemoryStream> GetPersonsCSV()
{
    var stream = new MemoryStream();
    using var writer = new StreamWriter(stream, leaveOpen: true);
    using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
    
    var persons = await _dbContext.Persons.Include(p => p.Country).ToListAsync();
    csv.WriteRecords(persons);
    writer.Flush();
    stream.Position = 0;
    return stream;
}

Beziehungskonfiguration (Fluent API)

modelBuilder.Entity<Person>()
    .HasOne(p => p.Country)
    .WithMany(c => c.Persons)
    .HasForeignKey(p => p.CountryID);