Entity Framework Core - Has Conversion - Support Null Values
Asked Answered
M

2

9

I have an EF model with a notification emails property. The notification emails are saved in the database as string separated by ';'. I added a conversion to retrieve the data as a ICollection in the model. This is working well except one thing: when the string is null the collection is also null, and I want to convert it to an empty collection instead. is it possible?

//This is my code
  entity.Property(e => e.NotificationEmails)
             .HasConversion(
                v => string.Join(",", v.Select(s => s.Trim())),
                v => v.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));

I tried to add String.IsNullOrEmpty(v) but EF ignores it.

Mindi answered 13/5, 2019 at 8:58 Comment(5)
Storing the data as semi-colon separated items is a terrible idea. just make a table.Steal
@Steal can you please explain why?Mindi
Well for a start you don't need awful converters like you have here. There's lots of reasons.Steal
@Steal any other reasons you know about will really help?Mindi
@TalHumy Some other reasons: Server side filtering not possible (or hard to do). Individual Add/Remove/Update item not possible - has to update the whole. Etc. But to answer your concrete question, EF Core value converters so far are not called for null values - the assumption is that null is always converted to null. Since you cannot use such collection in L2E query anyway, you could handle it at object level with explicit backing field and special property getter.Iceblink
S
8

Currently, it isn't possible :

https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions#configuring-a-value-converter

A null value will never be passed to a value converter. This makes the implementation of conversions easier and allows them to be shared amongst nullable and non-nullable properties.

It isn't elegant, but you can use a backing field :

public class Notification
{
    private List<string> _emails = new List<string>();
    public List<string> Emails 
    {
        get => _emails;
        set => _emails = value ?? new List<string>();
    }
}

public class NotificationContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Notification>().Property(d => d.Emails).HasConversion(
                v => string.Join(",", v.Select(s => s.Trim())),
                v => v.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList()
            );
            modelBuilder.Entity<Notification>()
                .Property(b => b.Emails)
                .HasField("_emails")
                .UsePropertyAccessMode(PropertyAccessMode.Property);
    }
}

Note : in where, a empty list will not be translated by null, but by a empty string.

Edit : This feature is available from EF Core 6, but bugged. See this comment :

For anyone watching this issue: there are significant problems when executing queries that either convert nulls in the database to non-nulls in code or vice-versa. Therefore, we have marked this feature as internal for EF Core 6.0. You can still use it, but you will get a compiler warning. The warning can be disabled with a #pragma.

Saturday answered 3/3, 2020 at 9:38 Comment(0)
P
1

You can do this now by setting the ConvertsNulls property to true on the ValueConverter.

I haven't seen a way to do this with the model builder API yet.

public class CurrencyConverter : ValueConverter<Currency, decimal>
{
    public override bool ConvertsNulls => true;

    public CurrencyConverter()
        : base(
            v => v.Amount,
            v => new Currency(v))
    {
    }
}

https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.storage.valueconversion.valueconverter.convertsnulls?view=efcore-8.0

Photophilous answered 27/8, 2024 at 3:45 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.