Getting Started with EF Core on Universal Windows Platform (UWP) with a New Database

In this tutorial, you build a Universal Windows Platform (UWP) application that performs basic data access against a local SQLite database using Entity Framework Core.

View this article's sample on GitHub.

Prerequisites

Create a model project

Important

Due to limitations in the way .NET Core tools interact with UWP projects the model needs to be placed in a non-UWP project to be able to run migrations commands in the Package Manager Console (PMC)

  • Open Visual Studio

  • File > New > Project

  • From the left menu select Installed > Visual C# > .NET Standard.

  • Select the Class Library (.NET Standard) template.

  • Name the project Blogging.Model.

  • Name the solution Blogging.

  • Click OK.

Install Entity Framework Core

To use EF Core, install the package for the database provider(s) you want to target. This tutorial uses SQLite. For a list of available providers see Database Providers.

  • Tools > NuGet Package Manager > Package Manager Console.

  • Run Install-Package Microsoft.EntityFrameworkCore.Sqlite

Later in this tutorial you will be using some Entity Framework Core tools to maintain the database. So install the tools package as well.

  • Run Install-Package Microsoft.EntityFrameworkCore.Tools

Create the model

Now it's time to define a context and entity classes that make up the model.

  • Delete Class1.cs.

  • Create Model.cs with the following code:

    using Microsoft.EntityFrameworkCore;
    using System.Collections.Generic;
    
    namespace Blogging.Model
    {
        public class BloggingContext : DbContext
        {
            public DbSet<Blog> Blogs { get; set; }
            public DbSet<Post> Posts { get; set; }
    
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                optionsBuilder.UseSqlite("Data Source=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; }
        }
    }
    

Create a new UWP project

  • In Solution Explorer, right-click the solution, and then choose Add > New Project.

  • From the left menu select Installed > Visual C# > Windows Universal.

  • Select the Blank App (Universal Windows) project template.

  • Name the project Blogging.UWP, and click OK

  • Set the target and minimum versions to at least Windows 10 Fall Creators Update (10.0; build 16299.0).

Create the initial migration

Now that you have a model, set up the app to create a database the first time it runs. In this section, you create the initial migration. In the following section, you add code that applies this migration when the app starts.

Migrations tools require a non-UWP startup project, so create that first.

  • In Solution Explorer, right-click the solution, and then choose Add > New Project.

  • From the left menu select Installed > Visual C# > .NET Core.

  • Select the Console App (.NET Core) project template.

  • Name the project Blogging.Migrations.Startup, and click OK.

  • Add a project reference from the Blogging.Migrations.Startup project to the Blogging.Model project.

Now you can create your initial migration.

  • Tools > NuGet Package Manager > Package Manager Console

  • Select the Blogging.Model project as the Default project.

  • In Solution Explorer, set the Blogging.Migrations.Startup project as the startup project.

  • Run Add-Migration InitialCreate.

    This command scaffolds a migration that creates the initial set of tables for your model.

Create the database on app startup

Since you want the database to be created on the device that the app runs on, add 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.

  • Add a project reference from the Blogging.UWP project to the Blogging.Model project.

  • Open App.xaml.cs.

  • Add the highlighted code to apply any pending migrations.

    using Blogging.Model;
    using Microsoft.EntityFrameworkCore;
    using System;
    using Windows.ApplicationModel;
    using Windows.ApplicationModel.Activation;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace Blogging.UWP
    {
        /// <summary>
        /// Provides application-specific behavior to supplement the default Application class.
        /// </summary>
        sealed partial class App : Application
        {
            /// <summary>
            /// Initializes the singleton application object.  This is the first line of authored code
            /// executed, and as such is the logical equivalent of main() or WinMain().
            /// </summary>
            public App()
            {
                this.InitializeComponent();
                this.Suspending += OnSuspending;
    
                using (var db = new BloggingContext())
                {
                    db.Database.Migrate();
                }
            }
    
            /// <summary>
            /// Invoked when the application is launched normally by the end user.  Other entry points
            /// will be used such as when the application is launched to open a specific file.
            /// </summary>
            /// <param name="e">Details about the launch request and process.</param>
            protected override void OnLaunched(LaunchActivatedEventArgs e)
            {
                Frame rootFrame = Window.Current.Content as Frame;
    
                // Do not repeat app initialization when the Window already has content,
                // just ensure that the window is active
                if (rootFrame == null)
                {
                    // Create a Frame to act as the navigation context and navigate to the first page
                    rootFrame = new Frame();
    
                    rootFrame.NavigationFailed += OnNavigationFailed;
    
                    if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                    {
                        //TODO: Load state from previously suspended application
                    }
    
                    // Place the frame in the current Window
                    Window.Current.Content = rootFrame;
                }
    
                if (e.PrelaunchActivated == false)
                {
                    if (rootFrame.Content == null)
                    {
                        // When the navigation stack isn't restored navigate to the first page,
                        // configuring the new page by passing required information as a navigation
                        // parameter
                        rootFrame.Navigate(typeof(MainPage), e.Arguments);
                    }
                    // Ensure the current window is active
                    Window.Current.Activate();
                }
            }
    
            /// <summary>
            /// Invoked when Navigation to a certain page fails
            /// </summary>
            /// <param name="sender">The Frame which failed navigation</param>
            /// <param name="e">Details about the navigation failure</param>
            void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
            {
                throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
            }
    
            /// <summary>
            /// Invoked when application execution is being suspended.  Application state is saved
            /// without knowing whether the application will be terminated or resumed with the contents
            /// of memory still intact.
            /// </summary>
            /// <param name="sender">The source of the suspend request.</param>
            /// <param name="e">Details about the suspend request.</param>
            private void OnSuspending(object sender, SuspendingEventArgs e)
            {
                var deferral = e.SuspendingOperation.GetDeferral();
                //TODO: Save application state and stop any background activity
                deferral.Complete();
            }
        }
    }
    

Tip

If you change your model, 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 the model

You can now use the model to perform data access.

  • Open MainPage.xaml.

  • Add the page load handler and UI content highlighted below

<Page
    x:Class="Blogging.UWP.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Blogging.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 add code to wire up the UI with the database

  • Open MainPage.xaml.cs.

  • Add the highlighted code from the following listing:

using Blogging.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace Blogging.UWP
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    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.

  • In Solution Explorer, right-click the Blogging.UWP project and then select Deploy.

  • Set Blogging.UWP as the startup project.

  • Debug > Start Without Debugging

    The app builds and runs.

  • Enter a URL and click the Add button

    image

    image

    Tada! You now have a simple UWP app running Entity Framework Core.

Next steps

For compatibility and performance information that you should know when using EF Core with UWP, see .NET implementations supported by EF Core.

Check out other articles in this documentation to learn more about Entity Framework Core features.