# Persisting a Smart Enum with Entity Framework Core

> Replace a plain C# enum with Ardalis.SmartEnum to add behavior and data, then persist it with Entity Framework Core using a value conversion.

- URL: https://blog.nimblepros.com/blogs/persisting-a-smart-enum-with-entity-framework-core/
- Author: [Kyle McMaster](https://blog.nimblepros.com/authors/kyle/)
- Published: 2022-02-10
- Updated: 2026-11-06
- Categories: [Software Development](https://blog.nimblepros.com/categories/software-development/)
- Publisher: [NimblePros](https://blog.nimblepros.com/)

---

A Smart Enum is an enhancement of the C# enum that provides a strongly typed and object oriented approach to enum types.

Smart Enums can be used when a enum needs to be extended to include multiple fields that are tightly coupled or for encapsulating behavior into an enum like class.

As a quick refresher on enums, let's add a simple enum to the domain of the Clean Architecture [template](https://github.com/ardalis/CleanArchitecture) by adding a priority field to the `Project` class. You can learn how to get started with this template in this [blog post](https://ardalis.com/clean-architecture-asp-net-core/). In our example, this `PriorityStatus` enum has two values that represent the Project's priority as BACKLOG or CRITICAL.

```csharp
enum PriorityStatus
{
  BACKLOG,
  CRITICAL
}
```

This works great for simple values but what if we want to display a friendly name like "Backlog" or "Critical" to a presentation layer? Do we want to have mapping code for each response that returns that display name? Do we need to persist application specific display names to the database too? What if there are behaviors that we want to encapsulate to represent the transition from BACKLOG to CRITICAL? This is where Smart Enum can help us accomplish these concerns in a elegant manner.

## Enter Ardalis.SmartEnum

Let's refactor our enum to utilize the Smart Enum base class. First we'll need to add the [Ardalis.SmartEnum](https://github.com/ardalis/SmartEnum) package to the Core project.

```powershell
dotnet add package Ardalis.SmartEnum --version 2.0.1
```

Then, we'll make PriorityStatus a class that inherits from the SmartEnum base class. The base class constructor takes two parameters, one string for the Name and one integer for the Value. In this case, we'll add one additional field to our Smart Enum to show how they can be customized to be more purposeful and expressive.

```csharp
public class PriorityStatus : SmartEnum<PriorityStatus>
{
  public static readonly PriorityStatus BACKLOG = new PriorityStatus(nameof(BACKLOG), "Backlog", 0);
  public static readonly PriorityStatus CRITICAL = new PriorityStatus(nameof(CRITICAL), "Critical", 1);

  public string DisplayName { get; }

  protected PriorityStatus(string name, string displayName, int value) : base(name, value)
  {
    DisplayName = displayName;
  }
}
```

The Project class should now look like this. Note that the Project constructor now takes a parameter for PriorityStatus and this will break the calls to the constructor throughout the Clean Architecture template. This is easily fixed by passing an arbitrary value to the places the constructor is used for now.

```csharp
public class Project : BaseEntity, IAggregateRoot
{
  public string Name { get; private set; }

  private List<ToDoItem> _items = new List<ToDoItem>();
  public IEnumerable<ToDoItem> Items => _items.AsReadOnly();
  public ProjectStatus Status => _items.All(i => i.IsDone) ? ProjectStatus.Complete : ProjectStatus.InProgress;

  public PriorityStatus Priority { get; private set; }

  public Project(string name, PriorityStatus priority)
  {
    Name = Guard.Against.NullOrEmpty(name, nameof(name));
    Priority = priority;
  }

  // other methods left out
}
```

## Persisting values with Entity Framework Core

At this point, Entity Framework Core will complain about not knowing how to construct a PriorityStatus instance as it is not configured as an Entity and there is no parameterless constructor provided. We can see this in action if we run the tests.

```plaintext
System.InvalidOperationException : No suitable constructor was found for entity type 'PriorityStatus'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'name', 'displayName', 'value' in 'PriorityStatus(string name, string displayName, int value)'.
```

 We can fix this by telling Entity Framework Core how to convert the object to and from the database using [value conversions](https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions) introduced into Entity Framework Core in version 2.1. We can define a value conversion in the `Configure` method in `ProjectConfiguration.cs` in the Infrastructure project. Note that in previous versions of Entity Framework Core, a parameterless constructor was required in order to populate the SmartEnum class but as of version 6.x this is no longer a requirement.

```csharp
public class ProjectConfiguration : IEntityTypeConfiguration<Project>
{
  public void Configure(EntityTypeBuilder<Project> builder)
  {
    builder.Property(p => p.Name)
        .HasMaxLength(100)
        .IsRequired();

    builder.Property(p => p.Priority)
        .HasConversion(
            p => p.Value,
            p => PriorityStatus.FromValue(p));
  }
}
```

After adding the conversion expressions, we can run the the tests again to see that they are now passing. The `HasConversion` method tells Entity Framework how to read and write to the database for a given property on our model. The first parameter is for converting the value when persisting to the database. The second parameter is for converting the value when reading from the database. This second parameter makes use of the `FromValue` method provided by the SmartEnum base class which takes an integer and returns an instance of the SmartEnum. It's important to note that these conversion methods are flexible, so if the database was storing the Name string rather than the Value integer of the SmartEnum, use of the `FromName` method would also be possible. You can find a simplified implementation of the Smart Enum used in this example [here](https://github.com/ardalis/CleanArchitecture/blob/main/src/Clean.Architecture.Core/ProjectAggregate/PriorityStatus.cs).

## Additional Resources
- https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions
- https://github.com/ardalis/SmartEnum#persisting-with-ef-core-21-or-higher
- https://codeblog.jonskeet.uk/2006/01/05/classenum/
