How to load all related EF entities in preparation for serialization

673 views Asked by At

Can someone tell me how to (elegantly) load all related entity objects in preparation for serialization to disk?

I have a table Session. A Session can have multiple Recordings which are in the Recordings Table. Further, each Recording can have multiple RecordedFiles, which are in the RecordedFiles table.

The EF classes look like this (abbreviated for simplicity):

[Serializable]
public partial class Session
{
    public Session()
    {
       this.Notes = new HashSet<Note>();
        this.Recordings = new HashSet<Recording>();
    }

    public System.Guid SessionGUID { get; set; }
     public int SessionNum { get; set; }
    public virtual ICollection<Note> Notes { get; set; }
   public virtual ICollection<Recording> Recordings { get; set; }
}

[Serializable]
public partial class Recording
{
    public Recording()
    {
        this.RecordedFiles = new HashSet<RecordedFile>();
         this.ProcessedFiles = new HashSet<ProcessedFile>();
    }

    public System.Guid RecordingGUID { get; set; }
    public int RecordingNumber { get; set; }
    public System.Guid SessionGUID { get; set; }
     public virtual ICollection<ProcessedFile> ProcessedFiles { get; set; }   
    public virtual ICollection<RecordedFile> RecordedFiles { get; set; }
    public virtual Session Session { get; set; }
   }

Originally, I was using Lazy Loading, and by trial and error I noticed that I couldn't serialize all things unless I happened to expand the collections in the debugger before serializing. This makes sense: With Lazy Loading, the entities are not pulled out until they are needed. But obviously, I can't always step through the debugger and do this! My next thought was to use "Eagerly Loading". See https://msdn.microsoft.com/en-US/data/jj574232 for example. But if you look at this, you see that you need to have "include" statements. I believe I would have to have multiple include statements (see: Loading all the children entities with entity framework) to cover different branches coming off of Session (Recordings & Notes). And the situation is even worse than I'm showing: there are multiple branches coming off Session AND they are deeper than I'm letting on. That is, a Session might have a collection of Recordings, which in turn has a collection of RecordedFiles, which in turn, etc. etc.

If I have to write some ugly expression like: Session session = context.Sessions.Include("Recordings.RecordedFiles").Include("Recordings.ProcessedFiles").Include("Equipment.StereoEquipment").Include("Notes").Where(p => p.GUID == ####).FirstOrDefault();

I will. But I'm guessing there is some elegant way to say, "Load all entities related to this given Session". Can someone enlighten me? Notice in the monstrosity above I have both include "Recordings.RecordedFiles" and "Recordings.ProcessedFiles". That is, Session has a collection of Recordings. Each Recording has a collection of RecordedFiles AND ProcessedFiles. It would be nice to say "Include Recordings.{all sub collections}

Thanks,

Dave

Edit: I should have pointed out that another reason to avoid the multiple "includes" is that if the database changes (to have another table or collection under Recordings for example), the code would have to be rewritten. It could get hard to keep track of that.

1

There are 1 answers

4
Matt Whetton On BEST ANSWER

I'm afraid there's no built in way to do what you want. You could do something with reflection, where you enumerate all properties and load them yourself. Like this:

How can I recursively Include ALL navigable properties to emulate Lazy Loading