EF Core: IEnumerable to separated list of string

The problem

In my database I have a column where I store comma separated strings representing a combination of options/features I need to use on the website. It would be nice to be able to access the comma separated items as an IEnumerable so I can use it to – for instance – populate a dropdown list.

Some thoughts

Of course, I could use entity framework core to get the string value from the database, and then split that string into a list, and use that in my page model. However then I don’t know how many times I would need to do that in the future, when I might be building more and more functionality based on this same column. Also, I cannot think of a situation where my or my colleagues would want to access this list as a “real” string instead of as a list of the items contained in that string. So it would be nice if there was a way to do this conversion as close to the data as possible so we have this logic in one place and can reuse it.

Enter EF Core Value Conversions

Luckily, Entity Framework Core had a feature I could use by adding one of the following code blocks to my entity’s configuration:

In line with entity configuration:

entity.Property(x => x.OptionMainGroups)
                .HasMaxLength(1500)
                .HasConversion(
                    convertToProviderExpression: x => string.Join(',', x),
                    convertFromProviderExpression: x => x.Split(',', System.StringSplitOptions.TrimEntries))
                .IsUnicode(false);

As a separate converter

var converter = new ValueConverter<ICollection<string>, string>(
                                                        convertToProviderExpression: x => string.Join(',', x),
                                                        convertFromProviderExpression: x => x.Split(',', System.StringSplitOptions.TrimEntries)
                                                        );

            entity.ToTable("DossierType");

            entity.HasKey(x => x.Id);

            entity.Property(x => x.Name)
                 .IsRequired()
                 .HasMaxLength(50)
                 .IsUnicode(false);

            entity.Property(x => x.Description)
                .HasMaxLength(255)
                .IsUnicode(false);

            entity.Property(x => x.OptionMainGroups)
                .HasMaxLength(1500)
                .HasConversion(converter)
                .IsUnicode(false);

            entity.Property(x => x.OptionGroups)
                .HasMaxLength(1500)
                .HasConversion(converter)
                .IsUnicode(false);

As a conversion class (I did not test this but maybe I will next week when I’m back on the job)

public class StringToCollectionConverter: ValueConverter<ICollection<string>, string>
{
    public CurrencyConverter()
        : base(
            x => string.Join(',', x),
            v => x => x.Split(',', System.StringSplitOptions.TrimEntries)
    {
    }
}

//Override ConfigureConventions in dbcontext:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder
        .Properties<ICollection<string>>()
        .HaveConversion<StringToCollectionConverter>();
}

Working with NULL

As per the documentation a null value will not be converted, and treated as null in C#. For this example that would mean the ICollection would not be initialized, which will lead to a NullReferenceException when accessed.

To learn more about value conversions in ef core, visit https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions?tabs=data-annotations