1

I have defined a Many to Many relationship between 2 objects. Each object exposes the same Navigation property in order for me to traverse the relationships by code. The setup is as follows;

    public class Message : Entity<int>
    {
        public int UserId { get; set; }

        public User User { get; set; }

        public Guid Reference { get; set; } = Guid.NewGuid();

        public virtual ICollection<MessageGroup> MessageGroups { get; set; } = new HashSet<MessageGroup>();
    }
}

  public class Group : Entity<int>
    {
        public int UserId { get; set; }

        public User User { get; set; }

        public Guid Reference { get; set; } = Guid.NewGuid();

        public virtual ICollection<MessageGroup> MessageGroups { get; set; } = new HashSet<MessageGroup>();

    }

 public class MessageGroup
    {
        public int MessageId { get; set; }

        public Message Message { get; set; }

        public int GroupId { get; set; }

        public Group Group { get; set; }
    }

and this in my Context;

   protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

                modelBuilder.Entity<MessageGroup>()
                       .HasKey(bc => new { bc.GroupId, bc.MessageId });

                modelBuilder.Entity<MessageGroup>()
                    .HasRequired(bc => bc.Group)
                    .WithMany(b => b.MessageGroups)
                    .HasForeignKey(bc => bc.GroupId)
                    .WillCascadeOnDelete(false);

                modelBuilder.Entity<MessageGroup>()
                    .HasRequired(bc => bc.Message)
                    .WithMany(c => c.MessageGroups)
                    .HasForeignKey(bc => bc.MessageId)
                    .WillCascadeOnDelete(false);

}

However, when I attempt to load a Message that has multiple groups (records are correct in MessageGroup table), only the Messages are shown. For Information, I am loading these through the Messages DbSet. When I then load the Group through the Groups DbSet, the reverse happens, and only the Groups are shown.

Loaded from Messages DbSet;

enter image description here

Loaded from Group DbSet;

enter image description here

I can get both by using the MessageGroup DbSet and Including them;

var messageGroups = context.MessageGroups.Where(x => x.MessageId == id).Include(x => x.Group).Include(x => x.Message).ToList();

but I want to be able to load my Message or Group and have these available.

For information, my context is wrapped around another layer and I have exposed a few methods for each Type but ultimately, I am calling;

   public T Get(U id)
        {
            return _dbSet.Find(id);
        }
ChrisBint
  • 12,773
  • 6
  • 40
  • 62
  • Possible duplicate of [C# Entity-Framework: How can I combine a .Find and .Include on a Model Object?](https://stackoverflow.com/questions/7348663/c-sharp-entity-framework-how-can-i-combine-a-find-and-include-on-a-model-obje) – Progman Dec 09 '17 at 12:52
  • When loading a collection navigation property, it also loads the inverse navigation property. To load other property you need to explicitly `Include` it. Or since the collection navigation properties are `virtual` (hence lazy loaded), you should make the `MessageGroup` navigation properties `virtual` too. – Ivan Stoev Dec 09 '17 at 13:13
  • @Progman, yes I know you can Include them, but my specific question was how to make them available without doing so. Thanks – ChrisBint Dec 09 '17 at 13:24
  • 1
    @IvanStoev Marking the Group and Message navigation properties as virtual has solved the problem. If you add this as answer, I will accept it. Many thanks – ChrisBint Dec 09 '17 at 13:25

1 Answers1

2

When a collection navigation property is loaded, the EF navigation property fixup also loads the corresponding inverse navigation property. But other navigation properties must be loaded explicitly (eager, explicit or lazy).

Since you seem to rely on lazy loading the MessageGroups collection navigation properties, you should make the inverse reference navigation properties in MessageGroup virtual too:

public class MessageGroup
{
    public int MessageId { get; set; }

    public virtual Message Message { get; set; }

    public int GroupId { get; set; }

    public virtual Group Group { get; set; }
}
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343