How to round trip an object with relation using asp .net web api, entity framework and json (code first)? How to round trip an object with relation using asp .net web api, entity framework and json (code first)? json json

How to round trip an object with relation using asp .net web api, entity framework and json (code first)?


After much searching I was finally able to resolve my issue. Originally I tried adding a [ScriptIgnore] tag to the Movies set, however I was using EF5 final which changed the default serializer to JSON .NET. I finally found that [ScriptIgnore] didn't work and I had to set [JsonIgnore] like this:

public class Actor{    public int ActorID { get; set; }    public string Name { get; set; }    [JsonIgnore]    public virtual ICollection<Movie> Movies { get; set; }}public class Movie{    public int MovieID { get; set; }    public string Name { get; set; }    public virtual ICollection<Actor> Actors { get; set; }}

Doing that combined with the .Include("Actors") eager loading in the Get method finally solved my issue.

In summary I needed to:

  1. Have the virtual ICollection references on both objects to create the intermediate table.
  2. Add [JsonIgnore] to the Movies collection reference to solve the circular reference.
  3. Turn off the proxy to solve my 500 error.
  4. Eager load the Actors in the GetMovies/GetMovie method using .Include("Actors")

Additionally I found for subsequent PUTs of the Movie object, where the Actors collection had changed, I had to manually change the RelationShip state on each child Actor to either Added/Deleted to make sure the related collection was updated.


About your comment:

Also, I'd be completely happy to remove the public virtual ICollection<Movie> Movies { get; set; } from the Actor class, however in doing that, EF wasn't generating the intermediate table in the LocalDb.

If you remove one of the collections EF assumes by convention that your relationship is a one-to-many relationship (which doesn't have an intermediate table, but only a foreign key in one of the tables) in contrast to the model with two collections where EF creates a many-to-many relationship (that has an intermediate table).

However, you can override this convention using Fluent API and tell EF explicitly that the remaining collection belongs to a many-to-many relationship instead of a one-to-many. Having this model...

public class Actor{    //...    public int ActorID { get; set; }    public string Name { get; set; }}public class Movie{    //...    public int MovieID { get; set; }    public string Name { get; set; }    public virtual ICollection<Actor> Actors { get; set; }}

...you can define a many-to-many relationship this way:

public class MediaContext : DbContext{    //...    protected override void OnModelCreating(DbModelBuilder modelBuilder)    {        modelBuilder.Entity<Movie>()            .HasMany(m => m.Actors)            .WithMany()            .Map(a =>            {                a.MapLeftKey("MovieID");                a.MapRightKey("ActorID");                a.ToTable("MovieActors"); // intermediate table            });    }}