Saving Enums with Entity Framework Core

Full source code here.

A few years ago I wrote a post about saving enums to the database with Entity Framework. It was able to save the enum as a string to the database and when reading from the database it was able to take that string and populate the enum correctly. It worked fine but felt a bit hacky.

With Entity Framework Core there is a neater and nicer way to do this using value conversions.

Let’s say we have an Address with two enums – AddressType and DeliveryPreference.

public partial class Address
{
    public int AddressId { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public AddressType AddressType { get; set; }
    public DeliveryPreference DeliveryPreference { get; set; }
}

We can save the enums to the database as either strings or ints, and when reading them back populate the enum! Here’s how to do both.

The table
My table looks like this

As you can see, the AddressType is stored as an int and the DeliveryPreference is stored as a string.

When you run the application it should create the database and table for you, but in case you don’t have your permissions setup correctly, here’s the script to create it.

CREATE TABLE [dbo].[Address] (
    [AddressId]          INT            IDENTITY (1, 1) NOT NULL,
    [Line1]              VARCHAR (50)   NOT NULL,
    [Line2]              VARCHAR (50)   NOT NULL,
    [AddressType]        INT            NOT NULL,
    [DeliveryPreference] VARCHAR (50) NOT NULL,
    CONSTRAINT [PK_Address] PRIMARY KEY CLUSTERED ([AddressId] ASC)
);

Saving an enum as an string
Firstly lets look at saving the DeliveryPreference enum as an string.

In the context we build the entity, I have the usual things you would expect for AddressId, Line1 and Line2. But DeliveryPreference is a little different.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Address>(entity =>
    {
        entity.Property(e => e.AddressId).ValueGeneratedOnAdd();

        entity.Property(e => e.Line1)
            .IsRequired()
            .HasMaxLength(50)
            .IsUnicode(false);

        entity.Property(e => e.Line2)
            .IsRequired()
            .HasMaxLength(50)
            .IsUnicode(false);

        entity.Property(e => e.DeliveryPreference) 
            .HasMaxLength(50)
            .HasConversion(x => x.ToString(), // to converter
                x => (DeliveryPreference) Enum.Parse(typeof(DeliveryPreference), x));// from converter

	    //snip..

The DeliveryPreference uses the HasConversion method, passing it two parameters.
The first parameter is the convert to provider expression which as the name suggests converts the value in our object to the type you will store in the database.

And the second is the convert from provider expression, it converts the the type in database to the type in your class.

In this example, I cast the enum to an string to store in the database, and when retrieving from the database I cast the stored string to an DeliveryPreference enum.

Saving an enum as an int
For the second enum, AddressType I don’t explicitly need to convert it from an enum to an int, Entity Framework will do this automatically (as pointed out to me in this tweet). But I’m including it as an example in case you need something like this for some other explicit conversion.

In this example, I cast the enum to an int to store in the database, and when retrieving from the database I cast the stored int to an AddressType enum.

// this is a continuation of the OnModelCreating method
        entity.Property(e => e.AddressType)
            .HasConversion(x => (int) x, x => (AddressType) x);

Full source code here.

Saving enums as strings with Entity Framework

In September 2018 I wrote a new post explaining how to store enums as ints or strings with Entity Framework Core. It is a nicer solution than the one presented here.

Full source code here.

I hit a problem where I wanted to use Entity Framework to save the text value of an enum to the database rather than its numeric value. This is not possible with Entity Framework at the moment; there are a few hacky solutions out there. I add my own hacky solution here.

I have a Person class with an ID, name and gender; the gender is an enum with just male and female. I’d like to save “Male” or “Female” to the database instead of 1 or 2.

The enum is simple.

    public enum Gender
    {
        Male = 1,
        Female = 2
    }

The Person class makes use of Data Annotations to perform the correct mappings to the table. The Gender property is not mapped to the database while the GenderString is mapped as the column named Gender.

    public class Person 
    {
        public int PersonID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        [Column("Gender")]
        public string GenderString
        {
            get { return Gender.ToString(); }
            private set { Gender = value.ParseEnum<Gender>(); }
        }

        [NotMapped]
        public Gender Gender { get; set; }
    }

I use an extension method to parse the text value of gender back into the enum.

    public static class StringExtensions
    {
        public static T ParseEnum<T>(this string value)
        {
            return (T)Enum.Parse(typeof(T), value, true);
        }
    }

Rows in the table will now have the string value of the enum rather than that number.

PersonIDFirstNameLastNameGender
1JamesSmithMale
2JaneSmithFemale

And when a person is loaded from the database the Gender enum is correctly populated.

The only drawback is that there is now a public property called Gender and GenderString on the Person class, but I have made the set of GenderString private to prevent accidental updating.

Full source code here.