Entity Framework
Code First
Database Views
EF Core
Programming Tutorial

how to use views in code first entity framework

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Using database views with a code-first Entity Framework model usually means mapping a read-only query shape, not treating the view like a normal mutable table. In EF Core, the standard approach is to map the view to a keyless entity with HasNoKey() and ToView() so you can query it through LINQ without expecting inserts, updates, or deletes.

What A View Means In EF

A database view is a stored query in the database that looks table-like from the application's perspective. It is useful for:

  • pre-joining multiple tables
  • exposing reporting shapes
  • simplifying repeated SQL logic
  • restricting what data the application can see

In EF, the most important distinction is that a view is often read-only. That affects how you configure the entity.

Create The View In The Database

A simple example SQL view:

sql
1CREATE VIEW View_OrderSummary AS
2SELECT
3    o.Id AS OrderId,
4    c.Name AS CustomerName,
5    o.TotalAmount
6FROM Orders o
7JOIN Customers c ON c.Id = o.CustomerId;

The application model will map to the result shape of that view.

Map A Keyless Entity In EF Core

Create a CLR type for the view result:

csharp
1public class OrderSummary
2{
3    public int OrderId { get; set; }
4    public string CustomerName { get; set; } = string.Empty;
5    public decimal TotalAmount { get; set; }
6}

Then configure it in the context:

csharp
1using Microsoft.EntityFrameworkCore;
2
3public class AppDbContext : DbContext
4{
5    public DbSet<OrderSummary> OrderSummaries => Set<OrderSummary>();
6
7    protected override void OnModelCreating(ModelBuilder modelBuilder)
8    {
9        modelBuilder.Entity<OrderSummary>(entity =>
10        {
11            entity.HasNoKey();
12            entity.ToView("View_OrderSummary");
13            entity.Property(x => x.OrderId).HasColumnName("OrderId");
14            entity.Property(x => x.CustomerName).HasColumnName("CustomerName");
15            entity.Property(x => x.TotalAmount).HasColumnName("TotalAmount");
16        });
17    }
18}

HasNoKey() is the key part. It tells EF Core this is not a normal tracked entity with a primary key.

Query The View Like A DbSet

Once mapped, querying is straightforward:

csharp
1using var db = new AppDbContext();
2
3var results = await db.OrderSummaries
4    .Where(x => x.TotalAmount > 100)
5    .OrderByDescending(x => x.TotalAmount)
6    .ToListAsync();

This is why views are useful. You get LINQ access to a pre-shaped database projection without writing the join every time.

The result behaves like a read model, not like a full aggregate root.

Migrations And Views

Code-first does not automatically mean EF will invent the view definition for you in the same way it creates tables from entity models. In practice, views are often created through migrations using raw SQL.

Example migration fragment:

csharp
1protected override void Up(MigrationBuilder migrationBuilder)
2{
3    migrationBuilder.Sql(@"
4        CREATE VIEW View_OrderSummary AS
5        SELECT
6            o.Id AS OrderId,
7            c.Name AS CustomerName,
8            o.TotalAmount
9        FROM Orders o
10        JOIN Customers c ON c.Id = o.CustomerId;
11    ");
12}
13
14protected override void Down(MigrationBuilder migrationBuilder)
15{
16    migrationBuilder.Sql("DROP VIEW View_OrderSummary");
17}

This keeps the database object under source control while still fitting a code-first workflow.

Read-Only By Design

A view mapping should usually be treated as query-only.

You can do this:

  • filter
  • sort
  • project
  • join in LINQ

You should not expect this to work cleanly:

  • 'Add'
  • 'Update'
  • 'Remove'
  • 'SaveChanges against the view entity'

That is not what keyless view-mapped entities are for.

If the application needs mutation, that usually belongs on the underlying table-backed entities instead.

Older EF Patterns Versus EF Core

Older Entity Framework approaches sometimes mapped views in less explicit ways, occasionally by pretending the view was a table-like entity. EF Core made the intent clearer with ToView() and keyless entity configuration.

That is one reason the EF Core pattern is preferable when available. The model states directly that the object represents a database view and does not behave like a normal keyed entity.

Common Pitfalls

The biggest mistake is forgetting HasNoKey() when the view has no real primary key semantics. EF Core then tries to treat the type like a normal entity, which leads to configuration errors.

Another mistake is expecting a view-mapped entity to support normal change tracking and writes. Views are usually read models.

People also forget that the view must exist in the database. Mapping the CLR type alone does not create the SQL view unless your migrations explicitly do that.

Finally, make sure the property names and column names line up. A view with aliased columns should be mapped intentionally.

Summary

  • In EF Core, map database views as keyless entities with HasNoKey() and ToView().
  • Treat the mapped type as a read-only query model, not a normal mutable entity.
  • Create or manage the view definition through SQL migrations or database scripts.
  • Query the view through LINQ just like a DbSet.
  • Use underlying table entities for inserts, updates, and deletes.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.