What it is
Entity Framework Core is Microsoft's official ORM for .NET, translating LINQ queries into SQL with change tracking, migrations and relationship management.
Define a DbContext with DbSet properties. Queries are LINQ expressions translated to SQL; SaveChanges computes the minimal set of statements from tracked changes.
Installation
dotnet add package Microsoft.EntityFrameworkCore.SqlServerGetting started
The smallest useful thing you can do with it, and what each part means.
public class AppDb : DbContext
{
public DbSet<Book> Books => Set<Book>();
public DbSet<Author> Authors => Set<Author>();
protected override void OnModelCreating(ModelBuilder b)
{
b.Entity<Book>().HasIndex(x => x.Year);
b.Entity<Book>().Property(x => x.Title).HasMaxLength(200).IsRequired();
}
}
var recent = await db.Books
.Where(b => b.Year >= 1990)
.Include(b => b.Author) // one join instead of N queries
.OrderByDescending(b => b.Year)
.Take(10)
.ToListAsync();
db.Books.Add(new Book { Title = "Dune", Year = 1965 });
await db.SaveChangesAsync();// No change tracking needed for reads — measurably faster and less memory.
var titles = await db.Books
.AsNoTracking()
.Where(b => b.Year > 2000)
.Select(b => new BookSummary(b.Id, b.Title, b.Author.Name))
.ToListAsync();Advanced usage
Where the library earns its place over a simpler alternative.
await using var tx = await db.Database.BeginTransactionAsync();
try
{
// ExecuteUpdate issues one UPDATE — it does not load the entities.
await db.Stock
.Where(s => s.Sku == sku)
.ExecuteUpdateAsync(s => s.SetProperty(x => x.Quantity, x => x.Quantity - qty));
db.Orders.Add(new Order { Sku = sku, Quantity = qty });
await db.SaveChangesAsync();
await tx.CommitAsync();
}
catch
{
await tx.RollbackAsync();
throw;
}Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- A second operation was started on this context instance
- Concurrent use of one DbContext. Await every call, and do not share a context across parallel tasks.
- The LINQ expression could not be translated
- The query uses a C# method EF cannot express in SQL. Move that part after an explicit AsEnumerable, accepting that it then runs in memory.
Best practices
- Use AsNoTracking for read-only queries; change tracking is pure overhead there.
- Always Include or project relations — the alternative is N+1 queries or a lazy-loading exception.
- Use ExecuteUpdate and ExecuteDelete for bulk changes rather than loading entities.
- Register DbContext as scoped; it is not thread-safe and must not be a singleton.
Background
Why it exists, and what it was reacting to.
EF Core is a ground-up rewrite of the older Entity Framework, built to be cross-platform, lighter and provider-agnostic. Its defining feature is that LINQ — the same syntax you use on in-memory collections — becomes SQL.
