Jon Douglas The rantings of a developer

Xamarin.Android - Entity Framework

Preface

Entity Framework has been one of my favorite projects for quite some time. If you didn’t know, Entity Framework split off from the 6.X version to a new re-written 7.X (Core) version, in which the goal is to keep the ORM lightweight and very extensible.

Now the challenge for me has always been:

I want to use Entity Framework in my Xamarin projects.

This hasn’t really been possible for the last 3 years. In fact, I’ve attempted it a few years back and gave up because the tooling was simply just not there. However this is my personal redemption at getting this to work.

Tools

Let’s talk about the tooling needed to make this possible. Consider this more of a high level approach:

  • SQLite Provider- We will need a place to store our data. Seeing that SQLite is a perfect fit for mobile, we will use Entity Framework’s SQLite package:

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite/

  • Entity Framework Core - We will need an ORM to manage our CRUD operations and database migrations:

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/

Great! Now we’re off to the races.

Getting Started

Creating the NetStandard library

The first thing we’ll do is create a netstandard library. To do this, create a PCL project:

Since this is not a netstandard library quite yet, let’s go ahead and convert that by going to the project’s Properties

Once we have that set, we want to ensure we have the minimum requirements for the two NuGet packages we linked above:

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite/

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/

By the looks of things, the dependency is netstandard 1.3. So let’s make sure our netstandard project is targeting that version:

Creating the Xamarin.Android project

Nothing too special here, we’re just going to create a File -> New Single-View App (Android) Project:

Adding the NuGet packages

This step is typically easiest to do on the project level rather than the solution level as NuGet is sometimes not that friendly with different project structures(.csproj vs project.json)

Adding the NuGet packages to the netstandard library

Adding the NuGet packages to the Xamarin.Android project

Defining the DbContext

If you’ve used Entity Framework before, you will be very familiar with how we define a DbContext and our underlying Models that define our database schema.

Let’s start with a simple data model that we will call Cat.cs:

    public class Cat
    {
        [Key]
        public int CatId { get; set; }
        public string Name { get; set; }
        public int MeowsPerSecond { get; set; }
    }

Let’s now make sure that this is apart of our DbContext by defining a new context we’ll call CatContext.cs. You may notice that we have a string DatabasePath. We will use this later when we need to tell Entity Framework where to store our Database on disk:

    public class CatContext : DbContext
    {
        public DbSet<Cat> Cats { get; set; }

        private string DatabasePath { get; set; }

        public CatContext()
        {

        }

        public CatContext(string databasePath)
        {
            DatabasePath = databasePath;
        }

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

Implementing the Context

First, we need to make sure our Xamarin.Android project is referencing our netstandard library.

Now that we have that, let’s implement our MainActivity.cs with some Entity Framework code!

[Activity(Label = "EntityFrameworkWithXamarin.Droid", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        int count = 1;

        protected async override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            Button button = FindViewById<Button>(Resource.Id.MyButton);

            button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };

            TextView textView = FindViewById<TextView>(Resource.Id.TextView1);

            var dbFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
            var fileName = "Cats.db";
            var dbFullPath = Path.Combine(dbFolder, fileName);
            try
            {
                using (var db = new CatContext(dbFullPath))
                {
                    await db.Database.MigrateAsync(); //We need to ensure the latest Migration was added. This is different than EnsureDatabaseCreated.

                    Cat catGary = new Cat() { CatId = 1, Name = "Gary", MeowsPerSecond = 5 };
                    Cat catJack = new Cat() { CatId = 2, Name = "Jack", MeowsPerSecond = 11 };
                    Cat catLuna = new Cat() { CatId = 3, Name = "Luna", MeowsPerSecond = 3 };

                    List<Cat> catsInTheHat = new List<Cat>() { catGary, catJack, catLuna };

                    if(await db.Cats.CountAsync() < 3)
                    {
                        await db.Cats.AddRangeAsync(catsInTheHat);
                        await db.SaveChangesAsync();
                    }

                    var catsInTheBag = await db.Cats.ToListAsync();

                    foreach(var cat in catsInTheBag)
                    {
                        textView.Text += $"{cat.CatId} - {cat.Name} - {cat.MeowsPerSecond}" + System.Environment.NewLine;
                    }
                }

            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
            }
        }
    }

Let’s try to run this code.

Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: Cats'.

It looks like we’re missing a core Entity Framework feature, and that’s Migrations to create our database schema.

Well shucks…this is awkward. We don’t have a great way to generate Entity Framework Migrations from within a Xamarin.Android project or the netstandard library. Let’s work with a quick workaround by creating a new netcore Console Application so we can generate Migrations.

We need to add the Entity Framework Tools, Entity Framework Core Design, and Entity Framework Core to this project so we can use the command line to generate our Migrations.

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tools.DotNet

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Design/

We now need to move over our Cat.cs and CatContext.cs to ensure there’s a DbContext it can generate Migrations for. Your Console App should now look like this:

Now we can generate a schema for our context. Let’s use the new dotnet tooling to do this. Open up a new console in our current Console App directory:

Now we need to generate an initial Migration.

dotnet ef migrations add Initial

This should generate a migration:

Now we need to take the initial migrations generated in the Migrations folder of our project and simply move them over to our netstandard library.

Note: You can simply change the namespaces of these two generated files to the name of your netstandard namespace.

Let’s try running the Xamarin.Android project again and see if we run into any other exceptions

It looks like it worked! Our simple attempt at adding Cat models and retrieving them works!

If we wanted to take a closer look at the SQLite file that gets generated, use an emulator and open up ADM(Android Device Monitor):

Taking a closer look into the data/data/files folder, we will see our Cats.db that we created.

You can now take that file and open it in any SQLite explorer.

Note: I personally use DB Browser for SQLite (http://sqlitebrowser.org/)

Conclusion

Source Code: https://github.com/JonDouglas/EntityFrameworkWithXamarin

It’s been a three year battle with you Entity Framework. However I have to give my thanks to everyone involved in getting Entity Framework to the state it currently is. It’s been so much fun seeing how these projects turn out after a long period of development.