MSDN Documentation

Entity Framework Core Basics

This tutorial will guide you through the fundamental concepts of using Entity Framework Core (EF Core) for data access in your .NET applications. We'll cover setting up your project, defining models, configuring the context, and performing basic CRUD (Create, Read, Update, Delete) operations.

Prerequisites

Before you begin, ensure you have the following installed:

  • .NET SDK (latest stable version recommended)
  • An IDE such as Visual Studio or VS Code

1. Setting Up Your Project

First, create a new .NET Core Console Application.

dotnet new console -o EfCoreBasicsApp
cd EfCoreBasicsApp

Next, install the necessary EF Core NuGet packages. For this tutorial, we'll use the SQL Server provider.

dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.Tools

2. Defining Your Model

Let's define a simple model representing a Blog entity.

Create a Model File

Create a new file named Blog.cs in your project and add the following code:

namespace EfCoreBasicsApp
{
    public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }
        public string Title { get; set; }
    }
}

EF Core uses conventions to infer the database schema. Properties named ClassNameId (like BlogId) are treated as primary keys by default.

3. Creating Your DbContext

The DbContext is the main class that interacts with your database. It represents a session with the database and allows you to query and save data.

Create a DbContext File

Create a new file named BlogsContext.cs and add the following code:

using Microsoft.EntityFrameworkCore;

namespace EfCoreBasicsApp
{
    public class BlogsContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }

        public BlogsContext(DbContextOptions<BlogsContext> options) : base(options) { }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Fluent API configurations can go here
            modelBuilder.Entity<Blog>().HasData(
                new Blog { BlogId = 1, Url = "https://example.com/blog1", Title = "My First Blog" },
                new Blog { BlogId = 2, Url = "https://example.com/blog2", Title = "Another Great Post" }
            );
        }
    }
}

In this class, we declare a DbSet<Blog> which represents the collection of Blog entities in the database. The OnModelCreating method is where you can override EF Core's default conventions using the Fluent API or Data Annotations. Here, we've added some initial seed data.

4. Configuring the Connection

You need to tell EF Core how to connect to your database. This is typically done in the Program.cs file (or Startup.cs in older .NET Core versions).

Configure Services in Program.cs

Update your Program.cs file:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

// Application setup
var builder = Host.CreateDefaultBuilder(args).ConfigureServices((hostContext, services) =>
{
    // Replace with your actual connection string
    var connectionString = "Server=(localdb)\\mssqllocaldb;Database=EfCoreBasicsDb;Trusted_Connection=True;MultipleActiveResultSets=true";

    services.AddDbContext<BlogsContext>(options =>
        options.UseSqlServer(connectionString));

    services.AddHostedService<MyBackgroundService>(); // Example of using the context in a service
});

var app = builder.Build();

// Optionally run migrations here or via CLI tools
// You can also run this application to create the database and schema if it doesn't exist.

app.Run();

// Define a simple background service to demonstrate context usage
public class MyBackgroundService : IHostedService
{
    private readonly IServiceProvider _serviceProvider;

    public MyBackgroundService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        using (var scope = _serviceProvider.CreateScope())
        {
            var dbContext = scope.ServiceProvider.GetRequiredService<BlogsContext>();

            // Ensure the database exists (creates it if not)
            await dbContext.Database.EnsureCreatedAsync(cancellationToken);

            // Perform some operations
            await AddBlogAsync(dbContext);
            await ListBlogsAsync(dbContext);
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    private async Task AddBlogAsync(BlogsContext context)
    {
        var newBlog = new Blog { Url = "https://new.example.com/post", Title = "A New Journey" };
        context.Blogs.Add(newBlog);
        await context.SaveChangesAsync();
        Console.WriteLine("Added new blog.");
    }

    private async Task ListBlogsAsync(BlogsContext context)
    {
        Console.WriteLine("\nListing all blogs:");
        var blogs = await context.Blogs.ToListAsync();
        foreach (var blog in blogs)
        {
            Console.WriteLine($"- ID: {blog.BlogId}, Title: {blog.Title}, URL: {blog.Url}");
        }
    }
}
Note: Replace "Server=(localdb)\\mssqllocaldb;Database=EfCoreBasicsDb;Trusted_Connection=True;MultipleActiveResultSets=true" with your actual SQL Server connection string. If you don't have SQL Server installed, you can use SQLite for easier local development by changing .UseSqlServer(connectionString) to .UseSqlite("Data Source=blogs.db") and installing the Microsoft.EntityFrameworkCore.Sqlite package.

EF Core's EnsureCreatedAsync() method can create the database and schema based on your model if it doesn't exist. For production scenarios, it's recommended to use EF Core Migrations.

5. Performing CRUD Operations

Now let's see how to perform common database operations.

Creating a Blog (Create)

The Add() method stages an entity for insertion, and SaveChangesAsync() persists the changes.

// Assuming you have an instance of BlogsContext called 'dbContext'
var newBlog = new Blog { Url = "https://example.com/newblog", Title = "My Newest Blog" };
dbContext.Blogs.Add(newBlog);
await dbContext.SaveChangesAsync();

Reading Blogs (Read)

Use ToListAsync() to retrieve all blogs, or First(), Single(), FirstOrDefault() for specific entities.

// Get all blogs
var allBlogs = await dbContext.Blogs.ToListAsync();

// Get a specific blog by ID
var specificBlog = await dbContext.Blogs.FindAsync(1); // Using FindAsync for primary key lookup
var specificBlogByUrl = await dbContext.Blogs.FirstOrDefaultAsync(b => b.Url == "https://example.com/blog1");

Updating a Blog (Update)

Retrieve the entity, modify its properties, and then call SaveChangesAsync().

// Assuming 'blogToUpdate' is retrieved from the database
var blogToUpdate = await dbContext.Blogs.FindAsync(1);
if (blogToUpdate != null)
{
    blogToUpdate.Title = "Updated Blog Title";
    await dbContext.SaveChangesAsync();
}

Deleting a Blog (Delete)

Use Remove() to stage an entity for deletion.

// Assuming 'blogToDelete' is retrieved from the database
var blogToDelete = await dbContext.Blogs.FindAsync(2);
if (blogToDelete != null)
{
    dbContext.Blogs.Remove(blogToDelete);
    await dbContext.SaveChangesAsync();
}

Conclusion

You've now learned the basics of setting up and using Entity Framework Core for data access in your .NET applications. This includes defining models, configuring the context, and performing fundamental CRUD operations. EF Core offers many more advanced features, such as querying with LINQ, handling relationships, and implementing migrations, which are essential for building robust data-driven applications.

Continue exploring the EF Core Advanced Topics for more in-depth coverage.