跳到主要内容

Entity Framework Core

What EF Core Is (Interview One-Liner)​

EF Core is a lightweight ORM that lets you work with databases using C# objects instead of raw SQL, while still allowing full control when needed.

ORM = Object ↔ Relational Mapper


How EF Core Works (Big Picture)​

Think in 3 layers:

C# Entities
↓
EF Core Mapping
↓
Database Tables

Core Flow:​

  1. You define entities (C# classes)
  2. DbContext tracks them
  3. You query using LINQ
  4. EF Core translates LINQ → SQL
  5. Database executes SQL
  6. Results → C# objects

Core Building Blocks (Must Memorize)​

🔹 Entity​

  • A C# class
  • Represents one database table
  • Properties = columns
public class Person
{
public Guid PersonID { get; set; }
public string PersonName { get; set; }
}

🔹 DbContext (VERY IMPORTANT)​

DbContext = a session with the database

Responsibilities:

  • Database connection
  • Change tracking
  • LINQ → SQL translation
  • Saving changes
public class PersonsDbContext : DbContext
{
public DbSet<Person> Persons { get; set; }
}

📌 Lifetime: Scoped (one per request)


🔹 DbSet<T>​

DbSet = a table

_db.Persons.Add(person);
_db.Persons.Where((p) => p.Name == "John");

EF Core Query Lifecycle (Interview Gold ⭐)​

LINQ → Expression Tree → SQL → Database → Objects
  • Queries are not executed immediately
  • Executed only when:
    • ToList()
    • FirstOrDefault()
    • Single()

This is called deferred execution.


Change Tracking (Why EF Core Feels "Magic")​

EF Core tracks entity states:

StateMeaning
AddedWill INSERT
ModifiedWill UPDATE
DeletedWill DELETE
UnchangedNo action
_db.Persons.Add(person);
_db.SaveChanges(); // generates SQL

📌 Interview line:

"EF Core detects changes automatically and generates the correct SQL."


CRUD with EF Core (Service Layer)​

Create​

_db.Persons.Add(person);
await _db.SaveChangesAsync();

Read​

await _db.Persons.ToListAsync();

Update​

person.Name = "New";
await _db.SaveChangesAsync();

Delete​

_db.Persons.Remove(person);
await _db.SaveChangesAsync();

Relationships (VERY COMMON INTERVIEW TOPIC)​

Relationship Types​

  • One-to-One
  • One-to-Many ⭐
  • Many-to-Many

Example: Country → Persons (1 → Many)​

entity
.HasOne((p) => p.Country)
.WithMany((c) => c.Persons)
.HasForeignKey((p) => p.CountryID);
public Country Country { get; set; }

❌ Lazy Loading (avoid)​

  • Hidden queries
  • Performance issues

✅ Eager Loading​

_db.Persons.Include((p) => p.Country);

📌 Interview rule:

"Only load what you need."


9️⃣ Configuration: Data Annotations vs Fluent API​

Data Annotations​

  • Simple
  • Close to model
  • Limited
[Required][MaxLength(50)];

Fluent API ⭐ (Preferred)​

  • More powerful
  • Clean entities
  • Centralized
modelBuilder.Entity<Person>()
.Property(p => p.Name)
.HasMaxLength(50)
.IsRequired();

📌 Interview answer:

"Fluent API is better for complex rules and separation of concerns."


Code First vs Database First​

Code FirstDatabase First
Start from C#Start from DB
MigrationsScaffold
FlexibleLegacy DB

📌 Most modern apps → Code First


Migrations (SUPER IMPORTANT)​

Migrations keep your database schema in sync with your code

Common Commands​

Add-Migration AddPersonsTable
Update-Database

Each migration:

  • Up() → apply
  • Down() → rollback

📌 Best practice:

  • Small migrations
  • Clear names
  • Review generated SQL

Seed Data​

Used for:

  • Lookup tables
  • Demo data
  • Dev/test environments
modelBuilder.Entity<Country>()
.HasData(new Country { CountryID = ..., CountryName = "Japan" });

📌 Interview tip:

"Seed data is versioned via migrations."


Connection Strings​

Stored in:

  • appsettings.json
  • Environment variables
  • User secrets
options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection"),
);

📌 Production → environment variables / Key Vault


Async EF Core (NON-NEGOTIABLE)​

Always use:

  • ToListAsync
  • SaveChangesAsync

Why?

  • Scalability
  • Non-blocking threads

📌 Interview line:

"Async EF prevents thread starvation under load."


Stored Procedures (When Needed)​

EF Core supports them:

_db.Persons.FromSqlRaw("EXEC GetAllPersons");

Use when:

  • Legacy DB
  • Complex SQL
  • Performance-critical paths

Best Practices (Memorize This List)​

✅ Use services (not controllers) ✅ Use async everywhere ✅ Use DTOs ✅ Avoid lazy loading ✅ Use Include carefully ✅ Prefer Fluent API ✅ Small migrations ❌ Don't expose DbContext everywhere


One-Paragraph Interview Answer​

"EF Core is a modern ORM that allows us to work with relational data using strongly typed C# objects. It uses DbContext to track changes and translate LINQ queries into SQL. We typically use Code First with migrations to manage schema changes, Fluent API for configuration, async operations for scalability, and services to encapsulate data access logic. EF Core improves productivity while still allowing raw SQL or stored procedures when needed."


If You Remember ONLY 7 Things​

  1. DbContext = database session
  2. DbSet = table
  3. LINQ → SQL
  4. Change tracking
  5. Include for relationships
  6. Migrations sync schema
  7. Async everywhere