Entity Framework Core Tutorial: Getting Started
1. Install Entity Framework
Install-Package Microsoft.EntityFrameworkCore.Sqlite
Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
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.
2. Create Your Model
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; }
}
}
3. Use Migrations to Create a Database
Add-Migration MyFirstMigration
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.
Add this in App.xaml
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.
4. Get List of Rows
using (var db = new BloggingContext())
{
Blogs.ItemsSource = db.Blogs.ToList();
}
5. Insert Data
using (var db = new BloggingContext())
{
var blog = new Blog { Url = NewBlogUrl.Text };
db.Blogs.Add(blog);
db.SaveChanges();
Blogs.ItemsSource = db.Blogs.ToList();
}
6. Including & Excluding Types
Include
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>();
}
Exclude
[NotMapped]
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<Blog>();
}
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.
Example
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; }
}
The following code listing shows a one-to-many relationship between Blog
and Post
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)
It is recommended to have a foreign key property defined in the dependent entity class.
More Detail: https://docs.microsoft.com/en-us/ef/core/modeling/relationships
Computed Columns
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.Property(p => p.DisplayName)
.HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
}
Sequences
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; }
}
Loading All Data
using (var context = new BloggingContext())
{
var blogs = context.Blogs.ToList();
}
Loading a Single Entity
using (var context = new BloggingContext())
{
var blog = context.Blogs
.Single(b => b.BlogId == 1);
}
Filtering
using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Where(b => b.Url.Contains("dotnet"))
.ToList();
}
Adding Data
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
using (var db = new BloggingContext())
{
var blog = db.Blogs.First();
blog.Url = "http://sample.com/blog";
db.SaveChanges();
}
Deleting Data
using (var db = new BloggingContext())
{
var blog = db.Blogs.First();
db.Blogs.Remove(blog);
db.SaveChanges();
}
You can combine multiple Add/Update/Remove operations into a single call to SaveChanges
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();
}
Raw SQL Queries
var blogs = context.Blogs
.FromSql("SELECT * FROM dbo.Blogs")
.ToList();
var user = "johndoe";
var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogsForUser {0}", user)
.ToList();
var user = new SqlParameter("user", "johndoe");
var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogsForUser @user", user)
.ToList();
Composing with LINQ
var searchTerm = ".NET";
var blogs = context.Blogs
.FromSql("SELECT * FROM dbo.SearchBlogs {0}", searchTerm)
.Where(b => b.Rating > 3)
.OrderByDescending(b => b.Rating)
.ToList();