15

I was curious if it is possible to map an intermediate table through a containing object.

public class Subscriber : IEntity
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    private ChannelList _subscribedList { get; set; }
    public int NumSubscribedChannels { get { return _subscribedList.Count(); } }
}

public class HelpChannel : IEntity
{
    [Key]
    public int Id { get; set; }
    public string name { get; set; }
    public string category { get; set; }
    public int group { get; set; }
}

I need to have a subscriber table, channel table and an intermediate table to link a subscriber to his/her channels.

Is it possible to map the list that is within the ChannelList object to the Subscriber Model?

I figured that's probably not possible and that I would need to just have a private List for EF to map. But I wasn't sure if EF will do that for private variables. Will it?

I'm hoping that is does because if it has to be public to maintain the encapsulation.

Glen Nicol
  • 275
  • 1
  • 3
  • 15
  • can you clarify this sentence of yours: `Is it possible to map the list that is within the ChannelList object to the Subscriber Model?` – Ashkan Dec 10 '12 at 19:36
  • What type is `ChannelList`? I don't think you can map that with EF. If it is private, how are you going to add channels to subscribers? – Gert Arnold Dec 10 '12 at 21:37
  • ChannelList is just an object that has a List within it. – Glen Nicol Dec 11 '12 at 03:06
  • I want the subscriber to have a list of the channels that they are subscribed to. But I'd rather interact with this ChannelList object because it encapsulates the data and because there are so many of these lists I want all of the code in one place to work with a group of them. I just wasn't sure how to get EF to map these relationships without giving direct access to the list that would be public in a normal EF many to may Setup. – Glen Nicol Dec 11 '12 at 03:08

1 Answers1

39

You can map private properties in EF code-first. Here is a nice description how to do it. In your case it is about the mapping of Subscriber._subscribedList. What you can't do is this (in the context's override of OnModelCreating):

modelBuilder.Entity<Subscriber>().HasMany(x => x._subscribedList);

It won't compile, because _subscribedList is private.

What you can do is create a nested mapping class in Subscriber:

public class Subscriber : IEntity
{
    ...
    private ICollection<HelpChannel> _subscribedList { get; set; } // ICollection!

    public class SubscriberMapper : EntityTypeConfiguration<Subscriber>
    {
        public SubscriberMapper()
        {
            HasMany(s => s._subscribedList);
        }
    }
}

and in OnModelCreating:

modelBuilder.Configurations.Add(new Subscriber.SubscriberMapping());

You may want to make _subscribedList protected virtual, to allow lazy loading. But it is even possible to do eager loading with Include:

context.Subscribers.Include("_subscribedList");
Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • Then I would just pass that Icollection into the ChannelList object to preserve the encapsulation? Would I need to do something similar on the HelpChannel model? Because if you don't have a public collection of the opposite type in both models then it won't make the intermediate table to relate them together in a many to many. – Glen Nicol Dec 11 '12 at 03:12
  • Am I correct that with this approach there is no way to perform linq-to-entities queries using the relation? (Because the actual related collection is not public, while the public interface is not an entity navigation property? – Carl G Feb 19 '13 at 19:48
  • Yes, that's a consequence. – Gert Arnold Feb 19 '13 at 20:02
  • @Saibot Still works. Of course I have no clue what you did exactly. – Gert Arnold Aug 30 '17 at 10:14