I'm having a problem very similar to the ones mentioned in these questions:
Why is Entity Framework navigation property null?
Why EF navigation property return null?
The plot twist in my case is that the navigation collection properties are populated by EF, but only after I've queried DbSet<T>
properties of the dependent types in the DbContext
. To make my situation clearer, here's how my model is set up:
[Table(nameof(Composer))]
internal class ComposerRelationalDto : RelationdalDtoBase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual ICollection<NameRelationalDto> LocalizedNames { get; set; } = new HashSet<NameRelationalDto>();
public virtual ICollection<ArticleRelationalDto> Articles { get; set; } = new HashSet<ArticleRelationalDto>();
}
[Table(nameof(ComposerName))]
internal class NameRelationalDto : RelationdalDtoBase
{
[Key]
public long Id { get; set; }
[Required]
[ForeignKey(nameof(Composer))]
public Guid Composer_Id { get; set; }
public ComposerRelationalDto Composer { get; set; }
}
[Table(nameof(ComposerArticle))]
internal class ArticleRelationalDto : RelationdalDtoBase
{
[Key]
public long Id { get; set; }
[Index]
public Guid StorageId { get; set; }
[Required]
[ForeignKey(nameof(Composer))]
public Guid Composer_Id { get; set; }
public ComposerRelationalDto Composer { get; set; }
[Required]
[MaxLength(5)]
public string Language { get; set; }
}
In the corresponding repository I filter ComposerRelationalDto
objects by their name:
DbContext.Set<NameRelationalDto>().Where(nameWhereClause).GroupBy(n => n.Composer_Id).Select(group => group.FirstOrDefault().Composer)
The set of ComposerRelationalDto
s has empty collections for the Articles
and LocalizedNames
properties, even though the data has been correctly persisted in the database. However, if I load all DTOs of type ArticleRelationalDto
and NameRelationalDto
in a QuickWatch while debugging, then the same filter no longer returns empty collections and all relevant objects are present in the collection properties.
What I've tried so far was to
enable lazy loading and the creation of proxies explicitly
configure the one-to many-relationships manually:
modelBuilder.Entity<ComposerRelationalDto>().HasMany(c => c.LocalizedNames).WithRequired(n => n.Composer).HasForeignKey(n => n.Composer_Id);
modelBuilder.Entity<ComposerRelationalDto>().HasMany(c => c.Articles).WithRequired(a => a.Composer).HasForeignKey(a => a.Composer_Id);
and finally I just tried fiddling with the DbQuery<T>.Include()
method DbContext.Set<ComposerRelationalDto>().Include(c => c.Articles)
which unfortunately throws an ArgumentNullException from one of the internal methods it calls.
Basically, whatever fixes or workarounds I've tried haven't helped, so I must ask for more help.
Edit: I modified the dependent types' Composer property to be virtual. However, the problem persists.
After using .Select(group => group.FirstOrDefault().Composer).Include(c => c.Articles).Include(c => c.LocalizedNames)
I now no longer get an ArgumentNullException
(maybe I was getting the ArgumentNullException
because I was initially using .Include()
in a QuickWatch?), but rather a MySqlException
: Unknown column 'Join2.Id' in 'field list'; the Data dictionary contains Key: "Server Error Code" Value: 1054. Also the generated SQL is ridiculously large and barely legible.
I figured it out. It was the internal
access modifier on class declarations. A shame, because I really wanted to make the rest of the solution entirely database-agnostic (hence the unusual use of DTOs for code first, instead of the actual entities, as was already pointed out in the comments) and I wanted to enforce this in a strict manner.
Anyway, I played around some more with access modifiers and I could only manage restricting the DB object's visibility by making them public
with internal protected
constructors. Any other combination of class and ctor visibility involving internal
caused the problem to reappear. No luck with InternalsVisibleTo
, either.
This question - Entity Framework Code First internal class - is it possible? - seems to suggest that using an internal class shouldn't be a problem for EF, but it appears it is, after all, somewhat of a problem. If it wasn't then (Julie Lerman's answer dates back to 2011), it is now. I'm using EF 6.2.0 at the moment.