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: