Entity Framework Core with Xamarin Forms

The day is soon approaching where we will be able to use Entity Framework, with SQLite, on all platforms, with Xamarin Forms. Currently, EF Core works on Xamarin Forms, but only with UWP and Android, not iOS. Its an odd thing for iOS to be last on the list of support, but a current Mono implementation issue is preventing it from working.

Update on iOS issue: The issue is in the LightCompiler.cs (L1280-L1287) of Mono, where it will throw a NotImplementedException(“Interpreter of ref types”). If you are familiar with Entity Framework, you will know Rowan Miller. He has mentioned in GitHub Issue 7158 it will be fixed in a future version of mono, but currently they have no dates.

For those with only Android or UWP, here is how you implement Entity Framework Core, in Xamarin Forms, with SQLite. This allows you to use Entity Framework code, completely in your PCL, the only platform specific data you need to pass, is the location of the .db file.

Project Setup

If you have a PCL, you must convert it to .NET Standard. Read .NET Standard Library with Xamarin Forms, if you haven’t done this before, however only focus on updating the PCL, the native projects don’t have to be updated to .NET Core.

Note: Do NOT add the SQLite extension in UWP, this is not needed with EF Core and will cause a conflict, if added.

Install Microsoft.EntityFrameworkCore.Sqlite in every project, the traditional and the PCL. It will install all other required dependencies, as appropriate. You are now ready to get coding. I have an example repo, EFXamarin on GitHub if you want to see a completed solution.

Native Project Setup

All you need to do in each platform, is get the path to the SQLite database. This is slightly different in each platform. You will need to pass this value into the PCL, and that approach is up to your existing architecture. For simplicity sake, I will just pass this through the constructor of the App.cs.

// Android
var dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "exrin.db");

// UWP
var dbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "exrin.db");

// iOS
var dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "..", "Library", "exrin.db");


Database Setup

First you want to create the Tables, for your database. All you need to do, is create a class, and if you want a primary key, or other attributes, add them as appropriate.

public class Blog
{
    [Key]
    public int BlogId { get; set; }
    public string Url { get; set; }
    public int Rating { get; set; }

    public override string ToString()
    {
        return Url;
    }
}

Now, create the DbContext.

public class DatabaseContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    private string _databasePath;

    public DatabaseContext(string databasePath)
    {
        _databasePath = databasePath;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite($"Filename={_databasePath}");
    }
}

Adding and Retrieving Data

Next, all we need to do is EnsureCreated is called, to initialize the database, then add and retrieve data, just as you normally would with Entity Framework.

public App(string dbPath)
{
    List<Blog> itemSource;

    // Create Database & Tables
    using (var db = new DatabaseContext(dbPath))
    {
        // Ensure database is created
        db.Database.EnsureCreated();

        // Insert Data
        db.Add(new Blog() { BlogId = 1, Rating = 5, Url = "https://exrin.net" });
        db.Add(new Blog() { BlogId = 2, Rating = 5, Url = "https://xamarinhelp.com" });
        db.Add(new Blog() { BlogId = 3, Rating = 5, Url = "https://azuremobilehelp.com" });
        db.SaveChanges();

        // Retreive Data
        itemSource = db.Blogs.ToList();
    }

    // Show Data
    MainPage = new ContentPage()
    {
        Content = new ListView()
        {
            ItemsSource = itemSource
        }
    };
}

And then if you run the project on Android or UWP will you see.

androidentityframework uwpentityframework

If you run it on iOS, you will get the following error:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NotImplementedException: Interpreter of ref types
 at Microsoft.Scripting.Interpreter.LightCompiler.CompileMethodCallExpression (System.Linq.Expressions.Expression expr) [0x00089] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.4.0.114/src/mono/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightCompiler.cs:1283 
 at Microsoft.Scripting.Interpreter.LightCompiler.CompileNoLabelPush (System.Linq.Expressions.Expression expr) [0x001ba] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.4.0.114/src/mono/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightCompiler.cs:1642 
 at Microsoft.Scripting.Interpreter.LightCompiler.Compile (System.Linq.Expressions.Expression expr) [0x00008] in /Library/Fra
meworks/Xamarin.iOS.framework/Versions/10.4.0.114/src/mono/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightCompiler.cs:1729 

etc...

As mentioned, this has been noted and will be fixed in a future mono update.

Microsoft MVP | Xamarin MVP | Xamarin Certified Developer |
Exrin MVVM Framework | Xamarin Forms Developer | Melbourne, Australia

21 Comments

  1. Christoph Nienaber

    Cool stuff!
    Would love to see an update on this topic when iOS is supported. People with MVC background are familiar with EF and will feel right at home, when it just works.

    Can you do a comparison to using SQLite (only)? Do you think you will use EF Core only when the support is there?

    Greetings

    1. Adam Pedley

      When using SQLite, you would normally use the sqlite-net-pcl nuget package to communicate with a SQLite db. However, yes, when EFCore supports iOS, I will most likely move to EF Core only.

      Would much prefer a Microsoft open-source supported framework. I used EF lots with web development, and it would be great for people coming from that background, as you mentioned.

  2. Plamen Yovchev

    Hi Adam,

    Is it possible and so easy to work with database first approach. I have existing sqlite db which I want to use and not to write my own classes and to create the tables again. Is it possible to load the tables like in asp.net mvc like entities ?

    1. Adam Pedley

      If the database and table already exists, it won’t overwrite it. Thats what the EnsureCreated does. The only difference is you will have to have your db in your app, and ensure its outputted to the mobile device in the correct location when they first run the app.

      1. Plamen Yovchev

        So, I have to write classes for the existing tables and use the EnsureCreated method and etc. to be able to use them like “newly created entities”, correct ?

        P.S. sorry for the duplicaton.

        1. Adam Pedley

          Yes, just use it as you normally would with Code First. You could technically remove EnsureCreated I think because it will already be there, but it leaves the creation of the db entirely up to you. I have tried leaving out the EnsureCreated before, so give it a test first, it might also do other things in the background I am not aware of.

    1. Adam Pedley

      Unfortunately, I know nothing further than what is publicly stated. I would be looking out for Xamarin Cycle 10 with Mono 5.0 which will include the CoreFX upgrade, this may resolve it but its just speculation, it could require a completely separate fix.

  3. TimK

    Thanks for the excellent post, Adam. In our Xamarin.Forms PCL project, we are using SQLite local storage and connecting to a PostgreSQL external database from which to pull data into local storage. What would your advice be in terms of navigating the flow from the external database to the local one? At this point it seems best to use sqlite-net-pcl for the local db. Would you use a different Nuget package to connect on the PostgreSQL side and then translate the data to be sqlite-net-pcl compatible so as to store it locally?

    1. Adam Pedley

      There would be nothing avail that does this automatically. If you are connecting directly to the PostgreSQL over the internet, I would suggest you instead build an API to service the requests, you shouldn’t directly expose your DB to mobile clients.

      From here you would have to develop your own Syncing process. You might want to look at Azure Mobile Client, which includes syncing, but I am not about its capability to connect it up to an existing external source.

  4. Pete Suffolk

    Hi Adam,

    Having used code first for years I am keen to continue the methodology with Xamarin Forms for Android.

    I have downloaded your exampl and it works great.

    I have used your example to try to work out how to use EF in a XAML based application but I have failed, miserably!

    Have you an example on Entit Framework with a Xaml based application? I only need Android if it helps.

    1. Adam Pedley

      XAML and EF are completely separate. EF just gets the data and then you pass it to properties in your ViewModel to be bound to the XAML elements, such as a ListView. If you need an example of a project using XAML, you can have a look at my example with MVVMLight (https://github.com/adamped/xarch-starter)

      If you are having a specific problem, let me know.

      1. Pete Suffolk

        Hi Adam,

        Thank you for your reply.

        I have downloaded your MVVMLight example however, I cannot see any references to Entity Framework in it. Furthermore I couldn’t get it to build as there are a couple of dll’s missing: APiRepositorry and DataService.

        I am still interested in a simple XAML based Entity Framework example though.

        1. Adam Pedley

          Hi Pete

          I don’t have any examples of EF with XAML. They are two different parts of the system. You can just create an app using XAML and then connect up a datastore with EF. It would be best to have a XAML based app, then copy and paste over the relevant code from the EF sample to get what you want.

          1. Pete Suffolk

            I have tried to rework your example using XAML I just get odd errors from db.Database.EnsureCreated();

            Value cannot be null. Parameter name: path1

            And public DbSet Blogs { get; set; } appears to fail too.

            1. Adam Pedley

              If you are getting an error with the Path, it means that the dbPath string isn’t getting passed through to the DataContext is null. Check that you are getting a value from the native platform when its passed through.

              1. Pete Suffolk

                I changed the code for Onconfiguring to:

                protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
                {
                var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = “test.db” };
                var connectionString = connectionStringBuilder.ToString();
                var connection = new SqliteConnection(connectionString);

                optionsBuilder.UseSqlite(connection);
                }
                And I still get the same error.

                Also the DbSet issue may be due to threading.

                1. Adam Pedley

                  You need to specify the path as well as the file name. If you look further up in the post, you will see there is code to retrieve the database path for each platform.

                  1. Pete Suffolk

                    That worked perfectly, thank you

                    I need to ask you lots more questions just to see how narrow these comment boxes get.