Real-world examples of C# database examples with Entity Framework
1. A minimal DbContext and entity – the baseline example of C# database setup
Before getting fancy, you need a clean, minimal starting point. This first example of C# database examples with Entity Framework shows a simple domain model and DbContext that you can extend.
public class AppDbContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>()
.HasIndex(c => c.Email)
.IsUnique();
}
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
In modern .NET (6, 7, 8), you typically wire this up in Program.cs with dependency injection:
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
This is the baseline that all other examples include: a context, a set, and a model with a bit of configuration.
2. Async CRUD – the best examples you’ll actually copy into your API
Most real examples of C# database examples with Entity Framework today are async. If you’re still writing sync code in a web API, you’re leaving scalability on the table.
public class CustomersService
{
private readonly AppDbContext _db;
public CustomersService(AppDbContext db)
{
_db = db;
}
public async Task<Customer?> GetCustomerAsync(int id)
{
return await _db.Customers.FindAsync(id);
}
public async Task<Customer> CreateCustomerAsync(string name, string email)
{
var customer = new Customer
{
Name = name,
Email = email
};
_db.Customers.Add(customer);
await _db.SaveChangesAsync();
return customer;
}
public async Task<bool> UpdateCustomerEmailAsync(int id, string newEmail)
{
var customer = await _db.Customers.FindAsync(id);
if (customer == null) return false;
customer.Email = newEmail;
await _db.SaveChangesAsync();
return true;
}
public async Task<bool> DeleteCustomerAsync(int id)
{
var customer = await _db.Customers.FindAsync(id);
if (customer == null) return false;
_db.Customers.Remove(customer);
await _db.SaveChangesAsync();
return true;
}
}
This is one of the best examples to show junior developers: it’s straightforward, uses FindAsync, and demonstrates how EF tracks entities across operations.
3. Query patterns: filtering, projection, and pagination
If you’re looking for examples of C# database examples with Entity Framework that match real web app behavior, you need good query patterns: filtering, projection, and pagination. Here’s a realistic search scenario for a customer list endpoint.
public async Task<PagedResult<CustomerListItem>> SearchCustomersAsync(
string? search,
int page = 1,
int pageSize = 20)
{
var query = _db.Customers.AsQueryable();
if (!string.IsNullOrWhiteSpace(search))
{
query = query.Where(c =>
c.Name.Contains(search) ||
c.Email.Contains(search));
}
var totalCount = await query.CountAsync();
var items = await query
.OrderByDescending(c => c.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.Select(c => new CustomerListItem
{
Id = c.Id,
Name = c.Name,
Email = c.Email
})
.ToListAsync();
return new PagedResult<CustomerListItem>
{
TotalCount = totalCount,
Items = items
};
}
public class CustomerListItem
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
public class PagedResult<T>
{
public int TotalCount { get; set; }
public IReadOnlyList<T> Items { get; set; } = Array.Empty<T>();
}
Real examples like this matter because projection (Select) keeps queries efficient and avoids over-fetching columns you don’t need.
4. One-to-many relationships – a classic example of EF mapping
A lot of tutorials stop at single tables. The more realistic examples include relationships: orders and order items, blogs and posts, etc. Here’s a simple order scenario.
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public Customer Customer { get; set; } = null!;
public DateTime PlacedAt { get; set; } = DateTime.UtcNow;
public ICollection<OrderItem> Items { get; set; } = new List<OrderItem>();
}
public class OrderItem
{
public int Id { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; } = null!;
public string ProductName { get; set; } = string.Empty;
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
}
public class AppDbContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.HasMany(o => o.Items)
.WithOne(i => i.Order)
.HasForeignKey(i => i.OrderId);
}
}
And a realistic query with eager loading in EF Core:
public async Task<Order?> GetOrderWithItemsAsync(int orderId)
{
return await _db.Orders
.Include(o => o.Items)
.FirstOrDefaultAsync(o => o.Id == orderId);
}
This example of C# database design with Entity Framework scales to more complex graphs without changing the basic pattern.
5. Transactions and SaveChanges – real examples that avoid data corruption
In 2024, most production systems rely on multiple tables being updated together. Here’s an example of using explicit transactions with EF Core when you need more control than a single SaveChangesAsync call.
public async Task<bool> PlaceOrderAsync(int customerId, IEnumerable<(string product, int qty, decimal price)> items)
{
using var transaction = await _db.Database.BeginTransactionAsync();
try
{
var order = new Order
{
CustomerId = customerId,
PlacedAt = DateTime.UtcNow
};
_db.Orders.Add(order);
await _db.SaveChangesAsync();
foreach (var (product, qty, price) in items)
{
_db.OrderItems.Add(new OrderItem
{
OrderId = order.Id,
ProductName = product,
Quantity = qty,
UnitPrice = price
});
}
await _db.SaveChangesAsync();
await transaction.CommitAsync();
return true;
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
This is one of the best examples to show how EF Core plays nicely with explicit transactions while still giving you change tracking and validation.
6. Concurrency tokens – examples of handling conflicting updates
Real examples of C# database examples with Entity Framework need to show what happens when two users edit the same row. EF Core’s concurrency tokens ([Timestamp] or IsRowVersion) are the sane way to handle this.
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; } = Array.Empty<byte>();
}
Update logic with concurrency handling:
public async Task UpdateProductPriceAsync(int id, decimal newPrice, byte[] rowVersion)
{
var product = new Product
{
Id = id,
Price = newPrice,
RowVersion = rowVersion
};
_db.Attach(product);
_db.Entry(product).Property(p => p.Price).IsModified = true;
try
{
await _db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
// Reload database values and decide how to resolve the conflict
var entry = ex.Entries.Single();
var dbValues = await entry.GetDatabaseValuesAsync();
if (dbValues == null)
{
throw new InvalidOperationException("Product was deleted by another user.");
}
var currentDbProduct = (Product)dbValues.ToObject();
throw new InvalidOperationException(
$"Price was changed from {currentDbProduct.Price} before your update.");
}
}
If you’re building anything multi-user, this category of examples of EF behavior is worth understanding.
7. Migrations and schema evolution – examples of 2024-era workflows
The 2024–2025 trend is clear: code‑first migrations are the default for most greenfield .NET projects. You define your models, then let EF generate migration files that you review and apply.
Creating a migration from the CLI:
dotnet ef migrations add AddOrdersAndProducts
Applying migrations at startup (common in internal services and small teams):
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await db.Database.MigrateAsync();
}
If you want more background on why schema evolution matters, Microsoft’s official docs are still the best starting point:
- https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/
This is one of those less glamorous but very real examples of C# database examples with Entity Framework that separates hobby projects from maintainable systems.
8. Raw SQL and stored procedures – examples include escape hatches
Even with a strong ORM, sometimes you need to run raw SQL for performance or to call existing stored procedures. EF Core’s FromSqlInterpolated and ExecuteSqlInterpolated are your friends here.
Querying with raw SQL:
public async Task<List<Customer>> GetRecentCustomersRawAsync(int days)
{
return await _db.Customers
.FromSqlInterpolated($"SELECT * FROM Customers WHERE DATEDIFF(day, CreatedAt, GETUTCDATE()) <= {days}")
.ToListAsync();
}
Executing a stored procedure that returns no rows:
public async Task ArchiveOldOrdersAsync(int olderThanDays)
{
await _db.Database.ExecuteSqlInterpolatedAsync(
$"EXEC ArchiveOldOrders @olderThanDays = {olderThanDays}");
}
These real examples of C# database examples with Entity Framework show how you can mix high‑level EF with low‑level SQL when you have to.
9. Performance-minded patterns – examples of EF usage that scale
Performance in EF Core has improved a lot in recent versions (especially .NET 7 and 8), but you still need to use it thoughtfully. Here are two patterns you’ll see in the best examples of production EF code.
9.1 AsNoTracking for read‑only queries
public async Task<List<CustomerListItem>> GetCustomersReadOnlyAsync()
{
return await _db.Customers
.AsNoTracking()
.OrderBy(c => c.Name)
.Select(c => new CustomerListItem
{
Id = c.Id,
Name = c.Name,
Email = c.Email
})
.ToListAsync();
}
AsNoTracking skips change tracking and cuts overhead for read‑only scenarios such as public APIs or reporting screens.
9.2 Batching writes with AddRange and SaveChanges
public async Task ImportCustomersAsync(IEnumerable<Customer> customers)
{
_db.Customers.AddRange(customers);
await _db.SaveChangesAsync();
}
For bulk imports, this pattern is often enough. If you need heavy-duty bulk operations, real examples include pairing EF with libraries like EFCore.BulkExtensions, but the core idea is to minimize round trips.
10. Where to go deeper: docs and patterns
If you want more than just code snippets, the most reliable references for Entity Framework are still Microsoft’s official docs and university‑style database resources. While they’re not specific examples of C# database examples with Entity Framework, they provide the theory behind what EF is doing under the hood:
- Microsoft EF Core docs: https://learn.microsoft.com/en-us/ef/core/
- Stanford’s introductory database materials: https://cs.stanford.edu/academics/courses
- MIT OpenCourseWare database courses: https://ocw.mit.edu/courses/find-by-topic/#cat=engineering&subcat=computerscience&spec=databases
Pair those with the real examples in this article, and you’ll have both the practical and theoretical sides covered.
FAQ: examples of real-world Entity Framework usage
What are some real examples of C# database examples with Entity Framework in production apps?
Real‑world usage often looks like:
- A multi-tenant SaaS app using EF Core with SQL Server, code‑first migrations, and async queries for all API endpoints.
- An internal line‑of‑business app using EF Core with PostgreSQL, heavy use of
AsNoTrackingand projections for dashboards. - A hybrid legacy system where EF Core handles new tables while older stored procedures are called via
FromSqlInterpolated.
The examples of C# database examples with Entity Framework in this article are modeled on those kinds of systems rather than contrived console demos.
Can you show an example of using Entity Framework with dependency injection in ASP.NET Core?
Yes. In Program.cs:
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
builder.Services.AddScoped<CustomersService>();
Then inject CustomersService into your controllers or minimal API endpoints. This pattern appears in many of the best examples from Microsoft’s templates and is widely used in 2024‑era .NET projects.
Are these examples of C# database patterns valid for both EF Core and classic EF6?
Most concepts carry over, but syntax and APIs differ. The examples here target EF Core (the actively developed version). If you’re stuck on EF6, check Microsoft’s EF6 docs for older patterns and be aware some features—like improved batching and certain LINQ translations—are better in EF Core.
How do I test these examples without hitting a real database?
Common approaches include using an in‑memory provider like UseInMemoryDatabase for fast unit tests, or spinning up a real SQL Server or PostgreSQL instance in a container for integration tests. Many teams in 2024 use Docker‑based test databases so they’re exercising the same engine they use in production.
Related Topics
Practical examples of polymorphism in C++: function overloading
Best examples of dynamic memory allocation in C++: new and delete
Practical examples of C# variable declaration and initialization examples
Modern examples of C++ operator overloading: custom operators examples that actually matter
Best examples of C# conditional statements: examples & explanations
Real‑world examples of C# exception handling: 3 practical patterns every developer should know
Explore More C++ Code Snippets
Discover more examples and insights in this category.
View All C++ Code Snippets