Persist a list of integers with Entity Framework Core » 25 June 2023

I had to persist a list (or array) of integers in a database table using Entity Framework Core. I was surprised to find that EF Core does not support this out of the box. I found a few solutions online, but they all seemed to be overly complicated, here’s a quick summary of what I’ve found.

The original problem is that in EF Core I didn’t find a trivial way to map a list of integers to a single column in a database table. Most of the solutions I found online were using a custom type mapper, which is a bit of an overkill for such a simple problem. Considering these are actual primitive types, and not foreign keys for an entity type, I also didn’t want to create a separate table for them.

My favorite solution was to create a custom converter and comparer for the List<int> type that de-/serializes the list of numbers to JSON. This is a very simple solution, and it works with EF Core 6.0.

Now the caveat here is that while we save some complexity by not using a separate table, it also makes it harder to do any kind of queries against the numbers – in our situation it’s not a big deal as these are arbitrary numbers, but you may want to be mindful of this.

The converter class

First, I’ve created a static class for these utils to not pollute the original DbContext.

public static class MyDbUtils
{
  public static readonly ValueConverter intListConverter = new ValueConverter<List<int>, string>(
    i => JsonSerializer.Serialize(i, JsonSerializerOptions.Default),
    s => JsonSerializer.Deserialize<List<int>>(s, JsonSerializerOptions.Default)!);

  public static readonly ValueComparer intListComparer = new ValueComparer<List<int>>(
    (c1, c2) => c1!.SequenceEqual(c2!),
    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
    c => c.ToList());
}

DbContext

Now to the DbContext. You have to add the converter and comparer to the OnModelCreating method:

modelBuilder.Entity<MyEntity>().Property(d => d.Numbers)
  .HasConversion(MyDbUtils.intListConverter, MyDbUtils.intListComparer);

That’s it. Now your list of integers will be persisted as single column in the database table:

Screenshot of the database table