I have the following class definitions
public abstract class AbstractClass
{
[Key]
public string Name { get; set; }
public virtual IndependentClass IndependentClass { get; set; }
public string IndependentClassName { get { return IndependentClass == null ? "<NULL>" : IndependentClass.Name; } }
}
public class Impl1 : AbstractClass
{
}
public class Impl2 : AbstractClass
{
}
public class IndependentClass
{
[Key]
public string Name { get; set; }
public virtual Impl1 Impl1 { get; set; }
public virtual ICollection<Impl2> Impl2s { get; set; }
}
with these in my Context.OnModelCreating:
modelBuilder.Entity<AbstractClass>().HasOptional(abs => abs.IndependentClass);
modelBuilder.Entity<IndependentClass>().HasRequired(ind => ind.Impl1);
modelBuilder.Entity<IndependentClass>().HasMany(ind => ind.Impl2s);
My initialization looks like this (with adding the arrays to the context and context.SaveChanges() trimmed)
var impl1s = new[]
{
new Impl1() { Name = "a" },
new Impl1() { Name = "b" },
new Impl1() { Name = "c" }
}
var inds = new[]
{
new IndependentClass() { Name = "A", Impl1 = impl1s[0] },
new IndependentClass() { Name = "B", Impl1 = impl1s[1] }
}
var impl2s = new[]
{
new Impl2() { Name = "a1", IndependentClass = inds[0] },
new Impl2() { Name = "a2", IndependentClass = inds[0] },
new Impl2() { Name = "b1", IndependentClass = inds[1] },
new Impl2() { Name = "b2", IndependentClass = inds[1] },
new Impl2() { Name = "c1", IndependentClass = null }
}
And finally I have a simple View that dumps each of the db collections. My problem is that the navigation properties aren’t getting populated like I need them to. i.e., the output of my view is this:
Independent Classes:
A: Impl1 = a, Impl2s = []
B: Impl1 = b, Impl2s = []
Impl1s
a: IndependentClass = <NULL>
b: IndependentClass = <NULL>
c: IndependentClass = <NULL>
Impl2s
a1: IndependentClass = A
a2: IndependentClass = A
b1: IndependentClass = B
b2: IndependentClass = B
c1: IndependentClass = <NULL>
The IndepdendentClasses should have their Impl2s populated, and the first two Impl1s should have IndependentClasses populated.
Can anyone tell me what I’m doing wrong?
Your model has three relationships with the following navigation properties:
AbstractClass.IndependentClass<->IndependentClass.(NoNavigationProperty)IndependentClass.Impl1<->Impl1.(NoNavigationProperty)IndependentClass.Impl2s<->Impl2.(NoNavigationProperty)For each relationship one end of the association is not exposed as navigation property. It’s not expected in this model that…
…because you don’t populate
IndependentClass.Impl2sin your initialization code nor do you fillImpl1.IndependentClass. You fillImpl2.IndependentClassbut because this navigation property belongs to another relationship it doesn’t affectIndependentClass.Impl2sat all.If you want actually two relationships…
IndependentClass.Impl1<->Impl1.IndependentClass(one-to-one)IndependentClass.Impl2s<->Impl2.IndependentClass(one-to-many)…you can’t achieve that as long as your
AbstractClassis an entity in your model with its own table because you must map between navigation properties of the types they are declared in, andImpl1.IndependentClassandImpl2.IndependentClassare inherited properties but they are not declared inImpl1andImpl2.If you don’t make
AbstractClassan entity, i.e. don’t use this abstract class in mapping code and don’t have aDbSet<AbstractClass>in your context class, then the two relationships above are possible. For EF your model does not have any inheritance, instead it considersImpl1(andImpl2) as an entity that just contains its own properties plus the properties of the base class as if it were one class without base.That’s the reason why the mapping in your own answer works as you expect: You have defined the one-to-one relationship between
IndependentClass.Impl1andImpl1.IndependentClassexplicitly with Fluent API. The second relationship betweenIndependentClass.Impl2sandImpl2.IndependentClassis detected automatically by naming conventions as one-to-many relationship.