EF Core 3.1 cosmosdb Owned Entities

Viewed 909

I have the following domain model that I am trying to ensure is created using the COSMOSDB provider for EF Core 3.1 however I keep getting an error.

Model classes:

public class Application
{
    public Site Site { get; set; } = new Site();
    public Applicant Applicant { get; set; } = new Applicant();
    public Agent Agent { get; set; } = new Agent();
}

public class Site
{
    public Address Address { get; set; } = new Address();
}

public class Applicant
{
    public Address Address { get; set; } = new Address();
}

public class Agent
{
    public Address Address { get; set; } = new Address();
}

public class Address
{
    public MapCoordinate MapCoordinate { get; set; } = new MapCoordinate();

    public GeoLocation GeoLocation { get; set; } = new GeoLocation();
}

DbContext:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{   
    modelBuilder.HasDefaultContainer("Applications");

    modelBuilder.Entity<Address>(x => x.Property(y => y.GeoLocation).HasJsonConversion());
            
    modelBuilder.Entity<Application>(x =>
            {
                x.HasKey(x => x.ApplicationId);
                x.HasPartitionKey(x => x.ApplicationId);
                
                x.OwnsOne(x => x.Site).OwnsOne(x => x.Address);
                x.OwnsOne(x => x.Applicant).OwnsOne(x => x.Address);
                x.OwnsOne(x => x.Agent).OwnsOne(x => x.Address);
            });
}

Error: on the line

x.OwnsOne(x => x.Site).OwnsOne(x => x.Address)

I get:

System.InvalidOperationException: The type 'Address' cannot be marked as owned because a non-owned entity type with the same name already exists.

How do I map this relationship so I can get a Json document like:

{ 
    site : { address: { MapCoordinate : blah, GeoLocation: blah },
    applicant : { address: { MapCoordinate : blah, GeoLocation: blah },
    agent : { address: { MapCoordinate : blah, GeoLocation: blah }
}
1 Answers

So after posting on efcore github it turns out that calling:

modelBuilder.Entity<Address>(x => x.Property(y => y.GeoLocation).HasJsonConversion());

configures the Address Type as a standard entity rather than an Owned entity. I was effectively trying to configure all uses of the Address Type in one go. This currently isn't possible and needs to be done on each usage of the type e.g.:

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultContainer("Applications");

            modelBuilder.Entity<Application>(x =>
            {
                x.HasKey(x => x.ApplicationId);
                x.HasPartitionKey(x => x.ApplicationId);
                
                x.OwnsOne(x => x.Site).OwnsOne(x => x.Address, y =>
                    {
                        y.Property(p => p.GeoLocation).HasJsonConversion();
                        y.OwnsOne(p => p.MapCoordinate);
                    });
                x.OwnsOne(x => x.Applicant).OwnsOne(x => x.Address, y =>
                {
                    y.Property(p => p.GeoLocation).HasJsonConversion();
                    y.OwnsOne(p => p.MapCoordinate);
                });
                x.OwnsOne(x => x.Agent).OwnsOne(x => x.Address, y =>
                {
                    y.Property(p => p.GeoLocation).HasJsonConversion();
                    y.OwnsOne(p => p.MapCoordinate);
                });
            });
        }

The ability to bulk configure is expected in EFCore 6.0

Related