Entity Framework Core (EF Core) is a .NET object-relational mapper: it maps application objects, called entities, to data in a database. It is useful when an application must retain and query data too large or interconnected to manage conveniently in memory. Instead of writing every SQL query by hand with ADO.NET, you work with entities and queries in C#. The abstraction saves code, but it is not always the right choice when SQL performance is critical. section 5.0 section 5.1
A code-first setup begins with an entity class and a context. For example, a Book with Id and Title can be exposed through a DbSet<Book> on a class derived from DbContext. EF Core recognizes Id as a primary key by convention; a different key can be marked with [Key]. The context also selects a database provider. The in-memory provider makes initial development easy, but it does not use SQL and should not be mistaken for a persistent database. section 5.2 section 5.6
Listing 5.3 A DbContext that holds the Book class
using Microsoft.EntityFrameworkCore;
namespace ManningBooks;
public class CatalogContext : DbContext #1
{
public DbSet<Book> Books { get; set; } #2
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseInMemoryDatabase("ManningBooks"); #3
}
A compact context shows the two central pieces together: DbSet<Book> exposes the entities, and OnConfiguring selects the in-memory provider. section 5.2
Creating an entity and adding it to a context is not the final step: call SaveChanges to save it. Query the DbSet with LINQ, such as OrderBy(b => b.Id), to retrieve an ordered result. Familiar SQL ideas—filtering, ordering, grouping and projection—still apply, though LINQ expresses them differently. EF Core also supports mappings more complex than one table per .NET type. section 5.2 section 5.1
Listing 5.5 Adding Books to CatalogContext and getting ordered list
using ManningBooks;
using var dbContext = new CatalogContext(); #1
dbContext.Add(new Book { Title = ".NET in Action" }); #2
dbContext.Add(new Book { Title = "API Design Patterns" }); #3
dbContext.Add(new Book { Title = "Grokking Simplicity" });
dbContext.Add(new Book { Title = "The Programmer's Brain" });
dbContext.SaveChanges(); #4
foreach (var book in dbContext.Books.OrderBy(b => b.Id)) #5
{
Console.WriteLine($"\"{book.Title}\" has id {book.Id}"); #6
}
Follow the complete first pass: create a context, add books, call SaveChanges, then enumerate an ordered query. section 5.2
For a web API, ASP.NET Core controllers can use EF Core to create, retrieve, update and delete entities. Database requests can be slow, so asynchronous access helps avoid blocking application threads. SQLite provides a lightweight SQL database that can run in memory or use a file. section 5.4 section 5.6
Testing needs a deliberate provider choice. Although EF Core’s in-memory provider is convenient for development, its documentation advises against relying on it for unit or integration tests. An in-memory SQLite database is a lightweight option for integration tests. EF Core can store immutable records when they are only added or retrieved; replacing records to perform updates conflicts with its change tracking. EF Core guards against SQL injection, but generated SQL still merits inspection. section 5.2 section 8.6 section 8.1 section 9.7



