I'm currently in the process of migrating an existing database design into a new application using EF Core 2.2.1 with code first migrations. Our current design has a primary table which then can have multiple sub tables with the same, shared primary key. I've looked at this similar question and tried to replicate the answer there, but haven't had much luck in having the data show in the result.
The simplified schema looks a bit like the following:
public class Root
{
public enum SubEntityType
{
A,
B,
C,
D
}
public Guid Id { get; set; }
public SubEntityType Type { get; set; }
public virtual TypeA A { get; set; }
public virtual TypeB B { get; set; }
public virtual TypeC C { get; set; }
public virtual TypeD D { get; set; }
}
public class TypeA
{
public Guid Id { get; set; }
public virtual Root Root { get; set; }
public int A { get; set; }
}
public class TypeB
{
public Guid Id { get; set; }
public virtual Root Root { get; set; }
public Guid B { get; set; }
}
public class TypeC
{
public Guid Id { get; set; }
public virtual Root Root { get; set; }
public string C { get; set; }
}
public class TypeD
{
public Guid Id { get; set; }
public virtual Root Root { get; set; }
public bool D { get; set; }
}
Then I've set up the relationships using fluent api as follows:
builder.Entity<Models.Root>()
.HasOne( e => e.A )
.WithOne( e => e.Root )
.HasForeignKey<Models.TypeA>( e => e.Id );
builder.Entity<Models.Root>()
.HasOne( e => e.B )
.WithOne( e => e.Root )
.HasForeignKey<Models.TypeB>( e => e.Id );
builder.Entity<Models.Root>()
.HasOne( e => e.C )
.WithOne( e => e.Root )
.HasForeignKey<Models.TypeC>( e => e.Id );
builder.Entity<Models.Root>()
.HasOne( e => e.D )
.WithOne( e => e.Root )
.HasForeignKey<Models.TypeD>( e => e.Id );
It seems to work great up until I try to add data. I create the root entry with some dummy data. In root
table:
Id Type
6f0f24cf-fbd7-4b4d-8059-0810daaf5460 1
In TypeA
table:
Id A
6f0f24cf-fbd7-4b4d-8059-0810daaf5460 12
Everything inserts fine and looks good. When I query this like so:
var result = ctx.Root.First();
I get the following result (apologies for formatting, tried to make it a bit nicer):
Name Value
result {Test.Models.Root}
A null
B null
C null
D null
Id {6f0f24cf-fbd7-4b4d-8059-0810daaf5460}
Type B
Shouldn't A
be populated with the Test.Models.TypeA
object with the A
set to 12
? Is this an optimisation that EF does and I need to load A
on demand or have I set up the relationship incorrectly? Alternatively, is my approach wrong here and I should be doing this differently?
In Entity Framework Core, virtual navigation properties are not loaded automatically unless you Configure Lazy Loading or use Eager Loading
with Include
.
So write your query as follows:
var result = ctx.Root.Include(r => r.TypeA).Include(r => r.TypeB)
.Include(r => r.TypeC).Include(r => r.TypeD).FirstOrDefault();
Now Root
will have TypeA
, TypeB
, TypeC
and TypeD
associated with it.