.netentity-framework-coreef-core-8.0

EF Core config for optional complex type with required properties


My domain:

public struct LatLng
{
  public double Lat { get; set; }
  public double Lng { get; set; }
}

public class Building
{
  public LatLng? LatLng { get; set; }
}

I want LatLng as an EF v8 complex type which is optional, but whose properties are required:

modelBuilder.Entity<Building>()
  .ComplexProperty(x => x.LatLng, x => {
    x.Property(y => y.Value.Latitude).IsRequired();
    x.Property(y => y.Value.Longitude).IsRequired();
    x.IsRequired(false);
  });

The compiler warns "Nullable value type may be null. (CS8629)" which I can suppress (y!.Value) as it doesn't seem to make a difference for the internal model built by EF.

But when adding a migration I get an error:

Unable to create a 'DbContext' of type ''. The exception 'The expression 'y => y.Value.Latitude' is not a valid member access expression. The expression should represent a simple property or field access: 't => t.MyProperty'. (Parameter 'memberAccessExpression')' was thrown while attempting to create an instance.

How does one do this?

(Note this is just an example of the problem. I could rely on conventions in this case, but in others I need to perform custom config. I'd like to know how to do it.)


Solution

  • I forgot that I modeled Coordinates as a struct; I originally wanted it as a "value object". Now that I noticed, I changed it to a reference type, and that seems to satisfy EF.

    public class LatLng {
    

    and

    x.Property(y => y!.Latitude).IsRequired();
    x.Property(y => y!.Longitude).IsRequired();
    

    I'm not sure if this is the best approach, but it works for me.