Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Entity Framework Core¶
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Entity Framework Core¶
Entity Framework (EF) Core is a lightweight and extensible version of the popular Entity Framework data access technology.
EF Core is an object-relational mapper (O/RM) that enables .NET developers to work with a database using .NET objects. It eliminates the need for most of the data-access code that developers usually need to write. EF Core supports many database engines, see Database Providers for details.
If you like to learn by writing code, we’d recommend one of our Getting Started guides to get you started with EF Core.
Get Entity Framework Core¶
Install the NuGet package for the database provider you want to use. See Database Providers for information.
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
The Model¶
With EF Core, data access is performed using a model. A model is made up of entity classes and a derived context that represents a session with the database, allowing you to query and save data. See Creating a Model to learn more.
You can generate a model from an existing database, hand code a model to match your database, or use EF Migrations to create a database from your model (and evolve it as your model changes over time).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace Intro
{
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
|
Querying¶
Instances of your entity classes are retrieved from the database using Language Integrated Query (LINQ). See Querying Data to learn more.
1 2 3 4 5 6 7 | using (var db = new BloggingContext())
{
var blogs = db.Blogs
.Where(b => b.Rating > 3)
.OrderBy(b => b.Url)
.ToList();
}
|
Saving Data¶
Data is created, deleted, and modified in the database using instances of your entity classes. See Saving Data to learn more.
1 2 3 4 5 6 | using (var db = new BloggingContext())
{
var blog = new Blog { Url = "http://sample.com" };
db.Blogs.Add(blog);
db.SaveChanges();
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Getting Started¶
The following articles provide documentation for using EF on different platforms.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Getting Started on Full .NET (Console, WinForms, WPF, etc.)¶
These 101 tutorials require no previous knowledge of Entity Framework (EF) or Visual Studio. They will take you step-by-step through creating a simple application that queries and saves data from a database.
Entity Framework can create a model based on an existing database, or create a database for you based on your model. The following tutorials will demonstrate both of these approaches using a Console Application. You can use the techniques learned in these tutorials in any application that targets Full .NET, including WPF and WinForms.
Available Tutorials¶
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Console Application to New Database¶
In this walkthrough, you will build a console application that performs basic data access against a Microsoft SQL Server database using Entity Framework. You will use migrations to create the database from your model.
In this article:
Tip
You can view this article’s sample on GitHub.
Prerequisites¶
The following prerequisites are needed to complete this walkthrough:
Create a new project¶
- Open Visual Studio 2015
- From the left menu select
- Select the Console Application project template
- Ensure you are targeting .NET Framework 4.5.1 or later
- Give the project a name and click OK
Install Entity Framework¶
To use EF Core, install the package for the database provider(s) you want to target. This walkthrough uses SQL Server. For a list of available providers see Database Providers.
- Run
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Later in this walkthrough we will also be using some Entity Framework commands to maintain the database. So we will install the commands package as well.
- Run
Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
Create your model¶
Now it’s time to define a context and entity classes that make up your model.
- Enter Model.cs as the name and click OK
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace EFGetStarted.ConsoleApp
{
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFGetStarted.ConsoleApp.NewDb;Trusted_Connection=True;");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
|
Tip
In a real application you would put each class in a separate file and put the connection string in the App.Config
file and read it out using ConfigurationManager
. For the sake of simplicity, we are putting everything in a single code file for this tutorial.
Create your database¶
Now that you have a model, you can use migrations to create a database for you.
- Run
Add-Migration MyFirstMigration
to scaffold a migration to create the initial set of tables for your model. - Run
Update-Database
to apply the new migration to the database. Because your database doesn’t exist yet, it will be created for you before the migration is applied.
Tip
If you make future changes to your model, you can use the Add-Migration
command to scaffold a new migration to make the corresponding schema changes to the database. Once you have checked the scaffolded code (and made any required changes), you can use the Update-Database
command to apply the changes to the database.
EF uses a __EFMigrationsHistory
table in the database to keep track of which migrations have already been applied to the database.
Use your model¶
You can now use your model to perform data access.
- Open Program.cs
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System;
namespace EFGetStarted.ConsoleApp
{
class Program
{
static void Main(string[] args)
{
using (var db = new BloggingContext())
{
db.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
var count = db.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
Console.WriteLine();
Console.WriteLine("All blogs in database:");
foreach (var blog in db.Blogs)
{
Console.WriteLine(" - {0}", blog.Url);
}
}
}
}
}
|
You will see that one blog is saved to the database and then the details of all blogs are printed to the console.

Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Console Application to Existing Database (Database First)¶
In this walkthrough, you will build a console application that performs basic data access against a Microsoft SQL Server database using Entity Framework. You will use reverse engineering to create an Entity Framework model based on an existing database.
In this article:
Tip
You can view this article’s sample on GitHub.
Prerequisites¶
The following prerequisites are needed to complete this walkthrough:
- Visual Studio 2015 Update 3
- Latest version of NuGet Package Manager
- Latest version of Windows PowerShell
- Blogging database
This tutorial uses a Blogging database on your LocalDb instance as the existing database.
Note
If you have already created the Blogging database as part of another tutorial, you can skip these steps.
- Open Visual Studio
- Select Microsoft SQL Server and click Continue
- Enter (localdb)\mssqllocaldb as the Server Name
- Enter master as the Database Name and click OK
- The master database is now displayed under Data Connections in Server Explorer
- Right-click on the database in Server Explorer and select New Query
- Copy the script, listed below, into the query editor
- Right-click on the query editor and select Execute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | CREATE DATABASE [Blogging]
GO
USE [Blogging]
GO
CREATE TABLE [Blog] (
[BlogId] int NOT NULL IDENTITY,
[Url] nvarchar(max) NOT NULL,
CONSTRAINT [PK_Blog] PRIMARY KEY ([BlogId])
);
GO
CREATE TABLE [Post] (
[PostId] int NOT NULL IDENTITY,
[BlogId] int NOT NULL,
[Content] nvarchar(max),
[Title] nvarchar(max),
CONSTRAINT [PK_Post] PRIMARY KEY ([PostId]),
CONSTRAINT [FK_Post_Blog_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blog] ([BlogId]) ON DELETE CASCADE
);
GO
INSERT INTO [Blog] (Url) VALUES
('http://blogs.msdn.com/dotnet'),
('http://blogs.msdn.com/webdev'),
('http://blogs.msdn.com/visualstudio')
GO
|
Create a new project¶
- Open Visual Studio 2015
- From the left menu select
- Select the Console Application project template
- Ensure you are targeting .NET Framework 4.5.1 or later
- Give the project a name and click OK
Install Entity Framework¶
To use EF Core, install the package for the database provider(s) you want to target. This walkthrough uses SQL Server. For a list of available providers see Database Providers.
- Run
Install-Package Microsoft.EntityFrameworkCore.SqlServer
To enable reverse engineering from an existing database we need to install a couple of other packages too.
- Run
Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
- Run
Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design
Reverse engineer your model¶
Now it’s time to create the EF model based on your existing database.
- Run the following command to create a model from the existing database
Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer
The reverse engineer process created entity classes and a derived context based on the schema of the existing database. The entity classes are simple C# objects that represent the data you will be querying and saving.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System;
using System.Collections.Generic;
namespace EFGetStarted.ConsoleApp.ExistingDb
{
public partial class Blog
{
public Blog()
{
Post = new HashSet<Post>();
}
public int BlogId { get; set; }
public string Url { get; set; }
public virtual ICollection<Post> Post { get; set; }
}
}
|
The context represents a session with the database and allows you to query and save instances of the entity classes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace EFGetStarted.ConsoleApp.ExistingDb
{
public partial class BloggingContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>(entity =>
{
entity.Property(e => e.Url).IsRequired();
});
modelBuilder.Entity<Post>(entity =>
{
entity.HasOne(d => d.Blog)
.WithMany(p => p.Post)
.HasForeignKey(d => d.BlogId);
});
}
public virtual DbSet<Blog> Blog { get; set; }
public virtual DbSet<Post> Post { get; set; }
}
}
|
Use your model¶
You can now use your model to perform data access.
- Open Program.cs
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System;
namespace EFGetStarted.ConsoleApp.ExistingDb
{
class Program
{
static void Main(string[] args)
{
using (var db = new BloggingContext())
{
db.Blog.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
var count = db.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
Console.WriteLine();
Console.WriteLine("All blogs in database:");
foreach (var blog in db.Blog)
{
Console.WriteLine(" - {0}", blog.Url);
}
}
}
}
}
|
You will see that one blog is saved to the database and then the details of all blogs are printed to the console.

Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Getting Started on .NET Core (Windows, OSX, Linux, etc.)¶
These 101 tutorials require no previous knowledge of Entity Framework (EF) or Visual Studio. They will take you step-by-step through creating a simple application that queries and saves data from a database.
EF can be used on all platforms (Windows, OSX, Linux, etc.) that support .NET Core.
Available Tutorials¶
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
.NET Core Application to New SQLite Database¶
In this walkthrough, you will build a .NET Core console application that performs basic data access using Entity Framework. You will use migrations to create the database from your model.
In this article:
Tip
You can view this article’s sample on GitHub.
Prerequisites¶
- Minimum system requirements
- An operating system that supports .NET Core
- .NET Core SDK Preview 2
- A text editor
Caution
Known Issues
- Migrations on SQLite do not support more complex schema changes due to limitations in SQLite itself. See SQLite Limitations
The .NET Core SDK provides the command-line tool dotnet
which will be used to
build and run our sample application.
See the .NET Core website for instructions on installing the SDK on your operating system.
Create a new project¶
Create a new folder
ConsoleApp/
for your project. All files for the project should be in this folder.mkdir ConsoleApp cd ConsoleApp/
Execute the following .NET Core CLI commands to create a new console application, download dependencies, and run the .NET Core app.
dotnet new dotnet restore dotnet run
Install Entity Framework¶
To add EF to your project, modify
project.json
so it matches the following sample.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 { "version": "1.0.0-*", "buildOptions": { "debugType": "portable", "emitEntryPoint": true }, "dependencies": { "Microsoft.EntityFrameworkCore.Sqlite": "1.0.0", "Microsoft.EntityFrameworkCore.Design": { "version": "1.0.0-preview2-final", "type": "build" } }, "frameworks": { "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "type": "platform", "version": "1.0.0" } }, "imports": "dnxcore50" } }, "tools": { "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final" } }Run
dotnet restore
again to install the new packages.dotnet restoreVerify that Entity Framework is installed by running
dotnet ef --help
.dotnet ef --help
Create your model¶
With this new project, you are ready to begin using Entity Framework. The next steps will add code to configure and access a SQLite database file.
- Create a new file called
Model.cs
All classes in the following steps will be added to this file.
1 2 3 4 5 6 using System.Collections.Generic; using System.IO; using Microsoft.EntityFrameworkCore; namespace ConsoleApp.SQLite {
- Add a new class to represent the SQLite database.
We will call this
BloggingContext
. The call toUseSqlite()
configures EF to point to a *.db file.
1 2 3 4 5 6 7 8 9 10 public class BloggingContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite("Filename=./blog.db"); } }
- Add classes to represent tables.
Note that we will be using foreign keys to associate many posts to one blog.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Blog { public int BlogId { get; set; } public string Url { get; set; } public string Name { get; set; } public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public int BlogId { get; set; } public Blog Blog { get; set; } }To make sure the files are correct, you can compile the project on the command line by running
dotnet build
dotnet build
Create your database¶
We can now use Entity Framework command line tools to create and manage the schema of the database.
- Create the first migration.
Execute the command below to generate your first migration. This will find our context and models, and generate a migration for us in a folder named
Migrations/
dotnet ef migrations add MyFirstMigration
- Apply the migrations.
You can now begin using the existing migration to create the database file and creates the tables.
dotnet ef database updateThis should create a new file
blog.db
in the output path. This SQLite file should now contain two empty tables.
Note
When using relative paths with SQLite, the path will be relative to the application’s
main assembly. In this sample, the main binary is bin/Debug/netcoreapp1.0/ConsoleApp.dll
,
so the SQLite database will be in bin/Debug/netcoreapp1.0/blog.db
Use your model¶
Now that we have configured our model and created the database schema, we can use BloggingContext to create, update, and delete objects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System;
namespace ConsoleApp.SQLite
{
public class Program
{
public static void Main()
{
using (var db = new BloggingContext())
{
db.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
var count = db.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
Console.WriteLine();
Console.WriteLine("All blogs in database:");
foreach (var blog in db.Blogs)
{
Console.WriteLine(" - {0}", blog.Url);
}
}
}
}
}
|
Start your app¶
Run the application from the command line.
dotnet run
After adding the new post, you can verify the data has been added by inspecting the SQLite database file, bin/Debug/netcoreapp1.0/blog.db
.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Getting Started on ASP.NET Core¶
These 101 tutorials require no previous knowledge of Entity Framework (EF) or Visual Studio. They will take you step-by-step through creating a simple application that queries and saves data from a database.
Entity Framework can create a model based on an existing database, or create a database for you based on your model. The following tutorials will demonstrate both of these approaches using an ASP.NET Core application.
Available Tutorials¶
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
ASP.NET Core Application to New Database¶
In this walkthrough, you will build an ASP.NET Core MVC application that performs basic data access using Entity Framework. You will use migrations to create the database from your model.
In this article:
Tip
You can view this article’s sample on GitHub.
Create a new project¶
- Open Visual Studio 2015
- From the left menu select
- Select the ASP.NET Core Web Application (.NET Core) project template
- Enter EFGetStarted.AspNetCore.NewDb as the name and click OK
- Wait for the New ASP.NET Core Web Application dialog to appear
- Select the Web Application template and ensure that Authentication is set to No Authentication
- Click OK
Caution
If you use Individual User Accounts instead of None for Authentication then an Entity Framework model will be added to your project in Models\IdentityModel.cs. Using the techniques you will learn in this walkthrough, you can choose to add a second model, or extend this existing model to contain your entity classes.
Install Entity Framework¶
To use EF Core, install the package for the database provider(s) you want to target. This walkthrough uses SQL Server. For a list of available providers see Database Providers.
- Run
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Note
In ASP.NET Core projects the Install-Package
command will complete quickly and the package installation will occur in the background. You will see (Restoring...) appear next to References in Solution Explorer while the install occurs.
Later in this walkthrough we will also be using some Entity Framework commands to maintain the database. So we will install the commands package as well.
- Run
Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
- Open project.json
- Locate the
tools
section and add theef
command as shown below
1 2 3 4 5 | "tools": {
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
|
Create your model¶
Now it’s time to define a context and entity classes that make up your model.
- Right-click on the project in Solution Explorer and select
- Enter Models as the name of the folder
- Right-click on the Models folder and select
- From the left menu select
- Select the Class item template
- Enter Model.cs as the name and click OK
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace EFGetStarted.AspNetCore.NewDb.Models
{
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
|
Note
In a real application you would typically put each class from your model in a separate file. For the sake of simplicity, we are putting all the classes in one file for this tutorial.
Register your context with dependency injection¶
The concept of dependency injection is central to ASP.NET Core. Services (such as BloggingContext
) are registered with dependency injection during application startup. Components that require these services (such as your MVC controllers) are then provided these services via constructor parameters or properties. For more information on dependency injection see the Dependency Injection article on the ASP.NET site.
In order for our MVC controllers to make use of BloggingContext
we are going to register it as a service.
- Open Startup.cs
- Add the following
using
statements at the start of the file
1 2 | using EFGetStarted.AspNetCore.NewDb.Models;
using Microsoft.EntityFrameworkCore;
|
Now we can use the AddDbContext
method to register it as a service.
- Locate the
ConfigureServices
method- Add the lines that are highlighted in the following code
1 2 3 4 | public void ConfigureServices(IServiceCollection services)
{
var connection = @"Server=(localdb)\mssqllocaldb;Database=EFGetStarted.AspNetCore.NewDb;Trusted_Connection=True;";
services.AddDbContext<BloggingContext>(options => options.UseSqlServer(connection));
|
Create your database¶
Now that you have a model, you can use migrations to create a database for you.
- Run
Add-Migration MyFirstMigration
to scaffold a migration to create the initial set of tables for your model. If you receive an error stating the term ‘add-migration’ is not recognized as the name of a cmdlet, then close and reopen Visual Studio - Run
Update-Database
to apply the new migration to the database. Because your database doesn’t exist yet, it will be created for you before the migration is applied.
Tip
If you make future changes to your model, you can use the Add-Migration
command to scaffold a new migration to make the corresponding schema changes to the database. Once you have checked the scaffolded code (and made any required changes), you can use the Update-Database
command to apply the changes to the database.
EF uses a __EFMigrationsHistory
table in the database to keep track of which migrations have already been applied to the database.
Create a controller¶
Next, we’ll add an MVC controller that will use EF to query and save data.
- Right-click on the Controllers folder in Solution Explorer and select
- From the left menu select
- Select the Class item template
- Enter BlogsController.cs as the name and click OK
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | using EFGetStarted.AspNetCore.NewDb.Models;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
namespace EFGetStarted.AspNetCore.NewDb.Controllers
{
public class BlogsController : Controller
{
private BloggingContext _context;
public BlogsController(BloggingContext context)
{
_context = context;
}
public IActionResult Index()
{
return View(_context.Blogs.ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Blog blog)
{
if (ModelState.IsValid)
{
_context.Blogs.Add(blog);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(blog);
}
}
}
|
You’ll notice that the controller takes a BloggingContext
as a constructor parameter. ASP.NET dependency injection will take care of passing an instance of BloggingContext
into your controller.
The controller contains an Index
action, which displays all blogs in the database, and a Create
action, which inserts a new blogs into the database.
Create views¶
Now that we have a controller it’s time to add the views that will make up the user interface.
We’ll start with the view for our Index
action, that displays all blogs.
- Right-click on the Views folder in Solution Explorer and select
- Enter Blogs as the name of the folder
- Right-click on the Blogs folder and select
- From the left menu select
- Select the MVC View Page item template
- Enter Index.cshtml as the name and click Add
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | @model IEnumerable<EFGetStarted.AspNetCore.NewDb.Models.Blog>
@{
ViewBag.Title = "Blogs";
}
<h2>Blogs</h2>
<p>
<a asp-controller="Blogs" asp-action="Create">Create New</a>
</p>
<table class="table">
<tr>
<th>Id</th>
<th>Url</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.BlogId)
</td>
<td>
@Html.DisplayFor(modelItem => item.Url)
</td>
</tr>
}
</table>
|
We’ll also add a view for the Create
action, which allows the user to enter details for a new blog.
- Right-click on the Blogs folder and select
- From the left menu select
- Select the MVC View Page item template
- Enter Create.cshtml as the name and click Add
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @model EFGetStarted.AspNetCore.NewDb.Models.Blog
@{
ViewBag.Title = "New Blog";
}
<h2>@ViewData["Title"]</h2>
<form asp-controller="Blogs" asp-action="Create" method="post" class="form-horizontal" role="form">
<div class="form-horizontal">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Url" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Url" class="form-control" />
<span asp-validation-for="Url" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>
|
Run the application¶
You can now run the application to see it in action.
- The application will build and open in a web browser
- Navigate to /Blogs
- Click Create New
- Enter a Url for the new blog and click Create


Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
ASP.NET Core Application to Existing Database (Database First)¶
In this walkthrough, you will build an ASP.NET Core MVC application that performs basic data access using Entity Framework. You will use reverse engineering to create an Entity Framework model based on an existing database.
In this article:
Tip
You can view this article’s sample on GitHub.
Prerequisites¶
The following prerequisites are needed to complete this walkthrough:
This tutorial uses a Blogging database on your LocalDb instance as the existing database.
Note
If you have already created the Blogging database as part of another tutorial, you can skip these steps.
- Open Visual Studio
- Select Microsoft SQL Server and click Continue
- Enter (localdb)\mssqllocaldb as the Server Name
- Enter master as the Database Name and click OK
- The master database is now displayed under Data Connections in Server Explorer
- Right-click on the database in Server Explorer and select New Query
- Copy the script, listed below, into the query editor
- Right-click on the query editor and select Execute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | CREATE DATABASE [Blogging]
GO
USE [Blogging]
GO
CREATE TABLE [Blog] (
[BlogId] int NOT NULL IDENTITY,
[Url] nvarchar(max) NOT NULL,
CONSTRAINT [PK_Blog] PRIMARY KEY ([BlogId])
);
GO
CREATE TABLE [Post] (
[PostId] int NOT NULL IDENTITY,
[BlogId] int NOT NULL,
[Content] nvarchar(max),
[Title] nvarchar(max),
CONSTRAINT [PK_Post] PRIMARY KEY ([PostId]),
CONSTRAINT [FK_Post_Blog_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blog] ([BlogId]) ON DELETE CASCADE
);
GO
INSERT INTO [Blog] (Url) VALUES
('http://blogs.msdn.com/dotnet'),
('http://blogs.msdn.com/webdev'),
('http://blogs.msdn.com/visualstudio')
GO
|
Create a new project¶
- Open Visual Studio 2015
- From the left menu select
- Select the ASP.NET Core Web Application (.NET Core) project template
- Enter EFGetStarted.AspNetCore.ExistingDb as the name and click OK
- Wait for the New ASP.NET Core Web Application dialog to appear
- Select the Web Application template and ensure that Authentication is set to No Authentication
- Click OK
Install Entity Framework¶
To use EF Core, install the package for the database provider(s) you want to target. This walkthrough uses SQL Server. For a list of available providers see Database Providers.
- Run
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Note
In ASP.NET Core projects the Install-Package
will complete quickly and the package installation will occur in the background. You will see (Restoring...) appear next to References in Solution Explorer while the install occurs.
To enable reverse engineering from an existing database we need to install a couple of other packages too.
- Run
Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
- Run
Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design
- Open project.json
- Locate the
tools
section and add the highlighted lines as shown below
1 2 3 4 5 "tools": { "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final", "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final" },
Reverse engineer your model¶
Now it’s time to create the EF model based on your existing database.
- Run the following command to create a model from the existing database. If you receive an error stating the term ‘Scaffold-DbContext’ is not recognized as the name of a cmdlet, then close and reopen Visual Studio.
Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
The reverse engineer process created entity classes and a derived context based on the schema of the existing database. The entity classes are simple C# objects that represent the data you will be querying and saving.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System;
using System.Collections.Generic;
namespace EFGetStarted.AspNetCore.ExistingDb.Models
{
public partial class Blog
{
public Blog()
{
Post = new HashSet<Post>();
}
public int BlogId { get; set; }
public string Url { get; set; }
public virtual ICollection<Post> Post { get; set; }
}
}
|
The context represents a session with the database and allows you to query and save instances of the entity classes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace EFGetStarted.AspNetCore.ExistingDb.Models
{
public partial class BloggingContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>(entity =>
{
entity.Property(e => e.Url).IsRequired();
});
modelBuilder.Entity<Post>(entity =>
{
entity.HasOne(d => d.Blog)
.WithMany(p => p.Post)
.HasForeignKey(d => d.BlogId);
});
}
public virtual DbSet<Blog> Blog { get; set; }
public virtual DbSet<Post> Post { get; set; }
}
}
|
Register your context with dependency injection¶
The concept of dependency injection is central to ASP.NET Core. Services (such as BloggingContext
) are registered with dependency injection during application startup. Components that require these services (such as your MVC controllers) are then provided these services via constructor parameters or properties. For more information on dependency injection see the Dependency Injection article on the ASP.NET site.
In ASP.NET Core, configuration is generally performed in Startup.cs. To conform to this pattern, we will move configuration of the database provider to Startup.cs.
- Open Models\BloggingContext.cs
- Delete the lines of code highlighted below
1 2 3 4 5 6 7 | public partial class BloggingContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;");
}
|
- Add the lines of code highlighted below
1 2 3 4 5 | public partial class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
|
In order for our MVC controllers to make use of BloggingContext
we are going to register it as a service.
- Open Startup.cs
- Add the following
using
statements at the start of the file
1 2 | using EFGetStarted.AspNetCore.ExistingDb.Models;
using Microsoft.EntityFrameworkCore;
|
Now we can use the AddDbContext
method to register it as a service.
- Locate the
ConfigureServices
method- Add the lines that are highlighted in the following code
1 2 3 4 | public void ConfigureServices(IServiceCollection services)
{
var connection = @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;";
services.AddDbContext<BloggingContext>(options => options.UseSqlServer(connection));
|
Create a controller¶
Next, we’ll add an MVC controller that will use EF to query and save data.
- Right-click on the Controllers folder in Solution Explorer and select
- From the left menu select
- Select the Class item template
- Enter BlogsController.cs as the name and click OK
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | using EFGetStarted.AspNetCore.ExistingDb.Models;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
namespace EFGetStarted.AspNetCore.ExistingDb.Controllers
{
public class BlogsController : Controller
{
private BloggingContext _context;
public BlogsController(BloggingContext context)
{
_context = context;
}
public IActionResult Index()
{
return View(_context.Blog.ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Blog blog)
{
if (ModelState.IsValid)
{
_context.Blog.Add(blog);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(blog);
}
}
}
|
You’ll notice that the controller takes a BloggingContext
as a constructor parameter. ASP.NET dependency injection will take care of passing an instance of BloggingContext
into your controller.
The controller contains an Index
action, which displays all blogs in the database, and a Create
action, which inserts a new blogs into the database.
Create views¶
Now that we have a controller it’s time to add the views that will make up the user interface.
We’ll start with the view for our Index
action, that displays all blogs.
- Right-click on the Views folder in Solution Explorer and select
- Enter Blogs as the name of the folder
- Right-click on the Blogs folder and select
- From the left menu select
- Select the MVC View Page item template
- Enter Index.cshtml as the name and click Add
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | @model IEnumerable<EFGetStarted.AspNetCore.ExistingDb.Models.Blog>
@{
ViewBag.Title = "Blogs";
}
<h2>Blogs</h2>
<p>
<a asp-controller="Blogs" asp-action="Create">Create New</a>
</p>
<table class="table">
<tr>
<th>Id</th>
<th>Url</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.BlogId)
</td>
<td>
@Html.DisplayFor(modelItem => item.Url)
</td>
</tr>
}
</table>
|
We’ll also add a view for the Create
action, which allows the user to enter details for a new blog.
- Right-click on the Blogs folder and select
- From the left menu select
- Select the MVC View Page item template
- Enter Create.cshtml as the name and click Add
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @model EFGetStarted.AspNetCore.ExistingDb.Models.Blog
@{
ViewBag.Title = "New Blog";
}
<h2>@ViewData["Title"]</h2>
<form asp-controller="Blogs" asp-action="Create" method="post" class="form-horizontal" role="form">
<div class="form-horizontal">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Url" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Url" class="form-control" />
<span asp-validation-for="Url" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>
|
Run the application¶
You can now run the application to see it in action.
- The application will build and open in a web browser
- Navigate to /Blogs
- Click Create New
- Enter a Url for the new blog and click Create


Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Getting Started on Universal Windows Platform (UWP)¶
These 101 tutorials require no previous knowledge of Entity Framework (EF) or Visual Studio. They will take you step-by-step through creating a simple application that queries and saves data from a database.
Entity Framework can be used to access a local SQLite database in Universal Windows Platform applications.
Available Tutorials¶
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Local SQLite on UWP¶
In this walkthrough, you will build a Universal Windows Platform (UWP) application that performs basic data access against a local SQLite database using Entity Framework.
Caution
Avoid using anonymous types in LINQ queries on UWP. Deploying a UWP application to the app store requires your application to be compiled with .NET Native. Queries with anonymous types have poor performance on .NET Native or may crash the application.
In this article:
Tip
You can view this article’s sample on GitHub.
Prerequisites¶
- The following items are required to complete this walkthrough:
- Windows 10
- Visual Studio 2015 Update 3
- The latest version of Windows 10 Developer Tools
Create a new project¶
- Open Visual Studio 2015
- From the left menu select
- Select the Blank App (Universal Windows) project template
- Give the project a name and click OK
Upgrade Microsoft.NETCore.UniversalWindowsPlatform¶
Depending on your version of Visual Studio, the template may have generated your project with an old version of .NET Core for UWP.
EF Core requires Microsoft.NETCore.UniversalWindowsPlatform
version 5.2.2 or greater.
- Run
Update-Package Microsoft.NETCore.UniversalWindowsPlatform
Install Entity Framework¶
To use EF Core, install the package for the database provider(s) you want to target. This walkthrough uses SQLite. For a list of available providers see Database Providers.
- Run
Install-Package Microsoft.EntityFrameworkCore.Sqlite
Later in this walkthrough we will also be using some Entity Framework commands to maintain the database. So we will install the commands package as well.
- Run
Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
Create your model¶
Now it’s time to define a context and entity classes that make up your model.
- Enter Model.cs as the name and click OK
- Replace the contents of the file with the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace EFGetStarted.UWP
{
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=Blogging.db");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
|
Tip
In a real application you would put each class in a separate file and put the connection string in the App.Config
file and read it out using ConfigurationManager
. For the sake of simplicity, we are putting everything in a single code file for this tutorial.
Create your database¶
Warning
Known Issue in Preview 2
Using EF Tools on UWP projects does not work without manually adding binding redirects.
- From the left menu select
- Give the file the name “App.config”
- Add the following contents to the file
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="4.0.0.0" newVersion="4.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Overlapped" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="4.0.0.0" newVersion="4.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="4.1.0.0" newVersion="4.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
See Issue #5471 for more details.
Now that you have a model, you can use migrations to create a database for you.
- Run
Add-Migration MyFirstMigration
to scaffold a migration to create the initial set of tables for your model.
Since we want the database to be created on the device that the app runs on, we will add some code to apply any pending migrations to the local database on application startup. The first time that the app runs, this will take care of creating the local database for us.
- Right-click on App.xaml in Solution Explorer and select View Code
- Add the highlighted using to the start of the file
1 2 3 4 5 6 | using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
|
- Add the highlighted code to apply any pending migrations
1 2 3 4 5 6 7 8 9 10 | public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
using (var db = new BloggingContext())
{
db.Database.Migrate();
}
}
|
Tip
If you make future changes to your model, you can use the Add-Migration
command to scaffold a new migration to apply the corresponding changes to the database. Any pending migrations will be applied to the local database on each device when the application starts.
EF uses a __EFMigrationsHistory
table in the database to keep track of which migrations have already been applied to the database.
Use your model¶
You can now use your model to perform data access.
- Open MainPage.xaml
- Add the page load handler and UI content highlighted below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <Page
x:Class="EFGetStarted.UWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:EFGetStarted.UWP"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Loaded="Page_Loaded">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<TextBox Name="NewBlogUrl"></TextBox>
<Button Click="Add_Click">Add</Button>
<ListView Name="Blogs">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Url}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
</Page>
|
Now we’ll add code to wire up the UI with the database
- Right-click MainPage.xaml in Solution Explorer and select View Code
- Add the highlighted code from the following listing
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
using (var db = new BloggingContext())
{
Blogs.ItemsSource = db.Blogs.ToList();
}
}
private void Add_Click(object sender, RoutedEventArgs e)
{
using (var db = new BloggingContext())
{
var blog = new Blog { Url = NewBlogUrl.Text };
db.Blogs.Add(blog);
db.SaveChanges();
Blogs.ItemsSource = db.Blogs.ToList();
}
}
}
|
You can now run the application to see it in action.
- The application will build and launch
- Enter a URL and click the Add button


Next steps¶
Tada! You now have a simple UWP app running Entity Framework.
Check out the numerous articles in this documentation to learn more about Entity Framework’s features.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Creating a Model¶
Entity Framework uses a set of conventions to build a model based on the shape of your entity classes. You can specify additional configuration to supplement and/or override what was discovered by convention.
This article covers configuration that can be applied to a model targeting any data store and that which can be applied when targeting any relational database. Providers may also enable configuration that is specific to a particular data store. For documentation on provider specific configuration see the Database Providers section.
In this section you can find information about conventions and configuration for the following:
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Including & Excluding Types¶
Including a type in the model means that EF has metadata about that type and will attempt to read and write instances from/to the database.
In this article:
Conventions¶
By convention, types that are exposed in DbSet
properties on your context are included in your model. In addition, types that are mentioned in the OnModelCreating
method are also included. Finally, any types that are found by recursively exploring the navigation properties of discovered types are also included in the model.
- For example, in the following code listing all three types are discovered:
Blog
because it is exposed in aDbSet
property on the contextPost
because it is discovered via theBlog.Posts
navigation propertyAuditEntry
because it is mentioned inOnModelCreating
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AuditEntry>();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog { get; set; }
}
public class AuditEntry
{
public int AuditEntryId { get; set; }
public string Username { get; set; }
public string Action { get; set; }
}
|
Data Annotations¶
You can use Data Annotations to exclude a type from the model.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public BlogMetadata Metadata { get; set; }
}
[NotMapped]
public class BlogMetadata
{
public DateTime LoadedFromDatabase { get; set; }
}
|
Fluent API¶
You can use the Fluent API to exclude a type from the model.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<BlogMetadata>();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public BlogMetadata Metadata { get; set; }
}
public class BlogMetadata
{
public DateTime LoadedFromDatabase { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Including & Excluding Properties¶
Including a property in the model means that EF has metadata about that property and will attempt to read and write values from/to the database.
In this article:
Conventions¶
By convention, public properties with a getter and a setter will be included in the model.
Data Annotations¶
You can use Data Annotations to exclude a property from the model.
1 2 3 4 5 6 7 8 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[NotMapped]
public DateTime LoadedFromDatabase { get; set; }
}
|
Fluent API¶
You can use the Fluent API to exclude a property from the model.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Ignore(b => b.LoadedFromDatabase);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public DateTime LoadedFromDatabase { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Keys (primary)¶
A key serves as the primary unique identifier for each entity instance. When using a relational database this maps to the concept of a primary key. You can also configure a unique identifier that is not the primary key (see Alternate Keys for more information).
In this article:
Conventions¶
By convention, a property named Id
or <type name>Id
will be configured as the key of an entity.
1 2 3 4 5 6 7 | class Car
{
public string Id { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
|
1 2 3 4 5 6 7 | class Car
{
public string CarId { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
|
Data Annotations¶
You can use Data Annotations to configure a single property to be the key of an entity.
1 2 3 4 5 6 7 8 | class Car
{
[Key]
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
|
Fluent API¶
You can use the Fluent API to configure a single property to be the key of an entity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasKey(c => c.LicensePlate);
}
}
class Car
{
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
|
You can also use the Fluent API to configure multiple properties to be the key of an entity (known as a composite key). Composite keys can only be configured using the Fluent API - conventions will never setup a composite key and you can not use Data Annotations to configure one.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasKey(c => new { c.State, c.LicensePlate });
}
}
class Car
{
public string State { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Generated Properties¶
In this article:
Value Generation Patterns¶
There are three value generation patterns that can be used for properties.
No value generation¶
No value generation means that you will always supply a valid value to be saved to the database. This valid value must be assigned to new entities before they are added to the context.
Value generated on add¶
Value generated on add means that a value is generated for new entities.
Caution
How the value is generated for added entities will depend on the database provider being used. Database providers may automatically setup value generation for some property types, but others may require you to manually setup how the value is generated.
For example, when using SQL Server, values will be automatically generated for GUID properties (using the SQL Server sequential GUID algorithm). However, if you specify that a DateTime property is generated on add, then you must setup a way for the values to be generated (such as setting default value SQL of GETDATE(), see Default Values).
If you add an entity to the context that has a value assigned to the primary key property, then EF will attempt to insert that value rather than generating a new one. A property is considered to have a value assigned if it is not assigned the CLR default value (null
for string
, 0
for int
, Guid.Empty
for Guid
, etc.).
Depending on the database provider being used, values may be generated client side by EF or in the database. If the value is generated by the database, then EF may assign a temporary value when you add the entity to the context. This temporary value will then be replaced by the database generated value during SaveChanges
.
Value generated on add or update¶
Value generated on add or update means that a new value is generated every time the record is saved (insert or update).
Caution
How the value is generated for added and updated entities will depend on the database provider being used. Database providers may automatically setup value generation for some property types, while others will require you to manually setup how the value is generated.
For example, when using SQL Server, byte[] properties that are set as generated on add or update and marked as concurrency tokens, will be setup with the rowversion data type - so that values will be generated in the database. However, if you specify that a DateTime property is generated on add or update, then you must setup a way for the values to be generated (such as a database trigger).
Like ‘value generated on add’, if you specify a value for the property on a newly added instance of an entity, that value will be inserted rather than a value being generated. Also, if you explicitly change the value assigned to the property (thus marking it as modified) then that new value will be set in the database rather than a value being generated.
Conventions¶
By convention, primary keys that are of an integer or GUID data type will be setup to have values generated on add. All other properties will be setup with no value generation.
Data Annotations¶
No value generation (Data Annotations)¶
1 2 3 4 5 6 | public class Blog
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Value generated on add (Data Annotations)¶
1 2 3 4 5 6 7 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime Inserted { get; set; }
}
|
Caution
This just lets EF know that values are generated for added entities, it does not guarantee that EF will setup the actual mechanism to generate values. See Value generated on add section for more details.
Value generated on add or update (Data Annotations)¶
1 2 3 4 5 6 7 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime LastUpdated { get; set; }
}
|
Caution
This just lets EF know that values are generated for added or updated entities, it does not guarantee that EF will setup the actual mechanism to generate values. See Value generated on add or update section for more details.
Fluent API¶
You can use the Fluent API to change the value generation pattern for a given property.
No value generation (Fluent API)¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.BlogId)
.ValueGeneratedNever();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Value generated on add (Fluent API)¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Inserted)
.ValueGeneratedOnAdd();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public DateTime Inserted { get; set; }
}
|
Caution
This just lets EF know that values are generated for added entities, it does not guarantee that EF will setup the actual mechanism to generate values. See Value generated on add section for more details.
Value generated on add or update (Fluent API)¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.LastUpdated)
.ValueGeneratedOnAddOrUpdate();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public DateTime LastUpdated { get; set; }
}
|
Caution
This just lets EF know that values are generated for added or updated entities, it does not guarantee that EF will setup the actual mechanism to generate values. See Value generated on add or update section for more details.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Required/optional properties¶
A property is considered optional if it is valid for it to contain null
. If null
is not a valid value to be assigned to a property then it is considered to be a required property.
In this article:
Conventions¶
By convention, a property whose CLR type can contain null will be configured as optional (string
, int?
, byte[]
, etc.). Properties whose CLR type cannot contain null will be configured as required (int
, decimal
, bool
, etc.).
Note
A property whose CLR type cannot contain null cannot be configured as optional. The property will always be considered required by Entity Framework.
Data Annotations¶
You can use Data Annotations to indicate that a property is required.
1 2 3 4 5 6 | public class Blog
{
public int BlogId { get; set; }
[Required]
public string Url { get; set; }
}
|
Fluent API¶
You can use the Fluent API to indicate that a property is required.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Maximum Length¶
Configuring a maximum length provides a hint to the data store about the appropriate data type to use for a given property. Maximum length only applies to array data types, such as string
and byte[]
.
Note
Entity Framework does not do any validation of maximum length before passing data to the provider. It is up to the provider or data store to validate if appropriate. For example, when targeting SQL Server, exceeding the maximum length will result in an exception as the data type of the underlying column will not allow excess data to be stored.
In this article:
Conventions¶
By convention, it is left up to the database provider to choose an appropriate data type for properties. For properties that have a length, the database provider will generally choose a data type that allows for the longest length of data. For example, Microsoft SQL Server will use nvarchar(max)
for string
properties (or nvarchar(450)
if the column is used as a key).
Data Annotations¶
You can use the Data Annotations to configure a maximum length for a property. In this example, targeting SQL Server this would result in the nvarchar(500)
data type being used.
1 2 3 4 5 6 | public class Blog
{
public int BlogId { get; set; }
[MaxLength(500)]
public string Url { get; set; }
}
|
Fluent API¶
You can use the Fluent API to configure a maximum length for a property. In this example, targeting SQL Server this would result in the nvarchar(500)
data type being used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.HasMaxLength(500);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Concurrency Tokens¶
If a property is configured as a concurrency token then EF will check that no other user has modified that value in the database when saving changes to that record. EF uses an optimistic concurrency pattern, meaning it will assume the value has not changed and try to save the data, but throw if it finds the value has been changed.
For example we may want to configure LastName
on Person
to be a concurrency token. This means that if one user tries to save some changes to a Person
, but another user has changed the LastName
then an exception will be thrown. This may be desirable so that your application can prompt the user to ensure this record still represents the same actual person before saving their changes.
In this article:
How concurrency tokens work in EF¶
Data stores can enforce concurrency tokens by checking that any record being updated or deleted still has the same value for the concurrency token that was assigned when the context originally loaded the data from the database.
For example, relational database achieve this by including the concurrency token in the WHERE
clause of any UPDATE
or DELETE
commands and checking the number of rows that were affected. If the concurrency token still matches then one row will be updated. If the value in the database has changed, then no rows are updated.
UPDATE [Person] SET [FirstName] = @p1
WHERE [PersonId] = @p0 AND [LastName] = @p2;
Conventions¶
By convention, properties are never configured as concurrency tokens.
Data Annotations¶
You can use the Data Annotations to configure a property as a concurrency token.
1 2 3 4 5 6 7 | public class Person
{
public int PersonId { get; set; }
[ConcurrencyCheck]
public string LastName { get; set; }
public string FirstName { get; set; }
}
|
Fluent API¶
You can use the Fluent API to configure a property as a concurrency token.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.Property(p => p.LastName)
.IsConcurrencyToken();
}
}
public class Person
{
public int PersonId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
|
Timestamp/row version¶
A timestamp is a property where a new value is generated by the database every time a row is inserted or updated. The property is also treated as a concurrency token. This ensures you will get an exception if anyone else has modified a row that you are trying to update since you queried for the data.
How this is achieved is up to the database provider being used. For SQL Server, timestamp is usually used on a byte[] property, which will be setup as a ROWVERSION column in the database.
Conventions¶
By convention, properties are never configured as timestamps.
Data Annotations¶
You can use Data Annotations to configure a property as a timestamp.
1 2 3 4 5 6 7 8 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[Timestamp]
public byte[] Timestamp { get; set; }
}
|
Fluent API¶
You can use the Fluent API to configure a property as a timestamp.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(p => p.Timestamp)
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public byte[] Timestamp { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Shadow Properties¶
Shadow properties are properties that do not exist in your entity class. The value and state of these properties is maintained purely in the Change Tracker.
Shadow property values can be obtained and changed through the ChangeTracker
API.
context.Entry(myBlog).Property("LastUpdated").CurrentValue = DateTime.Now;
Shadow properties can be referenced in LINQ queries via the EF.Property
static method.
var blogs = context.Blogs
.OrderBy(b => EF.Property<DateTime>(b, "LastUpdated"));
In this article:
Conventions¶
By convention, shadow properties are only created when a relationship is discovered but no foreign key property is found in the dependent entity class. In this case, a shadow foreign key property will be introduced. The shadow foreign key property will be named <navigation property name><principal key property name>
(the navigation on the dependent entity, which points to the principal entity, is used for the naming). If the principal key property name includes the name of the navigation property, then the name will just be <principal key property name>
. If there is no navigation property on the dependent entity, then the principal type name is used in its place.
For example, the following code listing will result in a BlogId
shadow property being introduced to the Post
entity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog { get; set; }
}
|
Data Annotations¶
Shadow properties can not be created with data annotations.
Fluent API¶
You can use the Fluent API to configure shadow properties. Once you have called the string overload of Property
you can chain any of the configuration calls you would for other properties.
If the name supplied to the Property
method matches the name of an existing property (a shadow property or one defined on the entity class), then the code will configure that existing property rather than introducing a new shadow property.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property<DateTime>("LastUpdated");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Relationships¶
A relationship defines how two entities relate to each other. In a relational database, this is represented by a foreign key constraint.
Note
Most of the samples in this article use a one-to-many relationship to demonstrate concepts. For examples of one-to-one and many-to-many relationships see the Other Relationship Patterns section at the end of the article.
In this article:
Definition of Terms¶
- There are a number of terms used to describe relationships
- Dependent entity: This is the entity that contains the foreign key property(s). Sometimes referred to as the ‘child’ of the relationship.
- Principal entity: This is the entity that contains the primary/alternate key property(s). Sometimes referred to as the ‘parent’ of the relationship.
- Foreign key: The property(s) in the dependent entity that is used to store the values of the principal key property that the entity is related to.
- Principal key: The property(s) that uniquely identifies the principal entity. This may be the primary key or an alternate key.
- Navigation property: A property defined on the principal and/or dependent entity that contains a reference(s) to the related entity(s).
- Collection navigation property: A navigation property that contains references to many related entities.
- Reference navigation property: A navigation property that holds a reference to a single related entity.
- Inverse navigation property: When discussing a particular navigation property, this term refers to the navigation property on the other end of the relationship.
- The following code listing shows a one-to-many relationship between
Blog
andPost
Post
is the dependent entityBlog
is the principal entityPost.BlogId
is the foreign keyBlog.BlogId
is the principal key (in this case it is a primary key rather than an alternate key)Post.Blog
is a reference navigation propertyBlog.Posts
is a collection navigation propertyPost.Blog
is the inverse navigation property ofBlog.Posts
(and vice versa)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
|
Conventions¶
By convention, a relationship will be created when there is a navigation property discovered on a type. A property is considered a navigation property if the type it points to can not be mapped as a scalar type by the current database provider.
Note
Relationships that are discovered by convention will always target the primary key of the principal entity. To target an alternate key, additional configuration must be performed using the Fluent API.
Fully Defined Relationships¶
- The most common pattern for relationships is to have navigation properties defined on both ends of the relationship and a foreign key property defined in dependent entity class.
- If a pair of navigation properties is found between two types, then they will be configured as inverse navigation properties of the same relationship.
- If the dependent entity contains a property named
<primary key property name>
,<navigation property name><primary key property name>
, or<principal entity name><primary key property name>
then it will be configured as the foreign key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
|
Caution
If there are multiple navigation properties defined between two types (i.e. more than one distinct pair of navigations that point to each other), then no relationships will be created by convention and you will need to manually configure them to identify how the navigation properties pair up.
No Foreign Key Property¶
While it is recommended to have a foreign key property defined in the dependent entity class, it is not required. If no foreign key property is found, a shadow foreign key property will be introduced with the name <navigation property name><principal key property name>
(see Shadow Properties for more information).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog { get; set; }
}
|
Cascade Delete¶
By convention, cascade delete will be set to Cascade for required relationships and SetNull for optional relationships. Cascade means dependent entities are also deleted. SetNull means that foreign key properties in dependent entities are set to null.
Note
This cascading behavior is only applied to entities that are being tracked by the context. A corresponding cascade behavior should be setup in the database to ensure data that is not being tracked by the context has the same action applied. If you use EF to create the database, this cascade behavior will be setup for you.
Data Annotations¶
There are two data annotations that can be used to configure relationships, [ForeignKey]
and [InverseProperty]
.
[ForeignKey]¶
You can use the Data Annotations to configure which property should be used as the foreign key property for a given relationship. This is typically done when the foreign key property is not discovered by convention.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogForeignKey { get; set; }
[ForeignKey("BlogForeignKey")]
public Blog Blog { get; set; }
}
|
Note
The [ForeignKey]
annotation can be placed on either navigation property in the relationship. It does not need to go on the navigation property in the dependent entity class.
[InverseProperty]¶
You can use the Data Annotations to configure how navigation properties on the dependent and principal entities pair up. This is typically done when there is more than one pair of navigation properties between two entity types.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int AuthorUserId { get; set; }
public User Author { get; set; }
public int ContributorUserId { get; set; }
public User Contributor { get; set; }
}
public class User
{
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[InverseProperty("Author")]
public List<Post> AuthoredPosts { get; set; }
[InverseProperty("Contributor")]
public List<Post> ContributedToPosts { get; set; }
}
|
Fluent API¶
To configure a relationship in the Fluent API, you start by identifying the navigation properties that make up the relationship. HasOne
or HasMany
identifies the navigation property on the entity type you are beginning the configuration on. You then chain a call to WithOne
or WithMany
to identify the inverse navigation. HasOne
/WithOne
are used for reference navigation properties and HasMany
/WithMany
are used for collection navigation properties.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog { get; set; }
}
|
Single Navigation Property¶
If you only have one navigation property then there are parameterless overloads of WithOne
and WithMany
. This indicates that there is conceptually a reference or collection on the other end of the relationship, but there is no navigation property included in the entity class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasMany(b => b.Posts)
.WithOne();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
|
Foreign Key¶
You can use the Fluent API to configure which property should be used as the foreign key property for a given relationship.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogForeignKey);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogForeignKey { get; set; }
public Blog Blog { get; set; }
}
|
The following code listing shows how to configure a composite foreign key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasKey(c => new { c.State, c.LicensePlate });
modelBuilder.Entity<RecordOfSale>()
.HasOne(s => s.Car)
.WithMany(c => c.SaleHistory)
.HasForeignKey(s => new { s.CarState, s.CarLicensePlate });
}
}
public class Car
{
public string State { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public List<RecordOfSale> SaleHistory { get; set; }
}
public class RecordOfSale
{
public int RecordOfSaleId { get; set; }
public DateTime DateSold { get; set; }
public decimal Price { get; set; }
public string CarState { get; set; }
public string CarLicensePlate { get; set; }
public Car Car { get; set; }
}
|
Principal Key¶
If you want the foreign key to reference a property other than the primary key, you can use the Fluent API to configure the principal key property for the relationship. The property that you configure as the principal key will automatically be setup as an alternate key (see Alternate Keys for more information).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RecordOfSale>()
.HasOne(s => s.Car)
.WithMany(c => c.SaleHistory)
.HasForeignKey(s => s.CarLicensePlate)
.HasPrincipalKey(c => c.LicensePlate);
}
}
public class Car
{
public int CarId { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public List<RecordOfSale> SaleHistory { get; set; }
}
public class RecordOfSale
{
public int RecordOfSaleId { get; set; }
public DateTime DateSold { get; set; }
public decimal Price { get; set; }
public string CarLicensePlate { get; set; }
public Car Car { get; set; }
}
|
The following code listing shows how to configure a composite principal key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RecordOfSale>()
.HasOne(s => s.Car)
.WithMany(c => c.SaleHistory)
.HasForeignKey(s => new { s.CarState, s.CarLicensePlate })
.HasPrincipalKey(c => new { c.State, c.LicensePlate });
}
}
public class Car
{
public int CarId { get; set; }
public string State { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public List<RecordOfSale> SaleHistory { get; set; }
}
public class RecordOfSale
{
public int RecordOfSaleId { get; set; }
public DateTime DateSold { get; set; }
public decimal Price { get; set; }
public string CarState { get; set; }
public string CarLicensePlate { get; set; }
public Car Car { get; set; }
}
|
Caution
The order that you specify principal key properties must match the order they are specified for the foreign key.
Required¶
You can use the Fluent API to configure whether the relationship is required or optional. Ultimately this controls whether the foreign key property is required or optional. This is most useful when you are using a shadow state foreign key. If you have a foreign key property in your entity class then the requiredness of the relationship is determined based on whether the foreign key property is required or optional (see Required/optional properties for more information).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.IsRequired();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog { get; set; }
}
|
Cascade Delete¶
You can use the Fluent API to configure the cascade delete behavior for a given relationship.
- There are three behaviors that control how a delete operation is applied to dependent entities in a relationship when the principal is deleted or the relationship is severed.
- Cascade: Dependent entities are also deleted.
- SetNull: The foreign key properties in dependent entities are set to null.
- Restrict: The delete operation is not applied to dependent entities. The dependent entities remain unchanged.
Note
This cascading behavior is only applied to entities that are being tracked by the context. A corresponding cascade behavior should be setup in the database to ensure data that is not being tracked by the context has the same action applied. If you use EF to create the database, this cascade behavior will be setup for you.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.OnDelete(DeleteBehavior.Cascade);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int? BlogId { get; set; }
public Blog Blog { get; set; }
}
|
Other Relationship Patterns¶
One-to-one¶
One to one relationships have a reference navigation property on both sides. They follow the same conventions as one-to-many relationships, but a unique index is introduced on the foreign key property to ensure only one dependent is related to each principal.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public BlogImage BlogImage { get; set; }
}
public class BlogImage
{
public int BlogImageId { get; set; }
public byte[] Image { get; set; }
public string Caption { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
|
Note
EF will choose one of the entities to be the dependent based on its ability to detect a foreign key property. If the wrong entity is chosen as the dependent you can use the Fluent API to correct this.
When configuring the relationship with the Fluent API, you use the HasOne
and WithOne
methods.
When configuring the foreign key you need to specify the dependent entity type - notice the generic parameter provided to HasForeignKey
in the listing below. In a one-to-many relationship it is clear that the entity with the reference navigation is the dependent and the one with the collection is the principal. But this is not so in a one-to-one relationship - hence the need to explicitly define it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogImage> BlogImages { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(p => p.BlogImage)
.WithOne(i => i.Blog)
.HasForeignKey<BlogImage>(b => b.BlogForeignKey);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public BlogImage BlogImage { get; set; }
}
public class BlogImage
{
public int BlogImageId { get; set; }
public byte[] Image { get; set; }
public string Caption { get; set; }
public int BlogForeignKey { get; set; }
public Blog Blog { get; set; }
}
|
Many-to-many¶
Many-to-many relationships without an entity class to represent the join table are not yet supported. However, you can represent a many-to-many relationship by including an entity class for the join table and mapping two separate one-to-many relationships.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | class MyContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostTag>()
.HasKey(t => new { t.PostId, t.TagId });
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Indexes¶
Indexes are a common concept across many data stores. While their implementation in the data store may vary, they are used to make lookups based on a column (or set of columns) more efficient.
In this article:
Conventions¶
By convention, an index is created in each property (or set of properties) that are used as a foreign key.
Data Annotations¶
Indexes can not be created using data annotations.
Fluent API¶
You can use the Fluent API specify an index on a single property. By default, indexes are non-unique.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasIndex(b => b.Url);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
You can also specify that an index should be unique, meaning that no two entities can have the same value(s) for the given property(s).
1 2 3 | modelBuilder.Entity<Blog>()
.HasIndex(b => b.Url)
.IsUnique();
|
You can also specify an index over more than one column.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasIndex(p => new { p.FirstName, p.LastName });
}
}
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
|
Note
There is only one index per distinct set of properties. If you use the Fluent API to configure an index on a set of properties that already has an index defined, either by convention or previous configuration, then you will be changing the definition of that index. This is useful if you want to further configure an index that was created by convention.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Alternate Keys¶
An alternate key serves as an alternate unique identifier for each entity instance in addition to the primary key. Alternate keys can be used as the target of a relationship. When using a relational database this maps to the concept of a unique index/constraint on the alternate key column(s) and one or more foreign key constraints that reference the column(s).
Note
If you just want to enforce uniqeness of a column then you want a unique index rather than an alternate key, see Indexes. In EF, alternate keys provide greater functionality than unique indexes because they can be used as the target of a foreign key.
Alternate keys are typically introduced for you when needed and you do not need to manually configure them. See Conventions for more details.
In this article:
Conventions¶
By convention, an alternate key is introduced for you when you identify a property, that is not the primary key, as the target of a relationship.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogUrl)
.HasPrincipalKey(b => b.Url);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string BlogUrl { get; set; }
public Blog Blog { get; set; }
}
|
Data Annotations¶
Alternate keys can not be configured using Data Annotations.
Fluent API¶
You can use the Fluent API to configure a single property to be an alternate key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasAlternateKey(c => c.LicensePlate);
}
}
class Car
{
public int CarId { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
|
You can also use the Fluent API to configure multiple properties to be an alternate key (known as a composite alternate key).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasAlternateKey(c => new { c.State, c.LicensePlate });
}
}
class Car
{
public int CarId { get; set; }
public string State { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Inheritance¶
Inheritance in the EF model is used to control how inheritance in the entity classes is represented in the database.
In this article:
Conventions¶
By convention, it is up to the database provider to determine how inheritance will be represented in the database. See Inheritance (Relational Database) for how this is handled with a relational database provider.
EF will only setup inheritance if two or more inherited types are explicitly included in the model. EF will not scan for base or derived types that were not otherwise included in the model. You can include types in the model by exposing a DbSet<TEntity> for each type in the inheritance hierarchy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<RssBlog> RssBlogs { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class RssBlog : Blog
{
public string RssUrl { get; set; }
}
|
If you don’t want to expose a DbSet<TEntity> for one or more entities in the hierarchy, you can use the Fluent API to ensure they are included in the model.
1 2 3 4 5 6 7 8 9 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RssBlog>();
}
}
|
Data Annotations¶
You cannot use Data Annotations to configure inheritance.
Fluent API¶
The Fluent API for inheritance depends on the database provider you are using. See Inheritance (Relational Database) for the configuration you can perform for a relational database provider.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Backing Fields¶
When a backing field is configured, EF will write directly to that field when materializing entity instances from the database (rather than using the property setter). This is useful when there is no property setter, or the setter contains logic that should not be executed when setting initial property values for existing entities being loaded from the database.
Caution
The ChangeTracker
has not yet been enabled to use backing fields when it needs to set the value of a property. This is only an issue for foreign key properties and generated properties - as the change tracker needs to propagate values into these properties. For these properties, a property setter must still be exposed.
Issue #4461 is tracking enabling the ChangeTracker
to write to backing fields for properties with no setter.
In this article:
Conventions¶
- By convention, the following fields will be discovered as backing fields for a given property (listed in precedence order):
- <propertyName> differing only by case
- _<propertyName>
- m_<propertyName>
1 2 3 4 5 6 7 8 9 10 11 12 | public class Blog
{
private string _url;
public int BlogId { get; set; }
public string Url
{
get { return _url; }
set { _url = value; }
}
}
|
Data Annotations¶
Backing fields cannot be configured with data annotations.
Fluent API¶
There is no top level API for configuring backing fields, but you can use the Fluent API to set annotations that are used to store backing field information.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.HasAnnotation("BackingField", "_blogUrl");
}
}
public class Blog
{
private string _blogUrl;
public int BlogId { get; set; }
public string Url => _blogUrl;
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Relational Database Modeling¶
This section covers aspects of modeling that are specific to relational databases.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Table Mapping¶
Table mapping identifies which table data should be queried from and saved to in the database.
In this article:
Conventions¶
By convention, each entity will be setup to map to a table with the same name as the DbSet<TEntity>
property that exposes the entity on the derived context. If no DbSet<TEntity>
is included for the given entity, the class name is used.
Data Annotations¶
You can use Data Annotations to configure the table that a type maps to.
1 2 3 4 5 6 | [Table("blogs")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
You can also specify a schema that the table belongs to.
1 2 3 4 5 6 | [Table("blogs", Schema = "blogging")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Fluent API¶
You can use the Fluent API to configure the table that a type maps to.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.ToTable("blogs");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
You can also specify a schema that the table belongs to.
1 2 | modelBuilder.Entity<Blog>()
.ToTable("blogs", schema: "blogging");
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Column Mapping¶
Column mapping identifies which column data should be queried from and saved to in the database.
In this article:
Conventions¶
By convention, each property will be setup to map to a column with the same name as the property.
Data Annotations¶
You can use Data Annotations to configure the column to which a property is mapped.
1 2 3 4 5 6 | public class Blog
{
[Column("blog_id")]
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Fluent API¶
You can use the Fluent API to configure the column to which a property is mapped.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.BlogId)
.HasColumnName("blog_id");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Data Types¶
Data type refers to the database specific type of the column to which a property is mapped.
In this article:
Conventions¶
By convention, the database provider selects a data type based on the CLR type of the property. It also takes into account other metadata, such as the configured Maximum Length, whether the property is part of a primary key, etc.
For example, SQL Server uses datetime2(7)
for DateTime
properties, and nvarchar(max)
for string
properties (or nvarchar(450)
for string
properties that are used as a key).
Data Annotations¶
You can use Data Annotations to specify an exact data type for the column.
1 2 3 4 5 6 | public class Blog
{
public int BlogId { get; set; }
[Column(TypeName = "varchar(200)")]
public string Url { get; set; }
}
|
Fluent API¶
You can use the Fluent API to specify an exact data type for the column.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.HasColumnType("varchar(200)");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
If you are targeting more than one relational provider with the same model then you probably want to specify a data type for each provider rather than a global one to be used for all relational providers.
1 2 3 | modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.ForSqlServerHasColumnType("varchar(200)");
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Primary Keys¶
A primary key constraint is introduced for the key of each entity type.
Conventions¶
By convention, the primary key in the database will be named PK_<type name>
.
Data Annotations¶
No relational database specific aspects of a primary key can be configured using Data Annotations.
Fluent API¶
You can use the Fluent API to configure the name of the primary key constraint in the database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasKey(b => b.BlogId)
.HasName("PrimaryKey_BlogId");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Default Schema¶
The default schema is the database schema that objects will be created in if a schema is not explicitly configured for that object.
Conventions¶
By convention, the database provider will choose the most appropriate default schema. For example, Microsoft SQL Server will use the dbo
schema and SQLite will not use a schema (since schemas are not supported in SQLite).
Data Annotations¶
You can not set the default schema using Data Annotations.
Fluent API¶
You can use the Fluent API to specify a default schema.
1 2 3 4 5 6 7 8 9 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("blogging");
}
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Computed Columns¶
A computed column is a column whose value is calculated in the database. A computed column can use other columns in the table to calculate its value.
Conventions¶
By convention, computed columns are not created in the model.
Data Annotations¶
Computed columns can not be configured with Data Annotations.
Fluent API¶
You can use the Fluent API to specify that a property should map to a computed column.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.Property(p => p.DisplayName)
.HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
}
}
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DisplayName { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Sequences¶
A sequence generates a sequential numeric values in the database. Sequences are not associated with a specific table.
Conventions¶
By convention, sequences are not introduced in to the model.
Data Annotations¶
You can not configure a sequence using Data Annotations.
Fluent API¶
You can use the Fluent API to create a sequence in the model.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class MyContext : DbContext
{
public DbSet<Order> Orders { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("OrderNumbers");
}
}
public class Order
{
public int OrderId { get; set; }
public int OrderNo { get; set; }
public string Url { get; set; }
}
|
You can also configure additional aspect of the sequence, such as its schema, start value, and increment.
1 2 3 4 5 6 7 8 9 10 11 | class MyContext : DbContext
{
public DbSet<Order> Orders { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("OrderNumbers", schema: "shared")
.StartsAt(1000)
.IncrementsBy(5);
}
}
|
Once a sequence is introduced, you can use it to generate values for properties in your model. For example, you can use Default Values to insert the next value from the sequence.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class MyContext : DbContext
{
public DbSet<Order> Orders { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("OrderNumbers", schema: "shared")
.StartsAt(1000)
.IncrementsBy(5);
modelBuilder.Entity<Order>()
.Property(o => o.OrderNo)
.HasDefaultValueSql("NEXT VALUE FOR shared.OrderNumbers");
}
}
public class Order
{
public int OrderId { get; set; }
public int OrderNo { get; set; }
public string Url { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Default Values¶
The default value of a column is the value that will be inserted if a new row is inserted but no value is specified for the column.
Conventions¶
By convention, a default value is not configured.
Data Annotations¶
You can not set a default value using Data Annotations.
Fluent API¶
You can use the Fluent API to specify the default value for a property.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Rating)
.HasDefaultValue(3);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public int Rating { get; set; }
}
|
You can also specify a SQL fragment that is used to calculate the default value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public DateTime Created { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Indexes¶
An index in a relational database maps to the same concept as an index in the core of Entity Framework.
Conventions¶
By convention, indexes are named IX_<type name>_<property name>
. For composite indexes <property name>
becomes an underscore separated list of property names.
Data Annotations¶
Indexes can not be configured using Data Annotations.
Fluent API¶
You can use the Fluent API to configure the name of an index.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasIndex(b => b.Url)
.HasName("Index_Url");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Foreign Key Constraints¶
A foreign key constraint is introduced for each relationship in the model.
Conventions¶
By convention, foreign key constraints are named FK_<dependent type name>_<principal type name>_<foreign key property name>
. For composite foreign keys <foreign key property name>
becomes an underscore separated list of foreign key property names.
Data Annotations¶
Foreign key constraint names cannot be configured using data annotations.
Fluent API¶
You can use the Fluent API to configure the foreign key constraint name for a relationship.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogId)
.HasConstraintName("ForeignKey_Post_Blog");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Alternate Keys (Unique Constraints)¶
A unique constraint is introduced for each alternate key in the model.
Conventions¶
By convention, the index and constraint that are introduced for an alternate key will be named AK_<type name>_<property name>
. For composite alternate keys <property name>
becomes an underscore separated list of property names.
Data Annotations¶
Unique constraints can not be configured using Data Annotations.
Fluent API¶
You can use the Fluent API to configure the index and constraint name for an alternate key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasAlternateKey(c => c.LicensePlate)
.HasName("AlternateKey_LicensePlate");
}
}
class Car
{
public int CarId { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Note
The configuration in this section is applicable to relational databases in general. The extension methods shown here will become available when you install a relational database provider (due to the shared Microsoft.EntityFrameworkCore.Relational package).
Inheritance (Relational Database)¶
Inheritance in the EF model is used to control how inheritance in the entity classes is represented in the database.
In this article:
Conventions¶
By convention, inheritance will be mapped using the table-per-hierarchy (TPH) pattern. TPH uses a single table to store the data for all types in the hierarchy. A discriminator column is used to identify which type each row represents.
EF will only setup inheritance if two or more inherited types are explicitly included in the model (see Inheritance for more details).
Below is an example showing a simple inheritance scenario and the data stored in a relational database table using the TPH pattern. The Discriminator column identifies which type of Blog is stored in each row.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<RssBlog> RssBlogs { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class RssBlog : Blog
{
public string RssUrl { get; set; }
}
|

Data Annotations¶
You cannot use Data Annotations to configure inheritance.
Fluent API¶
You can use the Fluent API to configure the name and type of the discriminator column and the values that are used to identify each type in the hierarchy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasDiscriminator<string>("blog_type")
.HasValue<Blog>("blog_base")
.HasValue<RssBlog>("blog_rss");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class RssBlog : Blog
{
public string RssUrl { get; set; }
}
|
Tip
You can view this article’s sample on GitHub.
Methods of configuration¶
Fluent API¶
You can override the OnModelCreating
method in your derived context and use the ModelBuilder
API to configure your model. This is the most powerful method of configuration and allows configuration to be specified without modifying your entity classes. Fluent API configuration has the highest precedence and will override conventions and data annotations.
1 2 3 4 5 6 7 8 9 10 11 | class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
}
|
Data Annotations¶
You can also apply attributes (known as Data Annotations) to your classes and properties. Data annotations will override conventions, but will be overwritten by Fluent API configuration.
1 2 3 4 5 6 | public class Blog
{
public int BlogId { get; set; }
[Required]
public string Url { get; set; }
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Querying Data¶
The following articles are available
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Basic Query¶
Entity Framework Core uses Language Integrate Query (LINQ) to query data from the database. LINQ allows you to use C# (or your .NET language of choice) to write strongly typed queries based on your derived context and entity classes.
In this article:
Tip
You can view this article’s sample on GitHub.
101 LINQ samples¶
This page shows a few examples to achieve common tasks with Entity Framework Core. For an extensive set of samples showing what is possible with LINQ, see 101 LINQ Samples.
Loading all data¶
1 2 3 4 | using (var context = new BloggingContext())
{
var blogs = context.Blogs.ToList();
}
|
Loading a single entity¶
1 2 3 4 5 | using (var context = new BloggingContext())
{
var blog = context.Blogs
.Single(b => b.BlogId == 1);
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Client vs. Server Evaluation¶
Entity Framework Core supports parts of the query being evaluated on the client and parts of it being pushed to the database. It is up to the database provider to determine which parts of the query will be evaluated in the database.
In this article:
Tip
You can view this article’s sample on GitHub.
Client eval¶
In the following example a helper method is used to standardize URLs for blogs that are returned from a SQL Server database. Because the SQL Server provider has no insight into how this method is implemented, it is not possible to translate it into SQL. All other aspects of the query are evaluated in the database, but passing the returned URL
through this method is performed on the client.
1 2 3 4 5 6 7 8 | var blogs = context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(blog => new
{
Id = blog.BlogId,
Url = StandardizeUrl(blog.Url)
})
.ToList();
|
1 2 3 4 5 6 7 8 9 10 11 | public static string StandardizeUrl(string url)
{
url = url.ToLower();
if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
return url;
}
|
Disabling client evaluation¶
While client evaluation can be very useful, in some instances it can result in poor performance. Consider the following query, where the helper method is now used in a filter. Because this can’t be performed in the database, all the data is pulled into memory and then the filter is applied on the client. Depending on the amount of data, and how much of that data is filtered out, this could result in poor performance.
1 2 3 | var blogs = context.Blogs
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToList();
|
By default, EF Core will log a warning when client evaluation is performed. See Logging for more information on viewing logging output. You can change the behavior when client evaluation occurs to either throw or do nothing. This is done when setting up the options for your context - typically in DbContext.OnConfiguring
, or in Startup.cs
if you are using ASP.NET Core.
1 2 3 4 5 6 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;")
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Tracking vs. No-Tracking¶
Tracking behavior controls whether or not Entity Framework Core will keep information about an entity instance in its change tracker. If an entity is tracked, any changes detected in the entity will be persisted to the database during SaveChanges()
. Entity Framework Core will also fix-up navigation properties between entities that are obtained from a tracking query and entities that were previously loaded into the DbContext instance.
In this article:
Tip
You can view this article’s sample on GitHub.
Tracking queries¶
By default, queries that return entity types are tracking. This means you can make changes to those entity instances and have those changes persisted by SaveChanges()
.
In the following example, the change to the blogs rating will be detected and persisted to the database during SaveChanges()
.
1 2 3 4 5 6 | using (var context = new BloggingContext())
{
var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
blog.Rating = 5;
context.SaveChanges();
}
|
No-tracking queries¶
No tracking queries are useful when the results are used in a read-only scenario. They are quicker to execute because there is no need to setup change tracking information.
You can swap an individual query to be no-tracking:
1 2 3 4 5 6 | using (var context = new BloggingContext())
{
var blogs = context.Blogs
.AsNoTracking()
.ToList();
}
|
You can also change the default tracking behavior at the context instance level:
1 2 3 4 5 6 | using (var context = new BloggingContext())
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = context.Blogs.ToList();
}
|
Tracking and projections¶
Even if the result type of the query isn’t an entity type, if the result contains entity types they will still be tracked by default. In the following query, which returns an anonymous type, the instances of Blog
in the result set will be tracked.
1 2 3 4 5 6 7 8 9 10 | using (var context = new BloggingContext())
{
var blog = context.Blogs
.Select(b =>
new
{
Blog = b,
Posts = b.Posts.Count()
});
}
|
If the result set does not contain any entity types, then no tracking is performed. In the following query, which returns an anonymous type with some of the values from the entity (but no instances of the actual entity type), there is no tracking performed.
1 2 3 4 5 6 7 8 9 10 | using (var context = new BloggingContext())
{
var blog = context.Blogs
.Select(b =>
new
{
Id = b.BlogId,
Url = b.Url
});
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Raw SQL Queries¶
Entity Framework Core allows you to drop down to raw SQL queries when working with a relational database. This can be useful if the query you want to perform can’t be expressed using LINQ, or if using a LINQ query is resulting in inefficient SQL being sent to the database.
In this article:
Tip
You can view this article’s sample on GitHub.
Limitations¶
- There are a couple of limitations to be aware of when using raw SQL queries:
- SQL queries can only be used to return entity types that are part of your model. There is an enhancement on our backlog to enable returning ad-hoc types from raw SQL queries.
- The SQL query must return data for all properties of the entity type.
- The column names in the result set must match the column names that properties are mapped to. Note this is different from EF6.x where property/column mapping was ignored for raw SQL queries and result set column names had to match the property names.
- The SQL query cannot contain related data. However, in many cases you can compose on top of the query using the
Include
operator to return related data (see Including related data).
Basic raw SQL queries¶
You can use the FromSql extension method to begin a LINQ query based on a raw SQL query.
1 2 3 | var blogs = context.Blogs
.FromSql("SELECT * FROM dbo.Blogs")
.ToList();
|
Raw SQL queries can be used to execute a stored procedure.
1 2 3 | var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogs")
.ToList();
|
Passing parameters¶
As with any API that accepts SQL, it is important to parameterize any user input to protect against a SQL injection attack. You can include parameter placeholders in the SQL query string and then supply parameter values as additional arguments. Any parameter values you supply will automatically be converted to a DbParameter
.
The following example passes a single parameter to a stored procedure. While this may look like String.Format
syntax, the supplied value is wrapped in a parameter and the generated parameter name inserted where the {0}
placeholder was specified.
1 2 3 4 5 | var user = "johndoe";
var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogsForUser {0}", user)
.ToList();
|
You can also construct a DbParameter and supply it as a parameter value. This allows you to use named parameters in the SQL query string
1 2 3 4 5 | var user = new SqlParameter("user", "johndoe");
var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogsForUser @user", user)
.ToList();
|
Composing with LINQ¶
If the SQL query can be composed on in the database, then you can compose on top of the initial raw SQL query using LINQ operators. SQL queries that can be composed on being with the SELECT
keyword.
The following example uses a raw SQL query that selects from a Table-Valued Function (TVF) and then composes on it using LINQ to perform filtering and sorting.
1 2 3 4 5 6 7 | var searchTerm = ".NET";
var blogs = context.Blogs
.FromSql("SELECT * FROM dbo.SearchBlogs {0}", searchTerm)
.Where(b => b.Rating > 3)
.OrderByDescending(b => b.Rating)
.ToList();
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
How Query Works¶
Entity Framework Core uses Language Integrate Query (LINQ) to query data from the database. LINQ allows you to use C# (or your .NET language of choice) to write strongly typed queries based on your derived context and entity classes.
In this article:
The life of a query¶
The following is a high level overview of the process each query goes through.
- The LINQ query is processed by Entity Framework Core to build a representation that is ready to be processed by the database provider
- The result is cached so that this processing does not need to be done every time the query is executed
- The result is passed to the database provider
- The database provider identifies which parts of the query can be evaluated in the database
- These parts of the query are translated to database specific query language (e.g. SQL for a relational database)
- One or more queries are sent to the database and the result set returned (results are values from the database, not entity instances)
- For each item in the result set
- If this is a tracking query, EF checks if the data represents an entity already in the change tracker for the context instance
- If so, the existing entity is returned
- If not, a new entity is created, change tracking is setup, and the new entity is returned
- If this is a no-tracking query, EF checks if the data represents an entity already in the result set for this query
- If so, the existing entity is returned
- If not, a new entity is created and returned
When queries are executed¶
When you call LINQ operators, you are simply building up an in-memory representation of the query. The query is only sent to the database when the results are consumed.
- The most common operations that result in the query being sent to the database are:
- Iterating the results in a
for
loop - Using an operator such as
ToList
,ToArray
,Single
,Count
- Databinding the results of a query to a UI
- Iterating the results in a
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Saving Data¶
The following articles are available
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Basic Save¶
Learn how to add, modify, and remove data using your context and entity classes.
In this article:
Tip
You can view this article’s sample on GitHub.
ChangeTracker & SaveChanges¶
Each context instance has a ChangeTracker that is responsible for keeping track of changes that need to be written to the database. As you make changes to instances of your entity classes, these changes are recorded in the ChangeTracker and then written to the database when you call SaveChanges.
Adding Data¶
Use the DbSet.Add method to add new instances of your entity classes. The data will be inserted in the database when you call SaveChanges.
1 2 3 4 5 6 7 8 | using (var db = new BloggingContext())
{
var blog = new Blog { Url = "http://sample.com" };
db.Blogs.Add(blog);
db.SaveChanges();
Console.WriteLine(blog.BlogId + ": " + blog.Url);
}
|
Updating Data¶
EF will automatically detect changes made to an existing entity that is tracked by the context. This includes entities that you load/query from the database, and entities that were previously added and saved to the database.
Simply modify the values assigned to properties and then call SaveChanges.
1 2 3 4 5 6 | using (var db = new BloggingContext())
{
var blog = db.Blogs.First();
blog.Url = "http://sample.com/blog";
db.SaveChanges();
}
|
Deleting Data¶
Use the DbSet.Remove method to delete instances of you entity classes.
If the entity already exists in the database, it will be deleted during SaveChanges. If the entity has not yet been saved to the database (i.e. it is tracked as added) then it will be removed from the context and will no longer be inserted when SaveChanges is called.
1 2 3 4 5 6 | using (var db = new BloggingContext())
{
var blog = db.Blogs.First();
db.Blogs.Remove(blog);
db.SaveChanges();
}
|
Multiple Operations in a single SaveChanges¶
You can combine multiple Add/Update/Remove operations into a single call to SaveChanges.
Note
For most database providers, SaveChanges is transactional. This means all the operations will either succeed or fail and the operations will never be left partially applied.
1 2 3 4 5 6 7 8 9 10 11 12 13 | using (var db = new BloggingContext())
{
db.Blogs.Add(new Blog { Url = "http://sample.com/blog_one" });
db.Blogs.Add(new Blog { Url = "http://sample.com/blog_two" });
var firstBlog = db.Blogs.First();
firstBlog.Url = "";
var lastBlog = db.Blogs.Last();
db.Blogs.Remove(lastBlog);
db.SaveChanges();
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Cascade Delete¶
Cascade delete allows deletion of a principal/parent entity to have a side effect on dependent/child entities it is related to.
- There are three cascade delete behaviors:
- Cascade: Dependent entities are also deleted.
- SetNull: The foreign key properties in dependent entities are set to null.
- Restrict: The delete operation is not applied to dependent entities. The dependent entities remain unchanged.
See Relationships for more information about conventions and configuration for cascade delete.
In this article:
Tip
You can view this article’s sample on GitHub.
Cascading to tracked entities¶
When you call SaveChanges, the cascade delete rules will be applied to any entities that are being tracked by the context.
Consider a simple Blog and Post model where the relationship between the two entities is required. By convention. the cascade behavior for this relationship is set to Cascade.
The following code loads a Blog and all its related Posts from the database (using the Include method). The code then deletes the Blog.
1 2 3 4 5 6 | using (var db = new BloggingContext())
{
var blog = db.Blogs.Include(b => b.Posts).First();
db.Remove(blog);
db.SaveChanges();
}
|
Because all the Posts are tracked by the context, the cascade behavior is applied to them before saving to the database. EF therefore issues a DELETE statement for each entity.
DELETE FROM [Post]
WHERE [PostId] = @p0;
DELETE FROM [Post]
WHERE [PostId] = @p1;
DELETE FROM [Blog]
WHERE [BlogId] = @p2;
Cascading to untracked entities¶
The following code is almost the same as our previous example, except it does not load the related Posts from the database.
1 2 3 4 5 6 | using (var db = new BloggingContext())
{
var blog = db.Blogs.First();
db.Remove(blog);
db.SaveChanges();
}
|
Because the Posts are not tracked by the context, a DELETE statement is only issued for the Blog. This relies on a corresponding cascade behavior being present in the database to ensure data that is not tracked by the context is also deleted. If you use EF to create the database, this cascade behavior will be setup for you.
DELETE FROM [Blog]
WHERE [BlogId] = @p0;
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Concurrency Conflicts¶
If a property is configured as a concurrency token then EF will check that no other user has modified that value in the database when saving changes to that record.
In this article:
Tip
You can view this article’s sample on GitHub.
How concurrency works in EF¶
For a detailed description of how concurrency works in Entity Framework Core, see Concurrency Tokens.
Resolving concurrency conflicts¶
Resolving a concurrency conflict involves using an algorithm to merge the pending changes from the current user with the changes made in the database. The exact approach will vary based on your application, but a common approach is to display the values to the user and have them decide the correct values to be stored in the database.
- There are three sets of values available to help resolve a concurrency conflict.
- Current values are the values that the application was attempting to write to the database.
- Original values are the values that were originally retrieved from the database, before any edits were made.
- Database values are the values currently stored in the database.
To handle a concurrency conflict, catch a DbUpdateConcurrencyException
during SaveChanges()
, use DbUpdateConcurrencyException.Entries
to prepare a new set of changes for the affected entities, and then retry the SaveChanges()
operation.
In the following example, Person.FirstName
and Person.LastName
are setup as concurrency token. There is a // TODO:
comment in the location where you would include application specific logic to choose the value to be saved to the database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace EFSaving.Concurrency
{
public class Sample
{
public static void Run()
{
// Ensure database is created and has a person in it
using (var context = new PersonContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.People.Add(new Person { FirstName = "John", LastName = "Doe" });
context.SaveChanges();
}
using (var context = new PersonContext())
{
// Fetch a person from database and change phone number
var person = context.People.Single(p => p.PersonId == 1);
person.PhoneNumber = "555-555-5555";
// Change the persons name in the database (will cause a concurrency conflict)
context.Database.ExecuteSqlCommand("UPDATE dbo.People SET FirstName = 'Jane' WHERE PersonId = 1");
try
{
// Attempt to save changes to the database
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
if (entry.Entity is Person)
{
// Using a NoTracking query means we get the entity but it is not tracked by the context
// and will not be merged with existing entities in the context.
var databaseEntity = context.People.AsNoTracking().Single(p => p.PersonId == ((Person)entry.Entity).PersonId);
var databaseEntry = context.Entry(databaseEntity);
foreach (var property in entry.Metadata.GetProperties())
{
var proposedValue = entry.Property(property.Name).CurrentValue;
var originalValue = entry.Property(property.Name).OriginalValue;
var databaseValue = databaseEntry.Property(property.Name).CurrentValue;
// TODO: Logic to decide which value should be written to database
// entry.Property(property.Name).CurrentValue = <value to be saved>;
// Update original values to
entry.Property(property.Name).OriginalValue = databaseEntry.Property(property.Name).CurrentValue;
}
}
else
{
throw new NotSupportedException("Don't know how to handle concurrency conflicts for " + entry.Metadata.Name);
}
}
// Retry the save operation
context.SaveChanges();
}
}
}
public class PersonContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True;");
}
}
public class Person
{
public int PersonId { get; set; }
[ConcurrencyCheck]
public string FirstName { get; set; }
[ConcurrencyCheck]
public string LastName { get; set; }
public string PhoneNumber { get; set; }
}
}
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Transactions¶
Transactions allow several database operations to be processed in an atomic manner. If the transaction is committed, all of the operations are successfully applied to the database. If the transaction is rolled back, none of the operations are applied to the database.
In this article:
Tip
You can view this article’s sample on GitHub.
Default transaction behavior¶
By default, if the database provider supports transactions, all changes in a single call to SaveChanges()
are applied in a transaction. If any of the changes fail, then the transaction is rolled back and none of the changes are applied to the database. This means that SaveChanges()
is guaranteed to either completely succeed, or leave the database unmodified if an error occurs.
For most applications, this default behavior is sufficient. You should only manually control transactions if your application requirements deem it necessary.
Controlling transactions¶
You can use the DbContext.Database
API to begin, commit, and rollback transactions. The following example shows two SaveChanges()
operations and a LINQ query being executed in a single transaction.
Not all database providers support transactions. Some providers may throw or no-op when transaction APIs are called.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | using (var context = new BloggingContext())
{
using (var transaction = context.Database.BeginTransaction())
{
try
{
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });
context.SaveChanges();
var blogs = context.Blogs
.OrderBy(b => b.Url)
.ToList();
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
transaction.Commit();
}
catch (Exception)
{
// TODO: Handle failure
}
}
}
|
Cross-context transaction (relational databases only)¶
You can also share a transaction across multiple context instances. This functionality is only available when using a relational database provider because it requires the use of DbTransaction
and DbConnection
, which are specific to relational databases.
To share a transaction, the contexts must share both a DbConnection
and a DbTransaction
.
Allow connection to be externally provided¶
Sharing a DbConnection
requires the ability to pass a connection into a context when constructing it.
The easiest way to allow DbConnection
to be externally provided, is to stop using the DbContext.OnConfiguring
method to configure the context and externally create DbContextOptions
and pass them to the context constructor.
Tip
DbContextOptionsBuilder
is the API you used in DbContext.OnConfiguring
to configure the context, you are now going to use it externally to create DbContextOptions
.
1 2 3 4 5 6 7 8 | public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
|
An alternative is to keep using DbContext.OnConfiguring
, but accept a DbConnection
that is saved and then used in DbContext.OnConfiguring
.
public class BloggingContext : DbContext
{
private DbConnection _connection;
public BloggingContext(DbConnection connection)
{
_connection = connection;
}
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connection);
}
}
Using external DbTransactions (relational databases only)¶
If you are using multiple data access technologies to access a relational database, you may want to share a transaction between operations performed by these different technologies.
The following example, shows how to perform an ADO.NET SqlClient operation and an Entity Framework Core operation in the same transaction.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | var connection = new SqlConnection(connectionString);
connection.Open();
using (var transaction = connection.BeginTransaction())
{
try
{
// Run raw ADO.NET command in the transaction
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandText = "DELETE FROM dbo.Blogs";
command.ExecuteNonQuery();
// Run an EF Core command in the transaction
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options;
using (var context = new BloggingContext(options))
{
context.Database.UseTransaction(transaction);
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
}
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
transaction.Commit();
}
catch (System.Exception)
{
// TODO: Handle failure
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
🔧 Disconnected Entities¶
Note
This topic hasn’t been written yet! You can track the status of this issue through our public GitHub issue tracker. Learn how you can contribute on GitHub.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Setting explicit values for generated properties¶
A generated property is a property whose value is generated (either by EF or the database) when the entity is added and/or updated. See Generated Properties for more information.
There may be situations where you want to set an explicit value for a generated property, rather than having one generated.
In this article:
Tip
You can view this article’s sample on GitHub.
The model¶
The model used in this article contains a single Employee
entity.
1 2 3 4 5 6 | public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public DateTime EmploymentStarted { get; set; }
}
|
- The context is setup to target SQL Server:
- By convention the
Employee.EmployeeId
property will be a store generatedIDENTITY
column - The
Employee.EmploymentStarted
property has also been setup to have values generated by the database for new entities
- By convention the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class EmployeeContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFSaving.ExplicitValuesGenerateProperties;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.Property(b => b.EmploymentStarted)
.HasDefaultValueSql("CONVERT(date, GETDATE())");
}
}
|
Saving an explicit value during add¶
- In the following code, two employees are being inserted into the database
- For the first, no value is assigned to
Employee.EmploymentStarted
property, so it remains set to the CLR default value forDateTime
. - For the second, we have set an explicit value of
1-Jan-2000
.
- For the first, no value is assigned to
1 2 3 4 5 6 7 8 9 10 11 | using (var db = new EmployeeContext())
{
db.Employees.Add(new Employee { Name = "John Doe" });
db.Employees.Add(new Employee { Name = "Jane Doe", EmploymentStarted = new DateTime(2000, 1, 1) });
db.SaveChanges();
foreach (var employee in db.Employees)
{
Console.WriteLine(employee.EmployeeId + ": " + employee.Name + ", " + employee.EmploymentStarted);
}
}
|
The code results in the following output, showing that the database generated a value for the first employee and our explicit value was used for the second:
1: John Doe, 1/28/2016 12:00:00 AM
2: Jane Doe, 1/1/2000 12:00:00 AM
Explicit values into SQL Server IDENTITY columns¶
For most situations, the approach shown above will work for key properties. However, to insert explicit values into a SQL Server IDENTITY
column, you need to manually enable IDENTITY_INSERT
before calling SaveChanges()
.
Note
We have a feature request on our backlog to do this automatically within the SQL Server provider.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | using (var db = new EmployeeContext())
{
db.Employees.Add(new Employee { EmployeeId = 100, Name = "John Doe" });
db.Employees.Add(new Employee { EmployeeId = 101, Name = "Jane Doe" });
db.Database.OpenConnection();
try
{
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employee ON");
db.SaveChanges();
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employee OFF");
}
finally
{
db.Database.CloseConnection();
}
foreach (var employee in db.Employees)
{
Console.WriteLine(employee.EmployeeId + ": " + employee.Name);
}
}
|
Setting an explicit values during update¶
Caution
Due to various bugs, this scenario is not properly supported in the current pre-release of EF Core. See documentation issue #122 for more details.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
EF Core vs. EF6.x¶
The following articles are available
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Which One Is Right for You¶
The following information will help you choose between Entity Framework Core and Entity Framework 6.x.
In this article:
What is EF6.x¶
Entity Framework 6.x (EF6.x) is a tried and tested data access technology with many years of features and stabilization. It first released in 2008, as part of .NET Framework 3.5 SP1 and Visual Studio 2008 SP1. Starting with the EF4.1 release it has shipped as the EntityFramework NuGet package - currently the most popular package on NuGet.org.
EF6.x continues to be a supported product, and will continue to see bug fixes and minor improvements for some time to come.
What is EF Core¶
Entity Framework Core (EF Core) is a lightweight, extensible, and cross-platform version of Entity Framework. EF Core introduces many improvements and new features when compared with EF6.x. At the same time, EF Core is a new code base and very much a v1 product.
EF Core keeps the developer experience from EF6.x, and most of the top-level APIs remain the same too, so EF Core will feel very familiar to folks who have used EF6.x. At the same time, EF Core is built over a completely new set of core components. This means EF Core doesn’t automatically inherit all the features from EF6.x. Some of these features will show up in future releases (such as lazy loading and connection resiliency), other less commonly used features will not be implemented in EF Core.
The new, extensible, and lightweight core has also allowed us to add some features to EF Core that will not be implemented in EF6.x (such as alternate keys and mixed client/database evaluation in LINQ queries).
See Feature Comparison for a detailed comparison of how the feature set in EF Core compares to EF6.x.
Guidance for new applications¶
Because EF Core is a new product, and still lacks some critical O/RM features, EF6.x will still be the most suitable choice for many applications.
- These are the types of applications we would recommend using EF Core for.
- New applications that do not require features that are not yet implemented in EF Core. Review Feature Comparison to see if EF Core may be a suitable choice for your application.
- Applications that target .NET Core, such as Universal Windows Platform (UWP) and ASP.NET Core applications. These applications can not use EF6.x as it requires the Full .NET Framework (i.e. .NET Framework 4.5).
Guidance for existing EF6.x applications¶
Because of the fundamental changes in EF Core we do not recommend attempting to move an EF6.x application to EF Core unless you have a compelling reason to make the change. If you want to move to EF Core to make use of new features, then make sure you are aware of its limitations before you start. Review Feature Comparison to see if EF Core may be a suitable choice for your application.
You should view the move from EF6.x to EF Core as a port rather than an upgrade. See Porting from EF6.x to EF Core for more information.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Feature Comparison¶
The following information will help you choose between Entity Framework Core and Entity Framework 6.x.
In this article:
Features not in EF Core¶
This is a list of features not currently implemented in EF Core that are likely to impact your ability to use it in a given application. This is by no means an exhaustive list of possible O/RM features, but the features that we feel have the highest impact on developers.
- Creating a Model
- Complex/value types are types that do not have a primary key and are used to represent a set of properties on an entity type.
- Visualizing a model to see a graphical representation of the code-based model.
- Simple type conversions such as string => xml.
- Spatial data types such as SQL Server’s geography & geometry.
- Many-to-many relationships without join entity. You can already model a many-to-many relationship with a join entity, see Relationships for details.
- Alternate inheritance mapping patterns for relational databases, such as table per type (TPT) and table per concrete type (TPC). Table per hierarchy (TPH) is already supported.
- Querying Data
- Improved translation to enable more queries to successfully execute, with more logic being evaluated in the database (rather than in-memory).
- GroupBy translation in particular will move translation of the LINQ GroupBy operator to the database, rather than in-memory.
- Lazy loading enables navigation properties to be automatically populated from the database when they are accessed.
- Explicit Loading allows you to trigger population of a navigation property on an entity that was previously loaded from the database.
- Raw SQL queries for non-model types allows a raw SQL query to be used to populate types that are not part of the model (typically for denormalized view-model data).
- Saving Data
- Simple command interception provides an easy way to read/write commands before/after they are sent to the database.
- Missing EntityEntry APIs from EF6.x such as
Reload
,GetModifiedProperties
,GetDatabaseValues
etc. - Stored procedure mapping allows EF to use stored procedures to persist changes to the database (
FromSql
already provides good support for using a stored procedure to query, see Raw SQL Queries for details). - Connection resiliency automatically retries failed database commands. This is especially useful when connection to SQL Azure, where transient failures are common.
- Database Schema Management
- Visual Studio wizard for reverse engineer that allows you to visually configure connection, select tables, etc. when creating a model from an existing database.
- Update model from database allows a model that was previously reverse engineered from the database to be refreshed with changes made to the schema.
- Seed data allows a set of data to be easily upserted to the database.
Side-by-side comparison¶
The following table compares the features available in EF Core and EF6.x. It is intended to give a high level comparison and does not list every feature, or attempt to give details on possible differences between how the same feature works.
Creating a Model | EF6.x | EF Core 1.0.0 |
Basic modelling (classes, properties, etc.) | Yes | Yes |
Conventions | Yes | Yes |
Custom conventions | Yes | Partial |
Data annotations | Yes | Yes |
Fluent API | Yes | Yes |
Inheritance: Table per hierarchy (TPH) | Yes | Yes |
Inheritance: Table per type (TPT) | Yes | |
Inheritance: Table per concrete class (TPC) | Yes | |
Shadow state properties | Yes | |
Alternate keys | Yes | |
Many-to-many: With join entity | Yes | Yes |
Many-to-many: Without join entity | Yes | |
Key generation: Database | Yes | Yes |
Key generation: Client | Yes | |
Complex/value types | Yes | |
Spatial data | Yes | |
Graphical visualization of model | Yes | |
Graphical drag/drop editor | Yes | |
Model format: Code | Yes | Yes |
Model format: EDMX (XML) | Yes | |
Reverse engineer model from database: Command line | Yes | |
Reverse engineer model from database: VS wizard | Yes | |
Incremental update model from database | Yes | |
Querying Data | EF6.x | EF Core 1.0.0 |
LINQ: Simple queries | Stable | Stable |
LINQ: Moderate queries | Stable | Stabilizing |
LINQ: Complex queries | Stable | In-Progress |
LINQ: Queries using navigation properties | Stable | In-Progress |
“Pretty” SQL generation | Poor | Yes |
Mixed client/server evaluation | Yes | |
Loading related data: Eager | Yes | Yes |
Loading related data: Lazy | Yes | |
Loading related data: Explicit | Yes | |
Raw SQL queries: Model types | Yes | Yes |
Raw SQL queries: Un-mapped types | Yes | |
Raw SQL queries: Composing with LINQ | Yes | |
Saving Data | EF6.x | EF Core 1.0.0 |
SaveChanges | Yes | Yes |
Change tracking: Snapshot | Yes | Yes |
Change tracking: Notification | Yes | Yes |
Accessing tracked state | Yes | Partial |
Optimistic concurrency | Yes | Yes |
Transactions | Yes | Yes |
Batching of statements | Yes | |
Stored procedure | Yes | |
Detached graph support (N-Tier): Low level APIs | Poor | Yes |
Detached graph support (N-Tier): End-to-end | Poor | |
Other Features | EF6.x | EF Core 1.0.0 |
Migrations | Yes | Yes |
Database creation/deletion APIs | Yes | Yes |
Seed data | Yes | |
Connection resiliency | Yes | |
Lifecycle hooks (events, command interception, ...) | Yes | |
Database Providers | EF6.x | EF Core 1.0.0 |
SQL Server | Yes | Yes |
MySQL | Yes | Paid only, unpaid coming soon 1 |
PostgreSQL | Yes | Yes |
Oracle | Yes | Paid only, unpaid coming soon 1 |
SQLite | Yes | Yes |
SQL Compact | Yes | Yes |
DB2 | Yes | Yes |
InMemory (for testing) | Yes | |
Azure Table Storage | Prototype | |
Redis | Prototype | |
Application Models | EF6.x | EF Core 1.0.0 |
WinForms | Yes | Yes |
WPF | Yes | Yes |
Console | Yes | Yes |
ASP.NET | Yes | Yes |
ASP.NET Core | Yes | |
Xamarin | Coming soon 2 | |
UWP | Yes |
- Footnotes:
- 1 Paid providers are available, unpaid providers are being worked on. The teams working on the unpaid providers have not shared public details of timeline etc.
- 2 EF Core is built to work on Xamarin when support for .NET Standard is enabled in Xamarin.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Porting from EF6.x to EF Core¶
The following articles cover porting from EF6.x to EF Core
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Ensure EF Core Will Work for Your Application¶
Before you start the porting process it is important to validate that EF Core meets the data access requirements for your application.
In this article:
Missing features¶
Make sure that EF Core has all the features you need to use in your application. See Feature Comparison for a detailed comparison of how the feature set in EF Core compares to EF6.x. If any required features are missing, ensure that you can compensate for the lack of these features before porting to EF Core.
Behavior changes¶
This is a non-exhaustive list of some changes in behavior between EF6.x and EF Core. It is important to keep these in mind as your port your application as they may change the way your application behaves, but will not show up as compilation errors after swapping to EF Core.
DbSet.Add/Attach and graph behavior¶
In EF6.x, calling DbSet.Add()
on an entity results in a recursive search for all entities referenced in its navigation properties. Any entities that are found, and are not already tracked by the context, are also be marked as added. DbSet.Attach()
behaves the same, except all entities are marked as unchanged.
- EF Core performs a similar recursive search, but with some slightly different rules.
The root entity is always in the requested state (added for
DbSet.Add
and unchanged forDbSet.Attach
).- For entities that are found during the recursive search of navigation properties:
- If the primary key of the entity is store generated
- If the primary key is not set to a value, the state is set to added. The primary key value is considered “not set” if it is assigned the CLR default value for the property type (i.e.
0
forint
,null
forstring
, etc.). - If the primary key is set to a value, the state is set to unchanged.
- If the primary key is not set to a value, the state is set to added. The primary key value is considered “not set” if it is assigned the CLR default value for the property type (i.e.
If the primary key is not database generated, the entity is put in the same state as the root.
Code First database initialization¶
- EF6.x has a significant amount of magic it performs around selecting the database connection and initializing the database. Some of these rules include:
- If no configuration is performed, EF6.x will select a database on SQL Express or LocalDb.
- If a connection string with the same name as the context is in the applications
App/Web.config
file, this connection will be used. - If the database does not exist, it is created.
- If none of the tables from the model exist in the database, the schema for the current model is added to the database. If migrations are enabled, then they are used to create the database.
- If the database exists and EF6.x had previously created the schema, then the schema is checked for compatibility with the current model. An exception is thrown if the model has changed since the schema was created.
- EF Core does not perform any of this magic.
- The database connection must be explicitly configured in code.
- No initialization is performed. You must use
DbContext.Database.Migrate()
to apply migrations (orDbContext.Database.EnsureCreated()
andEnsureDeleted()
to create/delete the database without using migrations).
Code First table naming convention¶
EF6.x runs the entity class name through a pluralization service to calculate the default table name that the entity is mapped to.
EF Core uses the name of the DbSet
property that the entity is exposed in on the derived context. If the entity does not have a DbSet
property, then the class name is used.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Porting an EDMX-Based Model (Model First & Database First)¶
EF Core does not support the EDMX file format for models. The best option to port these models, is to generate a new code-based model from the database for your application.
In this article:
Install EF Core NuGet packages¶
Install the Microsoft.EntityFrameworkCore.Tools
NuGet package.
You also need to install the design time NuGet package for the database provider you want to use. This is typically the runtime database provider package name with .Design
post-fixed. For example, when targeting SQL Server, you would install Microsoft.EntityFrameworkCore.SqlServer.Design
. See Database Providers for details.
Regenerate the model¶
You can now use the reverse engineer functionality to create a model based on your existing database.
Run the following command in Package Manager Console (Package Manager Console (Visual Studio) for command options to scaffold a subset of tables etc.
). See1 | Scaffold-DbContext "<connection string>" <database provider name>
|
For example, here is the command to scaffold a model from the Blogging database on your SQL Server LocalDB instance.
1 | Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer
|
Remove EF6.x model¶
You would now remove the EF6.x model from your application.
It is fine to leave the EF6.x NuGet package (EntityFramework) installed, as EF Core and EF6.x can be used side-by-side in the same application. However, if you aren’t intending to use EF6.x in any areas of your application, then uninstalling the package will help give compile errors on pieces of code that need attention.
Update your code¶
At this point, it’s a matter of addressing compilation errors and reviewing code to see if the behavior changes between EF6.x and EF Core will impact you.
Test the port¶
Just because your application compiles, does not mean it is successfully ported to EF Core. You will need to test all areas of your application to ensure that none of the behavior changes have adversely impacted your application.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Porting a Code-Based Model (Code First & Code First to Existing Database)¶
If you’ve read all the caveats and you are ready to port, then here are some guidelines to help you get started.
In this article:
Install EF Core NuGet packages¶
To use EF Core, you install the NuGet package for the database provider you want to use. For example, when targeting SQL Server, you would install Microsoft.EntityFrameworkCore.SqlServer
. See Database Providers for details.
If you are planning to use migrations, then you should also install the Microsoft.EntityFrameworkCore.Tools
package.
It is fine to leave the EF6.x NuGet package (EntityFramework) installed, as EF Core and EF6.x can be used side-by-side in the same application. However, if you aren’t intending to use EF6.x in any areas of your application, then uninstalling the package will help give compile errors on pieces of code that need attention.
Swap namespaces¶
Most APIs that you use in EF6.x are in the System.Data.Entity
namespace (and related sub-namespaces). The first code change is to swap to the Microsoft.EntityFrameworkCore
namespace. You would typically start with your derived context code file and then work out from there, addressing compilation errors as they occur.
Context configuration (connection etc.)¶
As described in Ensure EF Core Will Work for Your Application, EF Core has less magic around detecting the database to connect to. You will need to override the OnConfiguring
method on your derived context, and use the database provider specific API to setup the connection to the database.
Most EF6.x applications store the connection string in the applications App/Web.config
file. In EF Core, you read this connection string using the ConfigurationManager
API. You may need to add a reference to the System.Configuration
framework assembly to be able to use this API.
1 2 3 4 5 6 7 8 9 10 | public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["BloggingDatabase"].ConnectionString);
}
}
|
Update your code¶
At this point, it’s a matter of addressing compilation errors and reviewing code to see if the behavior changes will impact you.
Existing migrations¶
There isn’t really a feasible way to port existing EF6.x migrations to EF Core.
If possible, it is best to assume that all previous migrations from EF6.x have been applied to the database and then start migrating the schema from that point using EF Core. To do this, you would use the Add-Migration
command to add a migration once the model is ported to EF Core. You would then remove all code from the Up
and Down
methods of the scaffolded migration. Subsequent migrations will compare to the model when that initial migration was scaffolded.
Test the port¶
Just because your application compiles, does not mean it is successfully ported to EF Core. You will need to test all areas of your application to ensure that none of the behavior changes have adversely impacted your application.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
EF6.x and EF Core in the Same Application¶
It is possible to use EF Core and EF6.x in the same application. EF Core and EF6.x have the same type names that differ only by namespace, so this may complicate code that attempts to use both EF Core and EF6.x in the same code file.
If you are porting an existing application that has multiple EF models, then you can selectively port some of them to EF Core, and continue using EF6.x for the others.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Database Providers¶
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Microsoft SQL Server¶
This database provider allows Entity Framework Core to be used with Microsoft SQL Server (including SQL Azure). The provider is maintained as part of the EntityFramework GitHub project.
In this article:
Install¶
Install the Microsoft.EntityFrameworkCore.SqlServer NuGet package.
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
Get Started¶
- The following resources will help you get started with this provider.
Supported Database Engines¶
- Microsoft SQL Server (2008 onwards)
Supported Platforms¶
- Full .NET (4.5.1 onwards)
- .NET Core
- Mono (4.2.0 onwards)
Caution
Using this provider on Mono will make use of the Mono SQL Client implementation, which has a number of known issues. For example, it does not support secure connections (SSL).
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
SQLite¶
This database provider allows Entity Framework Core to be used with SQLite. The provider is maintained as part of the EntityFramework GitHub project.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
SQLite Limitations¶
When using the SQLite provider, there are a number of limitations you should be aware of. Most of these are a result of limitations in the underlying SQLite database engine and are not specific to EF.
Modeling Limitations¶
The common relational library (shared by Entity Framework relational database providers) defines APIs for modelling concepts that are common to most relational database engines. A number of these concepts are not supported by the SQLite provider.
- Schemas
- Sequences
Migrations Limitations¶
The SQLite database engine does not support a number of schema operations that are supported by the majority of other relational databases. If you attempt to apply one of the unsupported operations to a SQLite database then a NotSupportedException
will be thrown.
Operation | Supported? |
---|---|
AddColumn | ✔ |
AddForeignKey | ✗ |
AddPrimaryKey | ✗ |
AddUniqueConstraint | ✗ |
AlterColumn | ✗ |
AlterSequence | ✗ |
CreateIndex | ✔ |
CreateSchema | ✗ |
CreateSequence | ✗ |
CreateTable | ✔ |
DropColumn | ✗ |
DropForiegnKey | ✗ |
DropIndex | ✔ |
DropPrimaryKey | ✗ |
DropSchema | ✗ |
DropSequence | ✗ |
DropTable | ✔ |
DropUniqueConstraint | ✗ |
RenameColumn | ✗ |
RenameIndex | ✗ |
RenameSequence | ✗ |
RenameTable | ✔ |
RestartSequence | ✗ |
Tip
You can workaround some of these limitations by manually writing code in your migrations to perform a table rebuild. A table rebuild involves renaming the existing table, creating a new table, copying data to the new table, and dropping the old table. You will need to use the Sql(string)
method to perform some of these steps.
See Making Other Kinds Of Table Schema Changes in the SQLite documentation for more details.
In the future, EF may support some of these operations by using the table rebuild approach under the covers. You can track this feature on our GitHub project.
In this article:
Install¶
Install the Microsoft.EntityFrameworkCore.SQLite NuGet package.
PM> Install-Package Microsoft.EntityFrameworkCore.SQLite
Get Started¶
- The following resources will help you get started with this provider.
Supported Database Engines¶
- SQLite (3.7 onwards)
Supported Platforms¶
- Full .NET (4.5.1 onwards)
- .NET Core
- Mono (4.2.0 onwards)
- Universal Windows Platform
Limitations¶
See SQLite Limitations for some important limitations of the SQLite provider.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Npgsql (PostgreSQL)¶
This database provider allows Entity Framework Core to be used with PostgreSQL. The provider is maintained as part of the Npgsql project.
Note
This provider is not maintained as part of the Entity Framework Core project. When considering a third party provider, be sure to evaluate quality, licensing, support, etc. to ensure they meet your requirements.
In this article:
Install¶
Install the Npgsql.EntityFrameworkCore.PostgreSQL NuGet package.
PM> Install-Package Npgsql.EntityFrameworkCore.PostgreSQL
Get Started¶
See the Npgsql documentation to get started.
Supported Database Engines¶
- PostgreSQL
Supported Platforms¶
- Full .NET (4.5.1 onwards)
- .NET Core
- Mono (4.2.0 onwards)
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
MySQL (Official)¶
This database provider allows Entity Framework Core to be used with MySQL. The provider is maintained as part of the MySQL project.
Caution
This provider is pre-release.
Note
This provider is not maintained as part of the Entity Framework Core project. When considering a third party provider, be sure to evaluate quality, licensing, support, etc. to ensure they meet your requirements.
In this article:
Install¶
Install the MySql.Data.EntityFrameworkCore NuGet package.
PM> Install-Package MySql.Data.EntityFrameworkCore -Pre
Supported Platforms¶
- Full .NET (4.5.1 onwards)
- .NET Core
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Pomelo (MySQL)¶
This database provider allows Entity Framework Core to be used with MySQL. The provider is maintained as part of the Pomelo Foundation Project.
Note
This provider is not maintained as part of the Entity Framework Core project. When considering a third party provider, be sure to evaluate quality, licensing, support, etc. to ensure they meet your requirements.
In this article:
Install¶
Install the Pomelo.EntityFrameworkCore.MySQL NuGet package.
PM> Install-Package Pomelo.EntityFrameworkCore.MySQL
Get Started¶
- The following resources will help you get started with this provider.
Supported Platforms¶
- Full .NET (4.5.1 onwards)
- .NET Core
- Mono (4.2.0 onwards)
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Microsoft SQL Server Compact Edition¶
This database provider allows Entity Framework Core to be used with SQL Server Compact Edition. The provider is maintained as part of the ErikEJ/EntityFramework.SqlServerCompact GitHub Project.
Note
This provider is not maintained as part of the Entity Framework Core project. When considering a third party provider, be sure to evaluate quality, licensing, support, etc. to ensure they meet your requirements.
In this article:
Install¶
To work with SQL Server Compact Edition 4.0, install the EntityFrameworkCore.SqlServerCompact40 NuGet package.
PM> Install-Package EntityFrameworkCore.SqlServerCompact40
To work with SQL Server Compact Edition 3.5, install the EntityFrameworkCore.SqlServerCompact35.
PM> Install-Package EntityFrameworkCore.SqlServerCompact35
Supported Database Engines¶
- SQL Server Compact Edition 3.5
- SQL Server Compact Edition 4.0
Supported Platforms¶
- Full .NET (4.5.1 onwards)
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
IBM Data Servers¶
This database provider allows Entity Framework Core to be used with IBM Data Servers. Issues, questions, etc. can be posted in the .Net Development with DB2 and IDS forum
Note
This provider is not maintained as part of the Entity Framework Core project. When considering a third party provider, be sure to evaluate quality, licensing, support, etc. to ensure they meet your requirements.
Caution
This provider currently only supports the Entity Framework Core RC1 pre-release.
In this article:
Install¶
Install the EntityFramework.IBMDataServer NuGet package.
PM> Install-Package EntityFramework.IBMDataServer -Pre
Get Started¶
- The following resources will help you get started with this provider.
Supported Database Engines¶
- IBM Data Servers
Supported Platforms¶
- Full .NET (4.5.1 onwards)
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
InMemory (for Testing)¶
This database provider allows Entity Framework Core to be used with an in-memory database. This is useful when testing code that uses Entity Framework Core. The provider is maintained as part of the EntityFramework GitHub project.
In this article:
Install¶
Install the Microsoft.EntityFrameworkCore.InMemory NuGet package.
PM> Install-Package Microsoft.EntityFrameworkCore.InMemory
Get Started¶
- The following resources will help you get started with this provider.
Supported Database Engines¶
- Built-in in-memory database (designed for testing purposes only)
Supported Platforms¶
- Full .NET (4.5.1 onwards)
- .NET Core
- Mono (4.2.0 onwards)
- Universal Windows Platform
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Devart (MySQL, Oracle, PostgreSQL, SQLite, DB2, SQL Server, and more)¶
Devart is a third party provider writer that offers database providers for a wide range of databases. Find out more at devart.com/dotconnect.
Note
This provider is not maintained as part of the Entity Framework Core project. When considering a third party provider, be sure to evaluate quality, licensing, support, etc. to ensure they meet your requirements.
In this article:
Paid Versions Only¶
Devart dotConnect is a commercial third party provider. Entity Framework support is only available in paid versions of dotConnect.
Install¶
See the Devart dotConnect documentation for installation instructions.
Get Started¶
See the Devart dotConnect Entity Framework documentation and blog article about Entity Framework Core 1 Support to get started.
Supported Database Engines¶
- MySQL
- Oracle
- PostgreSQL
- SQLite
- DB2
- SQL Server
- Cloud apps
Supported Platforms¶
- Full .NET (4.5.1 onwards)
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Oracle (Coming Soon)¶
The Oracle .NET team is evaluating EF Core support, but have not announced any timing. You can vote on the Oracle EF Core Provider feature request.
Please direct any questions about this provider, including the release timeline, to the Oracle Community Site.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Miscellaneous¶
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Connection Strings¶
Most database providers require some form of connection string to connect to the database. Sometimes this connection string contains sensitive information that needs to be protected. You may also need to change the connection string as you move your application between environments, such as development, testing, and production.
In this article:
Full .NET Applications¶
Full .NET applications, such as WinForms, WPF, Console, and ASP.NET 4, have a tried and tested connection string pattern. The connection string should be added to your applications App.config file (Web.config if you are using ASP.NET). If your connection string contains sensitive information, such as username and password, you can protect the contents of the configuration file using Protected Configuration.
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="BloggingDatabase"
connectionString="Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" />
</connectionStrings>
</configuration>
|
Note
The providerName
setting is not required on EF Core connection strings stored in App.config because the database provider is configured via code.
You can then read the connection string using the ConfigurationManager
API in your context’s OnConfiguring
method. You may need to add a reference to the System.Configuration
framework assembly to be able to use this API.
1 2 3 4 5 6 7 8 9 10 | public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["BloggingDatabase"].ConnectionString);
}
}
|
Universal Windows Platform (UWP)¶
Connection strings in a UWP application are typically a SQLite connection that just specifies a local filename. They typically do not contain sensitive information, and do not need to be changed as an application is deployed. As such, these connection strings are usually fine to be left in code, as shown below. If you wish to move them out of code then UWP supports the concept of settings, see the App Settings section of the UWP documentation for details.
1 2 3 4 5 6 7 8 9 10 | public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=Blogging.db");
}
}
|
ASP.NET Core¶
In ASP.NET Core the configuration system is very flexible, and the connection string could be stored in appsettings.json
, an environment variable, the user secret store, or another configuration source. See the Configuration section of the ASP.NET Core documentation for more details. The following example shows the connection string stored in appsettings.json
.
1 2 3 4 5 | {
"ConnectionStrings": {
"BloggingDatabase": "Server=(localdb)\\mssqllocaldb;Database=EFGetStarted.ConsoleApp.NewDb;Trusted_Connection=True;"
},
}
|
The context is typically configured in Startup.cs
with the connection string being read from configuration. Note the GetConnectionString()
method simply looks for a configuration value whose key is ConnectionStrings:<connection string name>
.
1 2 3 4 5 | public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BloggingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BloggingDatabase")));
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Logging¶
In this article:
Tip
You can view this article’s sample on GitHub.
Create a logger¶
- The first step is to create an implementation of
ILoggerProvider
andILogger
. ILoggerProvider
is the component that decides when to create instances of your logger(s). The provider may choose to create different loggers in different situations.ILogger
is the component that does the actual logging. It will be passed information from the framework when certain events occur.
Here is a simple implementation that logs a human readable representation of every event to a text file and the Console.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | using Microsoft.Extensions.Logging;
using System;
using System.IO;
namespace EFLogging
{
public class MyLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName)
{
return new MyLogger();
}
public void Dispose()
{ }
private class MyLogger : ILogger
{
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
File.AppendAllText(@"C:\temp\log.txt", formatter(state, exception));
Console.WriteLine(formatter(state, exception));
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
}
}
}
|
Tip
- The arguments passed to the Log method are:
logLevel
is the level (e.g. Warning, Info, Verbose, etc.) of the event being loggedeventId
is a library/assembly specific id that represents the type of event being loggedstate
can be any object that holds state relevant to what is being loggedexception
gives you the exception that occurred if an error is being loggedformatter
uses state and exception to create a human readable string to be logged
Register your logger¶
ASP.NET Core¶
In an ASP.NET Core application, you register your logger in the Configure method of Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddProvider(new MyLoggerProvider());
...
}
Other applications¶
In your application startup code, create and instance of you context and register your logger.
Note
You only need to register the logger with a single context instance. Once you have registered it, it will be used for all other instances of the context in the same AppDomain.
1 2 3 4 5 6 | using (var db = new BloggingContext())
{
var serviceProvider = db.GetInfrastructure<IServiceProvider>();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
loggerFactory.AddProvider(new MyLoggerProvider());
}
|
Filtering what is logged¶
The easiest way to filter what is logged, is to adjust your logger provider to only return your logger for certain categories of events. For EF, the category passed to your logger provider will be the type name of the component that is logging the event.
For example, here is a logger provider that returns the logger only for events related to executing SQL against a relational database. For all other categories of events, a null logger (which does nothing) is returned.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | using Microsoft.Extensions.Logging;
using System;
using System.Linq;
namespace EFLogging
{
public class MyFilteredLoggerProvider : ILoggerProvider
{
private static string[] _categories =
{
typeof(Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory).FullName,
typeof(Microsoft.EntityFrameworkCore.Storage.Internal.SqlServerConnection).FullName
};
public ILogger CreateLogger(string categoryName)
{
if( _categories.Contains(categoryName))
{
return new MyLogger();
}
return new NullLogger();
}
public void Dispose()
{ }
private class MyLogger : ILogger
{
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
Console.WriteLine(formatter(state, exception));
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
}
private class NullLogger : ILogger
{
public bool IsEnabled(LogLevel logLevel)
{
return false;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{ }
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
}
}
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Testing with InMemory¶
This article covers how to use the InMemory provider to write efficient tests with minimal impact to the code being tested.
Caution
Currently you need to use ServiceCollection
and IServiceProvider
to control the scope of the InMemory database, which adds complexity to your tests. In the next release after RC2, there will be improvements to make this easier, see issue #3253 for more details.
In this article:
Tip
You can view this article’s sample on GitHub.
When to use InMemory for testing¶
The InMemory provider is useful when you want to test components using something that approximates connecting to the real database, without the overhead of actual database operations.
For example, consider the following service that allows application code to perform some operations related to blogs. Internally it uses a DbContext
that connects to a SQL Server database. It would be useful to swap this context to connect to an InMemory database so that we can write efficient tests for this service without having to modify the code, or do a lot of work to create a test double of the context.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class BlogService
{
private BloggingContext _context;
public BlogService(BloggingContext context)
{
_context = context;
}
public void Add(string url)
{
var blog = new Blog { Url = url };
_context.Blogs.Add(blog);
_context.SaveChanges();
}
public IEnumerable<Blog> Find(string term)
{
return _context.Blogs
.Where(b => b.Url.Contains(term))
.OrderBy(b => b.Url)
.ToList();
}
}
|
InMemory is not a relational database¶
EF Core database providers do not have to be relational databases. InMemory is designed to be a general purpose database for testing, and is not designed to mimic a relational database.
- Some examples of this include:
- InMemory will allow you to save data that would violate referential integrity constraints in a relational database.
- If you use DefaultValueSql(string) for a property in your model, this is a relational database API and will have no effect when running against InMemory.
Tip
For many test purposes these difference will not matter. However, if you want to test against something that behaves more like a true relational database, then consider using SQLite in-memory mode.
Get your context ready¶
Avoid configuring two database providers¶
In your tests you are going to externally configure the context to use the InMemory provider. If you are configuring a database provider by overriding OnConfiguring
in your context, then you need to add some conditional code to ensure that you only configure the database provider if one has not already been configured.
Note
If you are using ASP.NET Core, then you should not need this code since your database provider is configured outside of the context (in Startup.cs).
1 2 3 4 5 6 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFProviders.InMemory;Trusted_Connection=True;");
}
|
Add a constructor for testing¶
The simplest way to enable testing with the InMemory provider is to modify your context to expose a constructor that accepts a DbContextOptions<TContext>
.
1 2 3 4 5 6 7 8 | public class BloggingContext : DbContext
{
public BloggingContext()
{ }
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
|
Note
DbContextOptions<TContext>
tells the context all of its settings, such as which database to connect to. This is the same object that is built by running the OnConfiguring method in your context.
Writing tests¶
The key to testing with this provider is the ability to tell the context to use the InMemory provider, and control the scope of the in-memory database. Typically you want a clean database for each test method.
DbContextOptions<TContext>
exposes a UseInternalServiceProvider
method that allows us to control the IServiceProvider
the context will use. IServiceProvider
is the container that EF will resolve all its services from (including the InMemory database instance). Typically, EF creates a single IServiceProvider
for all contexts of a given type in an AppDomain - meaning all context instances share the same InMemory database instance. By allowing one to be passed in, you can control the scope of the InMemory database.
Here is an example of a test class that uses the InMemory database. Each test method creates a new DbContextOptions<TContext>
with a new IServiceProvider
, meaning each method has its own InMemory database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | using BusinessLogic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
namespace TestProject
{
[TestClass]
public class BlogServiceTests
{
private static DbContextOptions<BloggingContext> CreateNewContextOptions()
{
// Create a fresh service provider, and therefore a fresh
// InMemory database instance.
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Create a new options instance telling the context to use an
// InMemory database and the new service provider.
var builder = new DbContextOptionsBuilder<BloggingContext>();
builder.UseInMemoryDatabase()
.UseInternalServiceProvider(serviceProvider);
return builder.Options;
}
[TestMethod]
public void Add_writes_to_database()
{
// All contexts that share the same service provider will share the same InMemory database
var options = CreateNewContextOptions();
// Run the test against one instance of the context
using (var context = new BloggingContext(options))
{
var service = new BlogService(context);
service.Add("http://sample.com");
}
// Use a separate instance of the context to verify correct data was saved to database
using (var context = new BloggingContext(options))
{
Assert.AreEqual(1, context.Blogs.Count());
Assert.AreEqual("http://sample.com", context.Blogs.Single().Url);
}
}
[TestMethod]
public void Find_searches_url()
{
// All contexts that share the same service provider will share the same InMemory database
var options = CreateNewContextOptions();
// Insert seed data into the database using one instance of the context
using (var context = new BloggingContext(options))
{
context.Blogs.Add(new Blog { Url = "http://sample.com/cats" });
context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" });
context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" });
context.SaveChanges();
}
// Use a clean instance of the context to run the test
using (var context = new BloggingContext(options))
{
var service = new BlogService(context);
var result = service.Find("cat");
Assert.AreEqual(2, result.Count());
}
}
}
}
|
Sharing a database instance for read-only tests¶
If a test class has read-only tests that share the same seed data, then you can share the InMemory database instance for the whole class (rather than a new one for each method). This means you have a single DbContextOptions<TContext>
and IServiceProvider
for the test class, rather than one for each test method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Extensions.DependencyInjection;
using BusinessLogic;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System;
namespace TestProject
{
[TestClass]
public class BlogServiceTestsReadOnly
{
private DbContextOptions<BloggingContext> _contextOptions;
public BlogServiceTestsReadOnly()
{
// Create a service provider to be shared by all test methods
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Create options telling the context to use an
// InMemory database and the service provider.
var builder = new DbContextOptionsBuilder<BloggingContext>();
builder.UseInMemoryDatabase()
.UseInternalServiceProvider(serviceProvider);
_contextOptions = builder.Options;
// Insert the seed data that is expected by all test methods
using (var context = new BloggingContext(_contextOptions))
{
context.Blogs.Add(new Blog { Url = "http://sample.com/cats" });
context.Blogs.Add(new Blog { Url = "http://sample.com/catfish" });
context.Blogs.Add(new Blog { Url = "http://sample.com/dogs" });
context.SaveChanges();
}
}
[TestMethod]
public void Find_with_empty_term()
{
using (var context = new BloggingContext(_contextOptions))
{
var service = new BlogService(context);
var result = service.Find("");
Assert.AreEqual(3, result.Count());
}
}
[TestMethod]
public void Find_with_unmatched_term()
{
using (var context = new BloggingContext(_contextOptions))
{
var service = new BlogService(context);
var result = service.Find("horse");
Assert.AreEqual(0, result.Count());
}
}
[TestMethod]
public void Find_with_some_matched()
{
using (var context = new BloggingContext(_contextOptions))
{
var service = new BlogService(context);
var result = service.Find("cat");
Assert.AreEqual(2, result.Count());
}
}
}
}
|
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Configuring a DbContext¶
This article shows patterns for configuring a DbContext
with
DbContextOptions
. Options are primarily used to select and configure the
data store.
In this article
Configuring DbContextOptions¶
DbContext
must have an instance of DbContextOptions
in order to execute. This can be
supplied to DbContext
in one of two ways.
If both are used, “OnConfiguring” takes higher priority, which means it can overwrite or change options supplied by the constructor argument.
Constructor argument¶
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
Tip
The base constructor of DbContext also accepts the non-generic version of DbContextOptions
. Using the non-generic version is not recommended for applications with multiple context types.
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Filename=./blog.db");
using (var context = new BloggingContext(optionsBuilder.Options))
{
// do stuff
}
OnConfiguring¶
Caution
OnConfiguring
occurs last and can overwrite options obtained from DI or
the constructor. This approach does not lend itself to testing (unless you
target the full database).
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=./blog.db");
}
}
using (var context = new BloggingContext())
{
// do stuff
}
Using DbContext with dependency injection¶
EF supports using DbContext
with a dependency injection container. Your DbContext type can
be added to the service container by using AddDbContext<TContext>
.
AddDbContext
will add make both your DbContext type, TContext
, and DbContextOptions<TContext>
to the available for injection from the service container.
See more reading below for information on dependency injection.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BloggingContext>(options => options.UseSqlite("Filename=./blog.db"));
}
This requires adding a constructor argument to you DbContext type that accepts DbContextOptions
.
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
:base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
public MyController(BloggingContext context)
using (var context = serviceProvider.GetService<BloggingContext>())
{
// do stuff
}
var options = serviceProvider.GetService<DbContextOptions<BloggingContext>>();
Using IDbContextFactory<TContext>
¶
As an alternative to the options above, you may also provide an implementation of IDbContextFactory<TContext>
.
EF command line tools and dependency injection can use this factory to create an instance of your DbContext. This may be required in order to enable specific design-time experiences such as migrations.
Implement this interface to enable design-time services for context types that do not have a public default constructor. Design-time services will automatically discover implementations of this interface that are in the same assembly as the derived context.
Example:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace MyProject
{
public class BloggingContextFactory : IDbContextFactory<BloggingContext>
{
public BloggingContext Create()
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Filename=./blog.db");
return new BloggingContext(optionsBuilder.Options);
}
}
}
More reading¶
- Read Getting Started on ASP.NET Core for more information on using EF with ASP.NET Core.
- Read Dependency Injection to learn more about using DI.
- Read Testing with InMemory for more information.
- Read Understanding EF Services for more details on how EF uses dependency injection internally.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Upgrading from RC1 to RC2¶
This article provides guidance for moving an application built with the RC1 packages to RC2.
In this article:
Package Names and Versions¶
Between RC1 and RC2, we changed from “Entity Framework 7” to “Entity Framework Core”. You can read more about the reasons for the change in this post by Scott Hanselman. Because of this change, our package names changed from EntityFramework.*
to Microsoft.EntityFrameworkCore.*
and our versions from 7.0.0-rc1-final
to 1.0.0-rc2-final
(or 1.0.0-preview1-final
for tooling).
You will need to completely remove the RC1 packages and then install the RC2 ones. Here is the mapping for some common packages.
RC1 Package | RC2 Equivalent |
EntityFramework.MicrosoftSqlServer 7.0.0-rc1-final | Microsoft.EntityFrameworkCore.SqlServer 1.0.0-rc2-final |
EntityFramework.SQLite 7.0.0-rc1-final | Microsoft.EntityFrameworkCore.SQLite 1.0.0-rc2-final |
EntityFramework7.Npgsql 3.1.0-rc1-3 | NpgSql.EntityFrameworkCore.Postgres <to be advised> |
EntityFramework.SqlServerCompact35 7.0.0-rc1-final | EntityFrameworkCore.SqlServerCompact35 1.0.0-rc2-final |
EntityFramework.SqlServerCompact40 7.0.0-rc1-final | EntityFrameworkCore.SqlServerCompact40 1.0.0-rc2-final |
EntityFramework.InMemory 7.0.0-rc1-final | Microsoft.EntityFrameworkCore.InMemory 1.0.0-rc2-final |
EntityFramework.IBMDataServer 7.0.0-beta1 | Not yet available for RC2 |
EntityFramework.Commands 7.0.0-rc1-final | Microsoft.EntityFrameworkCore.Tools 1.0.0-preview1-final |
EntityFramework.MicrosoftSqlServer.Design 7.0.0-rc1-final | Microsoft.EntityFrameworkCore.SqlServer.Design 1.0.0-rc2-final |
Namespaces¶
Along with package names, namespaces changed from Microsoft.Data.Entity.*
to Microsoft.EntityFrameworkCore.*
. You can handle this change with a find/replace of using Microsoft.Data.Entity
with using Microsoft.EntityFrameworkCore
.
Table Naming Convention Changes¶
A significant functional change we took in RC2 was to use the name of the DbSet<TEntity>
property for a given entity as the table name it maps to, rather than just the class name. You can read more about this change in the related announcement issue.
For existing RC1 applications, we recommend adding the following code to the start of your OnModelCreating
method to keep the RC1 naming strategy:
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
entity.Relational().TableName = entity.DisplayName();
}
If you want to adopt the new naming strategy, we would recommend successfully completing the rest of the upgrade steps and then removing the code and creating a migration to apply the table renames.
AddDbContext / Startup.cs Changes (ASP.NET Core Projects Only)¶
In RC1, you had to add Entity Framework services to the application service provider - in Startup.ConfigureServices(...)
:
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
In RC2, you can remove the calls to AddEntityFramework()
, AddSqlServer()
, etc.:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
You also need to add a constructor, to your derived context, that takes context options and passes them to the base constructor. This is needed because we removed some of the scary magic that snuck them in behind the scenes:
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
Passing in an IServiceProvider¶
If you have RC1 code that passes an IServiceProvider
to the context, this has now moved to DbContextOptions
, rather than being a separate constructor parameter. Use DbContextOptionsBuilder.UseInternalServiceProvider(...)
to set the service provider.
Testing¶
The most common scenario for doing this was to control the scope of an InMemory database when testing. See the updated Testing with InMemory article for an example of doing this with RC2.
Resolving Internal Services from Application Service Provider (ASP.NET Core Projects Only)¶
If you have an ASP.NET Core application and you want EF to resolve internal services from the application service provider, there is an overload of AddDbContext
that allows you to configure this:
services.AddEntityFrameworkSqlServer()
.AddDbContext<ApplicationDbContext>((serviceProvider, options) =>
options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"])
.UseInternalServiceProvider(serviceProvider)); );
Caution
We recommend allowing EF to internally manage its own services, unless you have a reason to combine the internal EF services into your application service provider. The main reason you may want to do this is to use your application service provider to replace services that EF uses internally
DNX Commands => .NET CLI (ASP.NET Core Projects Only)¶
If you previously used the dnx ef
commands for ASP.NET 5 projects, these have now moved to dotnet ef
commands. The same command syntax still applies. You can use dotnet ef --help
for syntax information.
The way commands are registered has changed in RC2, due to DNX being replaced by .NET CLI. Commands are now registered in a tools
section in project.json
:
"tools": {
"Microsoft.EntityFrameworkCore.Tools": {
"version": "1.0.0-preview1-final",
"imports": [
"portable-net45+win8+dnxcore50",
"portable-net45+win8"
]
}
}
Tip
If you use Visual Studio, you can now use Package Manager Console to run EF commands for ASP.NET Core projects (this was not supported in RC1). You still need to register the commands in the tools
section of project.json
to do this.
Package Manager Commands Require PowerShell 5¶
If you use the Entity Framework commands in Package Manager Console in Visual Studio, then you will need to ensure you have PowerShell 5 installed. This is a temporary requirement that will be removed in the next release (see issue #5327 for more details).
Using “imports” in project.json¶
Some of EF Core’s dependencies do not support .NET Standard yet. EF Core in .NET Standard and .NET Core projects may require adding “imports” to project.json as a temporary workaround.
When adding EF, NuGet restore will display this error message:
Package Ix-Async 1.2.5 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Ix-Async 1.2.5 supports:
- net40 (.NETFramework,Version=v4.0)
- net45 (.NETFramework,Version=v4.5)
- portable-net45+win8+wp8 (.NETPortable,Version=v0.0,Profile=Profile78)
Package Remotion.Linq 2.0.2 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Remotion.Linq 2.0.2 supports:
- net35 (.NETFramework,Version=v3.5)
- net40 (.NETFramework,Version=v4.0)
- net45 (.NETFramework,Version=v4.5)
- portable-net45+win8+wp8+wpa81 (.NETPortable,Version=v0.0,Profile=Profile259)
The workaround is to manually import the portable profile “portable-net451+win8”. This forces NuGet to treat this binaries that match this provide as a compatible framework with .NET Standard, even though they are not. Although “portable-net451+win8” is not 100% compatible with .NET Standard, it is compatible enough for the transition from PCL to .NET Standard. Imports can be removed when EF’s dependencies eventually upgrade to .NET Standard.
Multiple frameworks can be added to “imports” in array syntax. Other imports may be necessary if you add additional libraries to your project.
{
"frameworks": {
"netcoreapp1.0": {
"imports": ["dnxcore50", "portable-net451+win8"]
}
}
See Issue #5176.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Upgrading from RC2 to RTM¶
This article provides guidance for moving an application built with the RC2 packages to 1.0.0 RTM.
In this article:
Package Versions¶
The names of the top level packages that you would typically install into an application did not change between RC2 and RTM.
- You need to upgrade the installed packages to the RTM versions:
- Runtime packages (e.g.
Microsoft.EntityFrameworkCore.SqlServer
) changed from1.0.0-rc2-final
to1.0.0
. - The
Microsoft.EntityFrameworkCore.Tools
package changed from1.0.0-preview1-final
to1.0.0-preview2-final
. Note that tooling is still pre-release.
- Runtime packages (e.g.
Existing migrations may need maxLength added¶
In RC2, the column definition in a migration looked like table.Column<string>(nullable: true)
and the length of the column was looked up in some metadata we store in the code behind the migration. In RTM, the length is now included in the scaffolded code table.Column<string>(maxLength: 450, nullable: true)
.
Any existing migrations that were scaffolded prior to using RTM will not have the maxLength
argument specified. This means the maximum length supported by the database will be used (nvarchar(max)
on SQL Server). This may be fine for some columns, but columns that are part of a key, foreign key, or index need to be updated to include a maximum length. By convention, 450 is the maximum length used for keys, foreign keys, and indexed columns. If you have explicitly configured a length in the model, then you should use that length instead.
ASP.NET Identity
This change impacts projects that use ASP.NET Identity and were created from a pre-RTM project template. The project template includes a migration used to create the database. This migration must be edited to specify a maximum length of 256
for the following columns.
- AspNetRoles
- Name
- NormalizedName
- AspNetUsers
- NormalizedEmail
- NormalizedUserName
- UserName
Failure to make this change will result in the following exception when the initial migration is applied to a database.
System.Data.SqlClient.SqlException (0x80131904): Column ‘NormalizedName’ in table ‘AspNetRoles’ is of a type that is invalid for use as a key column in an index.
.NET Core: Remove “imports” in project.json¶
If you were targeting .NET Core with RC2, you needed to add imports
to project.json as a temporary workaround for some of EF Core’s dependencies not supporting .NET Standard. These can now be removed.
{
"frameworks": {
"netcoreapp1.0": {
"imports": ["dnxcore50", "portable-net451+win8"]
}
}
UWP: Add binding redirects¶
Attempting to run EF commands on Universal Windows Platform (UWP) projects results in the following error:
System.IO.FileLoadException: Could not load file or assembly ‘System.IO.FileSystem.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference.
You need to manually add binding redirects to the UWP project. Create a file named App.config
in the project root folder and add redirects to the correct assembly versions.
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem.Primitives"
publicKeyToken="b03f5f7f11d50a3a"
culture="neutral" />
<bindingRedirect oldVersion="4.0.0.0"
newVersion="4.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Overlapped"
publicKeyToken="b03f5f7f11d50a3a"
culture="neutral" />
<bindingRedirect oldVersion="4.0.0.0"
newVersion="4.0.1.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Command Line Reference¶
Entity Framework provides command line tooling to automate common tasks such as code generation and database migrations.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Package Manager Console (Visual Studio)¶
EF command line tools for Visual Studio’s Package Manager Console (PMC) window.
In this article:
Caution
The commands require the latest version of Windows PowerShell
Installation¶
Package Manager Console commands are installed with the Microsoft.EntityFrameworkCore.Tools package.
To open the console, follow these steps.
- Open Visual Studio 2015
- Execute
Install-Package Microsoft.EntityFrameworkCore.Tools -Pre
.NET Core and ASP.NET Core Projects¶
.NET Core and ASP.NET Core projects also require installing .NET Core CLI. See .NET Core CLI for more information about this installation.
Note
.NET Core CLI has known issues in Preview 1. Because PMC commands call .NET Core CLI commands, these known issues also apply to PMC commands. See Preview 2 Known Issues.
Tip
On .NET Core and ASP.NET Core projects, add -Verbose
to any Package Manager Console command to see the equivalent .NET Core CLI command that was invoked.
Usage¶
Note
All commands support the common parameters: -Verbose
, -Debug
,
-ErrorAction
, -ErrorVariable
, -WarningAction
, -WarningVariable
,
-OutBuffer
, -PipelineVariable
, and -OutVariable
. For more information, see
about_CommonParameters.
Add-Migration¶
Adds a new migration.
SYNTAX
Add-Migration [-Name] <String> [-OutputDir <String>] [-Context <String>] [-Project <String>]
[-StartupProject <String>] [-Environment <String>] [<CommonParameters>]
PARAMETERS
-Name <String>
Specifies the name of the migration.
-OutputDir <String>
The directory (and sub-namespace) to use. If omitted, "Migrations" is used. Relative paths are relative to project directory.
-Context <String>
Specifies the DbContext to use. If omitted, the default DbContext is used.
-Project <String>
Specifies the project to use. If omitted, the default project is used.
-StartupProject <String>
Specifies the startup project to use. If omitted, the solution's startup project is used.
-Environment <String>
Specifies the environment to use. If omitted, "Development" is used.
Remove-Migration¶
Removes the last migration.
SYNTAX
Remove-Migration [-Context <String>] [-Project <String>] [-StartupProject <String>] [-Environment <String>]
[-Force] [<CommonParameters>]
PARAMETERS
-Context <String>
Specifies the DbContext to use. If omitted, the default DbContext is used.
-Project <String>
Specifies the project to use. If omitted, the default project is used.
-StartupProject <String>
Specifies the startup project to use. If omitted, the solution's startup project is used.
-Environment <String>
Specifies the environment to use. If omitted, "Development" is used.
-Force [<SwitchParameter>]
Removes the last migration without checking the database. If the last migration has been applied to the database, you will need to manually reverse the changes it made.
Scaffold-DbContext¶
Scaffolds a DbContext and entity type classes for a specified database.
SYNTAX
Scaffold-DbContext [-Connection] <String> [-Provider] <String> [-OutputDir <String>] [-Context <String>]
[-Schemas <String>] [-Tables <String>] [-DataAnnotations] [-Force] [-Project <String>]
[-StartupProject <String>] [-Environment <String>] [<CommonParameters>]
PARAMETERS
-Connection <String>
Specifies the connection string of the database.
-Provider <String>
Specifies the provider to use. For example, Microsoft.EntityFrameworkCore.SqlServer.
-OutputDir <String>
Specifies the directory to use to output the classes. If omitted, the top-level project directory is used.
-Context <String>
Specifies the name of the generated DbContext class.
-Schemas <String>
Specifies the schemas for which to generate classes.
-Tables <String>
Specifies the tables for which to generate classes.
-DataAnnotations [<SwitchParameter>]
Use DataAnnotation attributes to configure the model where possible. If omitted, the output code will use only the fluent API.
-Force [<SwitchParameter>]
Force scaffolding to overwrite existing files. Otherwise, the code will only proceed if no output files would be overwritten.
-Project <String>
Specifies the project to use. If omitted, the default project is used.
-StartupProject <String>
Specifies the startup project to use. If omitted, the solution's startup project is used.
-Environment <String>
Specifies the environment to use. If omitted, "Development" is used.
Script-Migration¶
Generates a SQL script from migrations.
SYNTAX
Script-Migration -From <String> -To <String> [-Idempotent] [-Context <String>] [-Project <String>]
[-StartupProject <String>] [-Environment <String>] [<CommonParameters>]
Script-Migration [-From <String>] [-Idempotent] [-Context <String>] [-Project <String>]
[-StartupProject <String>] [-Environment <String>] [<CommonParameters>]
PARAMETERS
-From <String>
Specifies the starting migration. If omitted, '0' (the initial database) is used.
-To <String>
Specifies the ending migration. If omitted, the last migration is used.
-Idempotent [<SwitchParameter>]
Generates an idempotent script that can be used on a database at any migration.
-Context <String>
Specifies the DbContext to use. If omitted, the default DbContext is used.
-Project <String>
Specifies the project to use. If omitted, the default project is used.
-StartupProject <String>
Specifies the startup project to use. If omitted, the solution's startup project is used.
-Environment <String>
Specifies the environment to use. If omitted, "Development" is used.
Update-Database¶
Updates the database to a specified migration.
SYNTAX
Update-Database [[-Migration] <String>] [-Context <String>] [-Project <String>] [-StartupProject <String>]
[-Environment <String>] [<CommonParameters>]
PARAMETERS
-Migration <String>
Specifies the target migration. If '0', all migrations will be reverted. If omitted, all pending migrations will be applied.
-Context <String>
Specifies the DbContext to use. If omitted, the default DbContext is used.
-Project <String>
Specifies the project to use. If omitted, the default project is used.
-StartupProject <String>
Specifies the startup project to use. If omitted, the solution's startup project is used.
-Environment <String>
Specifies the environment to use. If omitted, "Development" is used.
Use-DbContext¶
Sets the default DbContext to use.
SYNTAX
Use-DbContext [-Context] <String> [-Project <String>] [-StartupProject <String>] [-Environment <String>]
[<CommonParameters>]
PARAMETERS
-Context <String>
Specifies the DbContext to use.
-Project <String>
Specifies the project to use. If omitted, the default project is used.
-StartupProject <String>
Specifies the startup project to use. If omitted, the solution's startup project is used.
-Environment <String>
Specifies the environment to use. If omitted, "Development" is used.
Using EF Core commands and EF 6 commands side-by-side¶
EF Core commands do not work on EF 6 or earlier version of EF. However, EF Core re-uses some of the same command names from these earlier versions. These commands can be installed side-by-side, however, EF does not automatically know which version of the command to use. This is solved by prefixing the command with the module name. The EF 6 commands PowerShell module is named “EntityFramework”, and the EF Core module is named “EntityFrameworkCore”. Without the prefix, PowerShell may call the wrong version of the command.
# Invokes the EF Core command
PS> EntityFrameworkCore\Add-Migration
# Invokes the EF 6 command
PS> EntityFramework\Add-Migration
Common Errors¶
Error: “No parameterless constructor was found”¶
Design-time tools attempt to automatically find how your application creates instances of your DbContext type. If EF cannot find a suitable way to initialize your DbContext, you may encounter this error.
No parameterless constructor was found on 'TContext'. Either add a parameterless constructor to
'TContext' or add an implementation of 'IDbContextFactory<TContext>' in the same assembly as
'TContext'.
As the error message suggests, one solution is to add an implementation of IDbContextFactory<TContext>
to the current project. See Using IDbContextFactory<TContext> for an example of how to create this factory.
See also Preview 2 Known Issues for .NET Core CLI commands.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
.NET Core CLI¶
EF command-line tools for .NET Core Command Line Interface (CLI).
In this article:
Note
Command-line tools for .NET Core CLI has known issues. See Preview 2 Known Issues for more details.
Installation¶
Prerequisites¶
EF command-line tools requires .NET Core CLI Preview 2 or newer. See the .NET Core website for installation instructions.
Supported Frameworks¶
EF supports .NET Core CLI commands on these frameworks:
- .NET Framework 4.5.1 and newer. (“net451”, “net452”, “net46”, etc.)
- .NET Core App 1.0. (“netcoreapp1.0”)
Install by editing project.json¶
EF command-line tools for .NET Core CLI are installed by manually editing project.json
.
- Add
Microsoft.EntityFrameworkCore.Tools
as a “tool” andMicrosoft.EntityFrameworkCore.Design
as a build-only dependency under “dependencies”. See sample project.json below. - Execute
dotnet restore
. If restore does not succeed, the command-line tools may not have installed correctly.
The resulting project.json should include these items (in addition to your other project dependencies).
{
"dependencies": {
"Microsoft.EntityFrameworkCore.Design": {
"type": "build",
"version": "1.0.0-preview2-final"
}
},
"tools": {
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
},
"frameworks": {
"netcoreapp1.0": { }
}
}
Tip
A build-only dependency ("type": "build"
) means this dependency is local to the current project. For example, if Project A has a build only dependency and Project B depends on A, dotnet restore
will not add A’s build-only dependencies into Project B.
Usage¶
Commands can be run from the command line by navigating to the project directory and executing dotnet ef [subcommand]
. To see usage, add --help
to any command to see more information about parameters and subcommands.
dotnet-ef¶
Usage: dotnet ef [options] [command]
Options:
-h|--help Show help information
-p|--project <PROJECT> The project to target (defaults to the project in the current directory). Can be a path to a project.json or a project directory.
-s|--startup-project <PROJECT> The path to the project containing Startup (defaults to the target project). Can be a path to a project.json or a project directory.
-c|--configuration <CONFIGURATION> Configuration under which to load (defaults to Debug)
-f|--framework <FRAMEWORK> Target framework to load from the startup project (defaults to the framework most compatible with .NETCoreApp,Version=v1.0).
-b|--build-base-path <OUTPUT_DIR> Directory in which to find temporary outputs.
-o|--output <OUTPUT_DIR> Directory in which to find outputs
Commands:
database Commands to manage your database
dbcontext Commands to manage your DbContext types
migrations Commands to manage your migrations
dotnet-ef-database¶
Usage: dotnet ef database [options] [command]
Options:
-h|--help Show help information
-v|--verbose Enable verbose output
Commands:
drop Drop the database for specific environment
update Updates the database to a specified migration
dotnet-ef-database-drop¶
Usage: dotnet ef database drop [options]
Options:
-e|--environment <environment> The environment to use. If omitted, "Development" is used.
-c|--context <context> The DbContext to use. If omitted, the default DbContext is used
-f|--force Drop without confirmation
-h|--help Show help information
-v|--verbose Enable verbose output
dotnet-ef-database-update¶
Usage: dotnet ef database update [arguments] [options]
Arguments:
[migration] The target migration. If '0', all migrations will be reverted. If omitted, all pending migrations will be applied
Options:
-c|--context <context> The DbContext to use. If omitted, the default DbContext is used
-e|--environment <environment> The environment to use. If omitted, "Development" is used.
-h|--help Show help information
-v|--verbose Enable verbose output
dotnet-ef-dbcontext¶
Usage: dotnet ef dbcontext [options] [command]
Options:
-h|--help Show help information
-v|--verbose Enable verbose output
Commands:
list List your DbContext types
scaffold Scaffolds a DbContext and entity type classes for a specified database
dotnet-ef-dbcontext-list¶
Usage: dotnet ef dbcontext list [options]
Options:
-e|--environment <environment> The environment to use. If omitted, "Development" is used.
--json Use json output. JSON is wrapped by '//BEGIN' and '//END'
-h|--help Show help information
-v|--verbose Enable verbose output
dotnet-ef-dbcontext-scaffold¶
Usage: dotnet ef dbcontext scaffold [arguments] [options]
Arguments:
[connection] The connection string of the database
[provider] The provider to use. For example, Microsoft.EntityFrameworkCore.SqlServer
Options:
-a|--data-annotations Use DataAnnotation attributes to configure the model where possible. If omitted, the output code will use only the fluent API.
-c|--context <name> Name of the generated DbContext class.
-f|--force Force scaffolding to overwrite existing files. Otherwise, the code will only proceed if no output files would be overwritten.
-o|--output-dir <path> Directory of the project where the classes should be output. If omitted, the top-level project directory is used.
--schema <schema> Selects a schema for which to generate classes.
-t|--table <schema.table> Selects a table for which to generate classes.
-e|--environment <environment> The environment to use. If omitted, "Development" is used.
-h|--help Show help information
-v|--verbose Enable verbose output
dotnet-ef-migrations¶
Usage: dotnet ef migrations [options] [command]
Options:
-h|--help Show help information
-v|--verbose Enable verbose output
Commands:
add Add a new migration
list List the migrations
remove Remove the last migration
script Generate a SQL script from migrations
dotnet-ef-migrations-add¶
Usage: dotnet ef migrations add [arguments] [options]
Arguments:
[name] The name of the migration
Options:
-o|--output-dir <path> The directory (and sub-namespace) to use. If omitted, "Migrations" is used. Relative paths are relative the directory in which the command is executed.
-c|--context <context> The DbContext to use. If omitted, the default DbContext is used
-e|--environment <environment> The environment to use. If omitted, "Development" is used.
--json Use json output. JSON is wrapped by '//BEGIN' and '//END'
-h|--help Show help information
-v|--verbose Enable verbose output
dotnet-ef-migrations-list¶
Usage: dotnet ef migrations list [options]
Options:
-c|--context <context> The DbContext to use. If omitted, the default DbContext is used
-e|--environment <environment> The environment to use. If omitted, "Development" is used.
--json Use json output. JSON is wrapped by '//BEGIN' and '//END'
-h|--help Show help information
-v|--verbose Enable verbose output
dotnet-ef-migrations-remove¶
Usage: dotnet ef migrations remove [options]
Options:
-c|--context <context> The DbContext to use. If omitted, the default DbContext is used
-e|--environment <environment> The environment to use. If omitted, "Development" is used.
-f|--force Removes the last migration without checking the database. If the last migration has been applied to the database, you will need to manually reverse the changes it made.
-h|--help Show help information
-v|--verbose Enable verbose output
dotnet-ef-migrations-script¶
Usage: dotnet ef migrations script [arguments] [options]
Arguments:
[from] The starting migration. If omitted, '0' (the initial database) is used
[to] The ending migration. If omitted, the last migration is used
Options:
-o|--output <file> The file to write the script to instead of stdout
-i|--idempotent Generates an idempotent script that can used on a database at any migration
-c|--context <context> The DbContext to use. If omitted, the default DbContext is used
-e|--environment <environment> The environment to use. If omitted, "Development" is used.
-h|--help Show help information
-v|--verbose Enable verbose output
Common Errors¶
Error: “No parameterless constructor was found”¶
Design-time tools attempt to automatically find how your application creates instances of your DbContext type. If EF cannot find a suitable way to initialize your DbContext, you may encounter this error.
No parameterless constructor was found on 'TContext'. Either add a parameterless constructor to
'TContext' or add an implementation of 'IDbContextFactory<TContext>' in the same assembly as
'TContext'.
As the error message suggests, one solution is to add an implementation of IDbContextFactory<TContext>
to the current project. See Using IDbContextFactory<TContext> for an example of how to create this factory.
Preview 2 Known Issues¶
Targeting class library projects is not supported¶
.NET Core CLI does not support running commands on class libraries as of Preview 2. Despite being able to install EF tools, executing commands may throw this error message.
Could not invoke this command on the startup project '(your project name)'. This preview of Entity Framework tools does not support commands on class library projects in ASP.NET Core and .NET Core applications.
See issue https://github.com/dotnet/cli/issues/2645.
If dotnet run
does not work in the startup project, then dotnet ef
cannot run either.
“dotnet ef” is invoked as an alternate entry point into an application. If the “startup” project is not an application, then it is not currently possible to run the project as an application with the “dotnet ef” alternate entry point.
The “startup” project defaults to the current project, unless specified differently with the
parameter --startup-project
.
Convert the class library project into an “app” project. This can either be a .NET Core app or a desktop .NET app.
Example:
{
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0-*"
}
}
}
}
}
Be sure to register the EntityFramework Tools as a project dependency and in the tools section of your project.json.
Example:
{
"dependencies": {
"Microsoft.EntityFrameworkCore.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
}
},
"tools": {
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
}
}
Finally, specify a startup project that is a “runnable app.”
Example:
dotnet ef --startup-project ../MyConsoleApplication/ migrations list
Convert the class library project into an “app” project. This can either be a .NET Core app or a desktop .NET app.
To make the project a .NET Core App, add the “netcoreapp1.0” framework to project.json along with the other settings in the sample below:
{
"buildOptions": {
"emitEntryPoint": true
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0-*"
}
}
}
}
}
To make a desktop .NET app, ensure you project targets “net451” or newer (example “net461” also works) and ensure the build option "emitEntryPoint"
is set to true.
{
"buildOptions": {
"emitEntryPoint": true
},
"frameworks": {
"net451": { }
}
}
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Internals¶
Caution
These articles are advanced topics. The target audience is provider writers and EF contributors.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Writing a Database Provider¶
In this article
EF Core is designed to be extensible. It provides general purpose building blocks that are intended for use in multiple providers. The purpose of this article is to provide basic guidance on creating a new provider that is compatible with EF Core.
Tip
EF Core source code is open-source. The best source of information is the code itself.
Tip
This article shows snippets from an empty EF provider. You can view the full stubbed-out provider on GitHub.
DbContext Initialization¶
A user’s interaction with EF begins with the DbContext
constructor. Before
the context is available for use, it initializes options and services.
We will example both of these to understand what they represent and how EF
configures itself to use different providers.
Options¶
Microsoft.EntityFrameworkCore.Infrastructure.DbContextOptions
is the API
surface for users to configure DbContext
. Provider writers are
responsible for creating API to configure options and to make services
responsive to these options. For example, most providers require a connection
string. These options are typically created using DbContextOptionsBuilder
.
Services¶
System.IServiceProvider
is the main interface used for interaction with services.
EF makes heavy use of dependency injection (DI). The ServiceProvider
contains a collection of services available for injection. Initialization uses
DbContextOptions
to add additional services if needed and select
a scoped set of services that all EF operations will use during execution.
See also Understanding EF Services.
Note
EF uses Microsoft.Extensions.DependencyInjection to implement dependency injection. Documentation for this project is available on docs.asp.net.
Plugging in a Provider¶
As explained above, EF uses options and services. Each provider must create API so users to add provider-specific options and services. This API is best created by using extension methods.
Tip
When defining an extension method, define it in the namespace of the object being extended so Visual Studio auto-complete will include the extension method as a possible completion.
The Use Method¶
By convention, providers define a UseX()
extension on DbContextOptionsBuilder
.
This configures options which it typically takes as arguments to method.
optionsBuilder.UseMyProvider("Server=contoso.com")
The UseX()
extension method creates a provider-specific implementation of
IDbContextOptionsExtension
which is added to the collection of extensions
stored within DbContextOptions
. This is done by a call to the API
IDbContextOptionsBuilderInfrastructure.AddOrUpdateExtension
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public static class MyProviderDbContextOptionsExtensions
{
public static DbContextOptionsBuilder UseMyProvider(this DbContextOptionsBuilder optionsBuilder,
string connectionString)
{
((IDbContextOptionsBuilderInfrastructure) optionsBuilder).AddOrUpdateExtension(
new MyProviderOptionsExtension
{
ConnectionString = connectionString
});
return optionsBuilder;
}
}
|
Tip
The UseX()
method can also be used to return a special wrapper around
DbContextOptionsBuilder
that allows users to configure multiple options
with chained calls. See SqlServerDbContextOptionsBuilder
as an example.
The Add Method¶
By convention, providers define a AddX()
extension on
EntityFrameworkServicesBuilder
. This configures services and does not
take arguments.
EntityFrameworkServicesBuilder
is a wrapper around ServiceCollection
which is accessible by calling GetInfrastructure()
. The AddX()
method
should register services in this collection to be available for dependency
injection.
In some cases, users may call the Add method directly. This is
done when users are configuring a service provider manually and use this service
provider to resolve an instance of DbContext
. In other cases, the Add method
is called by EF upon service initialization. For more details on service
initialization, see Understanding EF Services.
A provider must register an implementation of IDatabaseProvider
.
Implementing this in-turn requires configuring several more required services.
Read more about working with services in Understanding EF Services.
EF provides many complete or partial implementations of the required services to
make it easier for provider-writers. For example, EF includes a class
DatabaseProvider<TProviderServices, TOptionsExtension>
which can be used in
service registration to hook up a provider.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public static class MyProviderServiceCollectionExtensions
{
public static IServiceCollection AddEntityFrameworkMyProvider(this IServiceCollection services)
{
services.AddEntityFramework();
services.TryAddEnumerable(ServiceDescriptor
.Singleton<IDatabaseProvider, DatabaseProvider<MyDatabaseProviderServices, MyProviderOptionsExtension>>());
services.TryAdd(new ServiceCollection()
// singleton services
.AddSingleton<MyModelSource>()
.AddSingleton<MyValueGeneratorCache>()
// scoped services
.AddScoped<MyDatabaseProviderServices>()
.AddScoped<MyDatabaseCreator>()
.AddScoped<MyDatabase>()
.AddScoped<MyEntityQueryableExpressionVisitorFactory>()
.AddScoped<MyEntityQueryModelVisitorFactory>()
.AddScoped<MyQueryContextFactory>()
.AddScoped<MyTransactionManager>());
return services;
}
}
|
Next Steps¶
With these two extensibility APIs now defined, users can now configure their “DbContext” to use your provider. To make your provider functional, you will need to implement other services.
Reading the source code of other providers is an excellent way to learn how to create a new EF provider. See Database Providers for a list of current EF providers and to find links to their source code (if applicable).
Microsoft.EntityFrameworkCore.Relational
includes an extensive library of services designed for relational providers. In many cases, these services need little or no modification to work for multiple relational databases.
For more information on other internal parts of EF, see Internals.
Caution
This documentation is for EF Core. For EF6.x and earlier release see http://msdn.com/data/ef.
Understanding EF Services¶
In this article
Entity Framework executes as a collection of services working together. A service is a reusable component. A service is typically an implementation of an interface. Services are available to other services via dependency injection (DI), which is implemented in EF using Microsoft.Extensions.DependencyInjection.
This article covers some fundamentals principles for understanding how EF uses services and DI.
Terms¶
- Service
- A reusable component. In .NET, a service can be identified by a class or interface. By convention, Entity Framework only uses interfaces to identify services.
- Service lifetime
- A description of the way in which a service is persisted and disposed across multiple uses of the same service type.
- Service provider
- The mechanism for storing a collection of services. Also known as a service container.
- Service collection
- The mechanism for constructing a service provider.
Categories of Services¶
Services fall into one or more categories.
- Context services
- Services that are related to a specific instance of
DbContext
. They provide functionality for working with the user model and context options. - Provider services
- Provider-specific implementations of services. For example, SQLite uses “provider services” to customize the behavior of SQL generation, migrations, and file I/O.
- Design-time services
- Services used when a developer is creating an application. For example, EF commands uses design-time services to execute migrations and code generation (aka scaffolding).
- User services
- A user can define custom services to interact with EF. These are written in
application code, not provider code. For example, users can provide an
implementation of
IModelCustomizer
for controlling how a model is created.
Note
Service provider is not to be confused with a “provider’s services”.
Service Lifetime¶
EF services can be registered with different lifetime options. The suitable option depends on how the service is used and implemented.
- Transient
- Transient lifetime services are created each time they are injected into other
services. This isolates each instance of the service. For example,
MigrationsScaffolder
should not be reused, therefore it is registered as transient. - Scoped
- Scoped lifetime services are created once per
DbContext
instance. This is used to isolate instance ofDbContext
. For example,StateManager
is added as scoped because it should only track entity states for one context. - Singleton
- Singleton lifetime services exists once per service provider and span all
scopes. Each time the service is injected, the same instance is used. For
example,
IModelCustomizer
is a singleton because it is idempotent, meaning each call toIModelCustomizer.Customize()
does not change the customizer.
How AddDbContext works¶
EF provides an extension method AddDbContext<TContext>()
for
adding using EF into a service collection. This method adds the following
into a service collection:
TContext
as “scoped”DbContextOptions
as a “singleton”DbContextOptionsFactory<T>
as a “singleton”
AddDbContext
does not add any context services, provider services, or design-time services
to the service collection (except for special cases). DbContext constructs its own internal service provider for this.
Special cases¶
AddDbContext
adds DbContextOptionsFactory<T>
to the service collection AddDbContext was called on (which is used to create the “external” service provider). DbContextOptionsFactory<T>
acts as a bridge between the external service provider and DbContext’s internal service provider. If the external provider has services for ILoggerFactory
or IMemoryCache
, these will be added to the internal service provider.
The bridging is done for these common scenarios so users can easily configure logging and memory caching without needing to provide a custom internal service provider.
DbContext’s internal service provider¶
By default, DbContext
uses an internal service provider that is separate from
all other service providers in the application. This internal provider is constructed
from an instance of DbContextOptions
. Methods such as UseSqlServer()
extend
the construction step add specialized services for their database system.
Providing a custom internal service provider¶
DbContextOptionsBuilder
provides an API for giving a custom service provider
to DbContext for EF to use internally. This API is DbContextOptions.UseInternalServiceProvider(IServiceProvider provider)
.
If a custom service provider is provided, DbContext will not use DbContextOptions
to create its own
internal service provider. The custom service provider must already have provider-specific services added.
Database provider writers should provided methods such as AddEntityFrameworkSqlServer” or “AddEntityFrameworkSqlite” to simplify the process of creating a custom service container.
var services = new ServiceCollection()
.AddEntityFrameworkSqlServer()
.AddSingleton<MyCustomService>()
.BuildServiceProvider();
var options = new DbContextOptionsBuilder();
options
.UseInternalServiceProvider(services)
.UseSqlServer(connectionString);
using (var context = new DbContext(options))
{ }
Service provider caching¶
EF caches this internal service provider with IDbContextOptions
as the key.
This means the service provider is only created once per unique set of options.
It is reused when a DbContext is instantiated using a set of
options that have already been used during the application lifetime.
Required Provider Services¶
EF database providers must register a basic set of services. These required services are
defined as properties on IDatabaseProviderServices
. Provider writers may
need to implement some services from scratch. Others have partial or complete
implementations in EF’s library that can be reused.
For more information on required provider services, see Writing a Database Provider.
Additional Information¶
EF uses ` the Microsoft.Extensions.DependencyInjection library <https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/>`_ to implement DI. Documentation for this library is available on docs.asp.net.
“System.IServiceProvider” is defined in the .NET base class library.
Entity Framework (EF) Core is a lightweight and extensible version of the popular Entity Framework data access technology.
EF Core is an object-relational mapper (O/RM) that enables .NET developers to work with a database using .NET objects. It eliminates the need for most of the data-access code that developers usually need to write. EF Core supports many database engines, see Database Providers for details.
If you like to learn by writing code, we’d recommend one of our Getting Started guides to get you started with EF Core.
Get Entity Framework Core¶
Install the NuGet package for the database provider you want to use. See Database Providers for information.
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
The Model¶
With EF Core, data access is performed using a model. A model is made up of entity classes and a derived context that represents a session with the database, allowing you to query and save data. See Creating a Model to learn more.
You can generate a model from an existing database, hand code a model to match your database, or use EF Migrations to create a database from your model (and evolve it as your model changes over time).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace Intro
{
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
|
Querying¶
Instances of your entity classes are retrieved from the database using Language Integrated Query (LINQ). See Querying Data to learn more.
1 2 3 4 5 6 7 | using (var db = new BloggingContext())
{
var blogs = db.Blogs
.Where(b => b.Rating > 3)
.OrderBy(b => b.Url)
.ToList();
}
|
Saving Data¶
Data is created, deleted, and modified in the database using instances of your entity classes. See Saving Data to learn more.
1 2 3 4 5 6 | using (var db = new BloggingContext())
{
var blog = new Blog { Url = "http://sample.com" };
db.Blogs.Add(blog);
db.SaveChanges();
}
|