Entity Framework doesn't populate collection properties

c# entity-framework entity-framework-6

Question

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 ComposerRelationalDtos 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

  1. enable lazy loading and the creation of proxies explicitly

  2. 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);
    
  3. 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.

1
0
7/3/2018 10:40:45 PM

Accepted Answer

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.

0
7/7/2018 4:53:35 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow